views:

247

answers:

1

Hi!

Here is the server code:

    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();     

        }
    }
}

Here is the client's:

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(); This line constanly throws a NullReferenceException, what's the problem?

Thanks!

+2  A: 

You can't just start a WCF service with a callback contract and immediately try to execute a client callback. There are no clients yet.

In your code, I see you manually instantiating a MyService and trying to execute a callback method. This simply won't work. If you want to use the GetCallbackChannel method then it has to be done when there is actually a channel - i.e. in the context of an actual operation invoked by a remote WCF client. Otherwise, there is no current OperationContext and you'll get a null reference exception because OperationContext.Current returns null.

Callbacks are intended to be used with long-running service operations. For example:

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

To test this you would have to actually create a client - start a new project, add a reference to this service, implement the callback that the importer generates, create an InstanceContext with the callback, create the client proxy using that InstanceContext, and finally invoke its PerformLongRunningOperation method.

If you are trying to develop a pub/sub implementation, where clients do not actually initiate the operations but simply register themselves to receive some callback, have a look at this page: Using Callback Contracts in WCF for Asynchronous Publish/Subscribe Event-Style Communication.

Aaronaught
Thanks a lot!!!
Yaroslav