答えを始める前に、質問によってもたらされたいくつかのあいまいさに対処したいと思いました。
WCF、より具体的には、WCFをホストするWebアプリケーションは、クライアントでサービスコンシューマークラスを作成するときに非同期メソッドが生成されるかどうかに関係なく、サービス呼び出しを同時に実行する新しいサービスインスタンスを作成します。非同期メソッドはクライアントの利益のためだけに使用されるため、サービス呼び出しが行われ、クライアントは実行を継続し、呼び出しの結果は後で任意の時間に要求される可能性があります。(通常、MyService.BeginMyMethod呼び出しを実行し、後でMyService.EndMyMethodを実行します。)
ここで質問に対処するために、より簡単な方法を採用し、WCFホストに現在実行時間の長いメソッドを追跡させたいと想定します。サービスがその長時間実行メソッドについて知るために、あなたは単にあなた自身の静的リストを維持することができます。簡単なコード例:
public class Service1 : IService1
{
public static List<Task> MyRunningTasks = new List<Task>();
private static object MyRunningTasksLockObject = new object();
public void StartMyLongRunningMethod()
{
var myTracker = new MyProcessTrackingClass()
{
OwnerName = HttpContext.Current.User.Identity.Name,
StartTime = DateTime.Now
};
var myAction = new Action<object>(userState =>
{
var myActionTracker = (MyProcessTrackingClass)userState;
for (int i = 0; i < 10; i++)
{
System.Threading.Thread.Sleep(TimeSpan.FromMinutes(1.0));
myActionTracker.PercentComplete += 10M;
}
});
var myTask = Task.Factory.StartNew(myAction, myTracker, TaskCreationOptions.LongRunning);
AddLongRunningMethod(myTask);
myTask.ContinueWith(t => RemoveLongRunningMethod(t));
}
private static void AddLongRunningMethod(Task item)
{
lock (MyRunningTasksLockObject)
{
MyRunningTasks.Add(item);
}
}
private static void RemoveLongRunningMethod(Task item)
{
lock (MyRunningTasksLockObject)
{
MyRunningTasks.Remove(item);
}
}
}
public sealed class MyProcessTrackingClass
{
public string OwnerName { get; set; }
public DateTime StartTime { get; set; }
public Decimal PercentComplete { get; set; }
}
上記の例の本体はmyAction
、メソッドロジックが移動する場所です(または、そのポイントから別のメソッドを呼び出すこともできます)。さらに、このアプローチには他にもいくつかの利点があります。1つは、サービスメソッド自体がTask
すべての面倒な作業を行うを作成するだけなので、メソッドは実際にはクライアントに迅速に応答を返すため、クライアント側で非同期メソッドを作成するかどうかは関係ありません。いいえ。
もう1つの利点は、サービスが実行中のプロセスを認識しているため、クライアントが現在の長時間実行中のプロセスを照会できるようにする別のサービスメソッドを公開することもできることです。
public IEnumerable<MyProcessTrackingClass> ListLongRunningProcesses()
{
return MyRunningTasks.Select(t => (MyProcessTrackingClass)t.AsyncState);
}
その最後の例で指摘されているように、AsyncState
eachのプロパティは、を作成したメソッドの引数Task
として渡されたカスタムクラスを保持します。を更新して、実行中のメソッドに関連付けたいプロパティを含めることができます。state
StartNew
Task
MyProcessTrackingClass