WCF - Информирование о прогрессе для клиента (Могу ли я использовать односторонние методы обратного вызова в операции запрос / ответ) - PullRequest
1 голос
/ 23 октября 2011

В моем контракте есть операция запрос-ответ, которая выполняет несколько задач.Поэтому я хотел бы сообщить о ходе операции клиенту как о его длительной операции.Таким образом, дуплекс является идеальным выбором, поскольку я могу использовать методы обратного вызова.Но моя операция возвращает результаты в конце операции.Итак, какова рекомендация для решения этой проблемы?

  1. Операция Reuest-reply и метод одностороннего обратного вызова для сообщений о прогрессе от службы внутри операции?

  2. Операция блокирования (запрос-ответ) и блокировки (синхронизация) сообщений от службы

  3. Будет ли метод обратного вызова использовать тот же канал, как и моя блокировка (запрос-ответить) метод предполагает свой результат?

    • Если да, я должен выполнить свою служебную операцию асинхронно.
  4. Придет ли метод обратного вызовав другом рабочем потоке или будет возвращен в тот же поток, который задал контекст экземпляра?

Я думаю, что блокирует работу службы и блокирует метод обратного вызова для сообщения о ходе выполнения (если он может вернуться надругой поток) будет идеальным и простым решением.

Но я не уверен, сколько WCF предоставляет мне из коробки.


Другими словами, я хочу сделать что-то симилар к приведенному ниже коду (псевдо).Работает.Видите ли вы какие-либо проблемы с этим подходом?(Идея состоит в том, чтобы вызвать метод обратного вызова в блокирующем вызове. Служба работает в нескольких режимах concurencymode. Поэтому я объявил обратный вызов UseSynchronizationContext = false), чтобы избежать deadlock.any возникают проблемы с подходом, описанным ниже?

[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();
           ...
               ...
     }
}    

Eventhough, если я установлю для UseSynchronizationContext значение true, WCF вызывает метод отчета в самом рабочем потоке.Похоже, мне не нужно устанавливать его в false.Будет ли это иметь смысл только для потока пользовательского интерфейса, потому что я вызываю операцию уже в другом потоке?

1 Ответ

1 голос
/ 23 октября 2011
[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);
    }
}
...