WCF: контракт обратного вызова не асинхронный, ошибка, потому что не реализованы методы Begin/End

У меня есть дуплексная служба WCF. В сервисном контракте у меня есть 3 асинхронных метода и 1 обычный метод (закрытие сеанса). В контракте обратного вызова у меня есть только 1 метод void, который не является асинхронным.

Когда я генерирую прокси с помощью svcUtil, я использую параметр /a и получаю .cs. Если я открою этот файл, я увижу, что сгенерирован метод Begin/end для неасинхронного метода контракта, я не знаю, почему, потому что этот метод не помечен как асинхронный в контракте. Во всяком случае, это не проблема.

Проблема заключается в методе контракта обратного вызова. В моем клиентском приложении я реализую интерфейс обратного вызова, но я реализовал один метод, метод синхронизации, поэтому у меня нет методов Begin/End. Однако я не могу скомпилировать, потому что у меня есть ошибка, что класс, реализующий интерфейс обратного вызова, не реализует методы Begin/end.

В чем проблема?

Спасибо. Даймрок.


person Álvaro García    schedule 28.04.2012    source источник


Ответы (1)


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

public class StackOverflow_10362783
{
    [ServiceContract(CallbackContract = typeof(ICallback))]
    public interface ITest
    {
        [OperationContract]
        string Hello(string text);
    }
    [ServiceContract]
    public interface ICallback
    {
        [OperationContract(IsOneWay = true)]
        void OnHello(string text);

        [OperationContract(IsOneWay = true, AsyncPattern = true)]
        IAsyncResult BeginOnHello(string text, AsyncCallback callback, object state);
        void EndOnHello(IAsyncResult asyncResult);
    }
    public class Service : ITest
    {
        public string Hello(string text)
        {
            ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
            ThreadPool.QueueUserWorkItem(delegate
            {
                callback.OnHello(text);
            });

            return text;
        }
    }
    class MyCallback : ICallback
    {
        AutoResetEvent evt;
        public MyCallback(AutoResetEvent evt)
        {
            this.evt = evt;
        }

        public void OnHello(string text)
        {
            Console.WriteLine("[callback] OnHello({0})", text);
            evt.Set();
        }

        public IAsyncResult BeginOnHello(string text, AsyncCallback callback, object state)
        {
            throw new NotImplementedException();
        }

        public void EndOnHello(IAsyncResult asyncResult)
        {
            throw new NotImplementedException();
        }
    }
    public static void Test()
    {
        string baseAddress = "net.tcp://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        host.AddServiceEndpoint(typeof(ITest), new NetTcpBinding(SecurityMode.None), "");
        host.Open();
        Console.WriteLine("Host opened");

        AutoResetEvent evt = new AutoResetEvent(false);
        MyCallback callback = new MyCallback(evt);
        DuplexChannelFactory<ITest> factory = new DuplexChannelFactory<ITest>(
            new InstanceContext(callback),
            new NetTcpBinding(SecurityMode.None),
            new EndpointAddress(baseAddress));
        ITest proxy = factory.CreateChannel();

        Console.WriteLine(proxy.Hello("foo bar"));
        evt.WaitOne();

        ((IClientChannel)proxy).Close();
        factory.Close();

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
person carlosfigueira    schedule 28.04.2012
comment
По какой причине вы вызываете обратный вызов через поток ThreadPool.QueueUserWorkItem(delegate { callback.OnHello(text); });? Не могли бы вы посоветовать, как можно вызвать асинхронный BeginOnHello? Вызывается ли EndOnHello по соглашению об именах? - person morleyc; 16.09.2015