2011-06-20 13 views
6

私はC#をかなり新しくしており、最近は.NET 4.0を使用して小さなwebappを構築しました。このアプリは2つの部分から構成されています.1つは永続的に実行されるように設計されており、ウェブ上の特定のリソースからデータを連続的に取得します。もう一方は、そのデータを分析する要求に応じてそのデータにアクセスします。私は最初の部分と闘っている。ASP Webアプリケーションのバックグラウンドタスク

最初のアプローチでは、フェッチ操作を実行するオブジェクト(この操作が本当に問題になっていなくても)を、たとえば5分ごとに設定することでした。私はApplication_Startにそのタイマーを定義して、それを後にしましょう。

しかし、私は最近、アプリケーションがユーザーの要求に基づいて作成/破棄されることを認識しました(私の見解からは、ある程度の非アクティブ時間後に破棄されるようです)。結果として、私のバックグラウンドアクティビティは、中断することなく、継続的に実行したいと思っている私のコントロールから停止/再開します。

ここに私の質問が来る:それはwebappで達成可能ですか?あるいは、私は絶対にそのようなもののために別のWindowsサービスが必要ですか?

貴重なご支援をお寄せいただきありがとうございます!

ギヨーム

+4

私は、サービスがバックグラウンドタスクを実行し、あなたが望むように実行されることを確認する最も適切な方法だと言います。それを考えると、もしあなたが欠点を抱えていれば、iisプロセスの中で実行中のものにかなり近づくことができます。もっと詳しくここhttp://stackoverflow.com/questions/1607178/background-task-with-an-asp-net-web-applicationそしてここhttp://blog.stackoverflow.com/2008/07/easy-background -tasks-in-aspnet/ – bronsoja

+0

2番目のリンクはまさに​​私が探していたものです!そのcodeprojectの記事もJeffのオリジナルのブログ投稿も私のGoogle検索結果に現れなかったことには驚きました。神は私がこれを投稿する前にlooooongの時間を検索することを知っている...ありがとう! – guidupuy

+2

これを両方の方法で実行した結果、スケジュールされたタスク用に別のアプリケーションを使用すると、ASP.NETアプリケーション内でスレッドを生成するよりも信頼性が高く簡単になります。 – weir

答えて

0

は、私はあなたがBackgroundWorkerを使用して、それを達成することができますすることができると思いますが、私はむしろあなたがサービスのために行くことをお勧めします。

0

IISのワーカープロセスが機能している限り、アプリケーションのコンテキストは有効です。 IISには、ワーカープロセスがリサイクルされるときのデフォルトのタイムアウトがあります(たとえば、アイドル時の数(20)または定期的なインターバル(1740))。

つまり、IISでこれらの設定を調整すると、しかし、サービスを使用することの他の答えも同様に機能します。

1

コンストラクタを使用して静的クラスを作成し、タイマーイベントを作成します。 しかしスティーブのようにSlokaが言及したように、IISにはサイトを維持するために操作する必要があるタイムアウトがあります。

using System.Runtime.Remoting.Messaging; 

public static class Variables 
{ 
static Variables() 
{ 
    m_wClass = new WorkerClass(); 

    // creates and registers an event timer 
    m_flushTimer = new System.Timers.Timer(1000); 
    m_flushTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnFlushTimer); 
    m_flushTimer.Start(); 
} 

private static void OnFlushTimer(object o, System.Timers.ElapsedEventArgs args) 
{ 
    // determine the frequency of your update 
    if (System.DateTime.Now - m_timer1LastUpdateTime > new System.TimeSpan(0,1,0)) 
    { 
     // call your class to do the update 
     m_wClass.DoMyThing(); 
     m_timer1LastUpdateTime = System.DateTime.Now; 
    } 
} 

private static readonly System.Timers.Timer m_flushTimer; 
private static System.DateTime m_timer1LastUpdateTime = System.DateTime.MinValue; 
private static readonly WorkerClass m_wClass; 
} 

public class WorkerClass 
{ 
public delegate WorkerClass MyDelegate(); 

public void DoMyThing() 
{ 
    m_test = "Hi"; 
    m_test2 = "Bye"; 
    //create async call to do the work 
    MyDelegate myDel = new MyDelegate(Execute); 
    AsyncCallback cb = new AsyncCallback(CommandCallBack); 
    IAsyncResult ar = myDel.BeginInvoke(cb, null); 
} 

private WorkerClass Execute() 
{ 
    //do my stuff in an async call 
    m_test2 = "Later"; 
    return this; 
} 

public void CommandCallBack(IAsyncResult ar) 
{ 
    // this is called when your task is complete 
    AsyncResult asyncResult = (AsyncResult)ar; 
    MyDelegate myDel = (MyDelegate)asyncResult.AsyncDelegate; 
    WorkerClass command = myDel.EndInvoke(ar); 

    // command is a reference to the original class that envoked the async call 
    // m_test will equal "Hi" 
    // m_test2 will equal "Later"; 
} 

private string m_test; 
private string m_test2; 
} 
0

私は最近、Accessファイルをデータベースにアップロードするためのファイルアップロード機能を作成しました。これは最善の方法ではなく、長期的な問題の一時的な修正です。 ProcessAccess関数を実行し、完了したら削除されたバックグラウンドスレッドを作成して解決しました。

IISには、非アクティブにかかわらず一定の時間が経過した後にスレッドを強制終了しない限り、終了しない関数を呼び出すスレッドを作成することができます。開いている関数の量が最終的にあなたの顔に爆発するので、再帰を使用しないでくださいが、for(;;)ループを500,000回だけ持っているので忙しいです:)

2

Webアプリケーション理想的ではありません。は、サイトが常に稼働していることを前提にしています。

サンプルは次のとおりです。global.asaxにキャッシュアイテムを作成していますが、有効期限があります。期限が切れると、イベントが発生します。 OnRemove()イベントのデータなどを取得できます。

次に、Application_BeginRequestのコードをトリガーするページへの呼び出しを設定して、キャッシュ項目を有効期限に戻すように設定できます。

のGlobal.asax:あなたのスケジュールされたタスクが迅速である場合、これは、うまく機能

private const string VendorNotificationCacheKey = "VendorNotification"; 
private const int IntervalInMinutes = 60; //Expires after X minutes & runs tasks 

protected void Application_Start(object sender, EventArgs e) 
{ 

    //Set value in cache with expiration time 
    CacheItemRemovedCallback callback = OnRemove; 

    Context.Cache.Add(VendorNotificationCacheKey, DateTime.Now, null, DateTime.Now.AddMinutes(IntervalInMinutes), TimeSpan.Zero, 
        CacheItemPriority.Normal, callback); 
} 

private void OnRemove(string key, object value, CacheItemRemovedReason reason) 
{ 
    SendVendorNotification(); 

    //Need Access to HTTPContext so cache can be re-added, so let's call a page. Application_BeginRequest will re-add the cache. 
    var siteUrl = ConfigurationManager.AppSettings.Get("SiteUrl"); 
    var client = new WebClient(); 
    client.DownloadData(siteUrl + "default.aspx"); 
    client.Dispose(); 

} 

private void SendVendorNotification() 
{ 
    //Do Tasks here 
} 

protected void Application_BeginRequest(object sender, EventArgs e) 
{ 
    //Re-add if it doesn't exist 
    if (HttpContext.Current.Request.Url.ToString().ToLower().Contains("default.aspx") && 
     HttpContext.Current.Cache[VendorNotificationCacheKey] == null) 
    { 
     //ReAdd 
     CacheItemRemovedCallback callback = OnRemove; 
     Context.Cache.Add(VendorNotificationCacheKey, DateTime.Now, null, DateTime.Now.AddMinutes(IntervalInMinutes), TimeSpan.Zero, 
          CacheItemPriority.Normal, callback); 
    } 
} 

。 長期間実行されているプロセスの場合は、間違いなくあなたのWebアプリケーションからそれを保持する必要があります。

最初のリクエストがアプリケーションを開始している限り、サイトに訪問者がいなくても60分ごとに起動します。

2

私はそれをWindowsサービスに入れることをお勧めします。あなたは上記のすべてのフープを避け、大きなものはIISを再起動します。 Windowsサービスには、次の利点もあります。

  1. サーバーの起動時に自動的に起動できます。 IISで実行していてサーバーが再起動した場合は、プロセスの開始が要求されるまで待つ必要があります。
  2. 必要な場合は、ロードバランシングのウェブサイトの複数のサーバー上に終わる場合は、あなたが誤って個別にあなたのメインのコードに簡単な問題
  3. の原因となるプロセスを取得する複数のデータを持っている可能性があり、別のマシン上でこのデータフェッチプロセスを配置することができます(単一責任の原則)。コードを実行するだけで、IISをだまそうとしない場合は、コードを簡単に管理できます。
0

IIS 7.5のアプリケーション初期化モジュールは、このタイプのinit作業を正確に行います。モジュールの詳細はこちらApplication Initialization Module