我的合同有执行多项任务的请求 - 回复操作。所以我想告诉客户操作的进度,因为它是一个长期运行的操作。所以Duplex是理想的选择,因为我可以使用回调方法。但是我的操作在操作结束时返回结果。那么解决这个问题的建议是什么?
操作中服务进度消息的Reuest-reply操作和单向回调方法?
阻止(请求 - 回复)操作和阻止(同步)来自服务的进度消息
回调方法是否会使用相同的通道,我的阻塞(请求 - 回复)方法会假设其结果吗?
回调方法是否会出现在另一个工作线程中,还是会返回到给出实例上下文的同一个线程?
我认为阻止服务操作和阻止进程消息的回调方法(如果它可以在另一个线程上返回)将是理想且简单的解决方案。
但我不确定WCF能为我提供多少开箱即用。
换句话说,我想做类似下面的代码(psuedo)。它的工作。你觉得这种方法有什么问题吗? (我的想法是在阻塞调用中调用一个回调方法。服务在多个concurencymode中运行。所以我声明了回调UseSynchronizationContext = false)以避免死锁。以下方法有哪些问题?
[ServiceContract(CallbackContract(typeof(IServiceCallback)]]
public interfact IService
{
//A long (timetaken) request-reply operation
string LonggggWork();
}
public interface IServiceCallback
{
void Report(string msg);
}
[CallbackBehavior(ConcuerencyMode.Multiple, UseSynchronizationContext=false)]
public ClientCallback : IServiceCallback
{
public void Report(string msg)
{
Console.WriteLine(msg);
}
}
[ServiceBehavior(ConcurencyMode.Multiple, InstanceMode.PerSession)]
publci Service : IService
{
IServiceCallback callback = ....;
public string LongggWork()
{
callback.Report("task1");
task1();
callback.Report("task2");
task2();
...
...
}
}
尽管我将UseSynchronizationContext设置为true,但是WCF正在工作线程本身中调用报表方法。所以看起来我不需要将其设置为false。它只对UI线程有意义,因为我在另一个线程中调用了操作吗?
答案 0 :(得分:1)
[ServiceContract(CallbackContract = typeof(ISubscriber))]
public interface IJobProcessor
{
[OperationContract(IsOneWay = true)]
void ProcessJob();
}
[ServiceContract]
public interface ISubscriber
{
//This would be the operation using which the server would notify the client about the status.
[OperationContract]
void UpdateStatus(string statusMessage);
}
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(JobProcessor), new Uri[] { new Uri("net.tcp://localhost:10000") });
host.AddServiceEndpoint(typeof(IJobProcessor), new NetTcpBinding(), "jobprocessor");
host.Open();
Console.WriteLine("Server running. Press enter to quit!");
Console.Read();
}
}
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant)]
public class JobProcessor : IJobProcessor
{
public void ProcessJob()
{
ISubscriber subscriber = OperationContext.Current.GetCallbackChannel<ISubscriber>();
for (int i = 0; i < 5; i++)
{
Thread.Sleep(1000 * 10);
subscriber.UpdateStatus(String.Format("{0} % complete", (i + 1) * 20));
}
}
}
//客户端看起来像这样......
class Program
{
static void Main(string[] args)
{
var proxy = DuplexChannelFactory<IJobProcessor>.CreateChannel(new InstanceContext(new Subscriber()), new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:10000/jobprocessor"));
proxy.ProcessJob();
Console.Write("Client proceeding with other work...");
Console.Read();
}
}
public class Subscriber : ISubscriber
{
public void UpdateStatus(string statusMessage)
{
Console.WriteLine(statusMessage);
}
}