Дуплексный контракт GetCallbackChannel всегда возвращает нулевой экземпляр - PullRequest
0 голосов
/ 11 апреля 2010

Вот код сервера:

    using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
   using System.ServiceModel;
  using System.Runtime.Serialization;
  using System.ServiceModel.Description;



   namespace Console_Chat
{


    [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IMyCallbackContract))]
    public interface IMyService
    {
        [OperationContract(IsOneWay = true)]
        void NewMessageToServer(string msg);

        [OperationContract(IsOneWay = false)]
        bool ServerIsResponsible();

    }



    [ServiceContract]
    public interface IMyCallbackContract
    {
        [OperationContract(IsOneWay = true)]
        void NewMessageToClient(string msg);

        [OperationContract(IsOneWay = true)]
        void ClientIsResponsible();



    }


    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class MyService : IMyService
    {

       public IMyCallbackContract callback = null;

    /*
    {
            get
            {
                return OperationContext.Current.GetCallbackChannel<IMyCallbackContract>();
            }
        }
      */  

        public MyService()
        {
            callback = OperationContext.Current.GetCallbackChannel<IMyCallbackContract>();
        }

        public void NewMessageToServer(string msg)

        {
            Console.WriteLine(msg);
        }

        public void NewMessageToClient( string msg)
        {

            callback.NewMessageToClient(msg);
        }


        public bool ServerIsResponsible()
        {
            return true;
        }

    }




    class Server
    {
        static void Main(string[] args)
        {
            String msg = "none";


            ServiceMetadataBehavior behavior = new
            ServiceMetadataBehavior();


            ServiceHost serviceHost = new
            ServiceHost(
            typeof(MyService),
            new Uri("http://localhost:8080/"));

            serviceHost.Description.Behaviors.Add(behavior);

            serviceHost.AddServiceEndpoint(
                typeof(IMetadataExchange),
                MetadataExchangeBindings.CreateMexHttpBinding(),
                "mex");


            serviceHost.AddServiceEndpoint(
                typeof(IMyService),
                new WSDualHttpBinding(),
                "ServiceEndpoint"
                );

            serviceHost.Open();
            Console.WriteLine("Server is up and running");

            MyService server = new MyService();
            server.NewMessageToClient("Hey client!");
/*

             do
            {
                msg = Console.ReadLine();

               // callback.NewMessageToClient(msg);


            } while (msg != "ex");

  */
            Console.ReadLine();     

        }
    }
}

Вот клиент:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
using System.ServiceModel.Description;
using Console_Chat_Client.MyHTTPServiceReference;



namespace Console_Chat_Client
{
    [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IMyCallbackContract))]
    public interface IMyService
    {
        [OperationContract(IsOneWay = true)]
        void NewMessageToServer(string msg);

        [OperationContract(IsOneWay = false)]
        bool ServerIsResponsible();

    }



    [ServiceContract]
    public interface IMyCallbackContract
    {
        [OperationContract(IsOneWay = true)]
        void NewMessageToClient(string msg);

        [OperationContract(IsOneWay = true)]
        void ClientIsResponsible();

    }




    public class MyCallback : Console_Chat_Client.MyHTTPServiceReference.IMyServiceCallback
    {

       static InstanceContext ctx = new InstanceContext(new MyCallback());

       static MyServiceClient client = new MyServiceClient(ctx);



        public void NewMessageToClient(string msg)
        {
            Console.WriteLine(msg);
        }

        public void ClientIsResponsible()
        {

        }


                class Client
                {
                    static void Main(string[] args)
                    {
                        String msg = "none";





                        client.NewMessageToServer(String.Format("Hello server!"));


                        do
                        {
                           msg = Console.ReadLine();
                           if (msg != "ex")
                               client.NewMessageToServer(msg);
                           else client.NewMessageToServer(String.Format("Client terminated"));
                        } while (msg != "ex");
                    }
                }






    }
}

callback = OperationContext.Current.GetCallbackChannel (); Эта строка постоянно вызывает исключение NullReferenceException, в чем проблема?

Спасибо!

1 Ответ

3 голосов
/ 11 апреля 2010

Вы не можете просто запустить службу WCF с контрактом обратного вызова и сразу попытаться выполнить обратный вызов клиента. Клиентов пока нет.

В вашем коде я вижу, как вы вручную создаете MyService и пытаетесь выполнить метод обратного вызова. Это просто не сработает. Если вы хотите использовать метод GetCallbackChannel, то это нужно делать, когда фактически существует канал - то есть в контексте фактической операции, вызываемой удаленным клиентом WCF. В противном случае текущее значение OperationContext отсутствует, и вы получите исключение нулевой ссылки, поскольку OperationContext.Current возвращает null.

Обратные вызовы предназначены для использования с длительными операциями обслуживания. Например:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyService : IMyService
{
    // One-way method
    public void PerformLongRunningOperation()
    {
        var callback = 
            OperationContext.Current.GetCallbackChannel<IMyCallbackContract>();
        var result = DoLotsOfWork();
        callback.LongRunningOperationFinished(result);
    }
}

Чтобы проверить это, вам фактически нужно создать клиента - начать новый проект, добавить ссылку на эту службу, реализовать обратный вызов, который генерирует импортер, создать InstanceContext с обратным вызовом, создать прокси-клиент клиента с помощью этого InstanceContext и, наконец, вызовите его PerformLongRunningOperation метод.

Если вы пытаетесь разработать реализацию pub / sub, в которой клиенты на самом деле не инициируют операции, а просто регистрируют себя для получения обратного вызова, взгляните на эту страницу: Использование контрактов обратного вызова в WCF для асинхронной публикации / Подписаться Event-Style Communication .

...