tags:

views:

27

answers:

0

The following code ( an example taken from a book ) defines duplex contract for a service that provides stock price updates. It uses duplex communication so that client can register for updates, and the service will periodically send updates to the client:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Threading;
using System.ServiceModel.Description;

namespace ConsoleApplication1
{
    [ServiceContract(CallbackContract = typeof(IClientCallBack))]
    public interface IServerStock
    {
        [OperationContract(IsOneWay = true)]
        void RegisterForUpdates(string ticker);
    }


    public interface IClientCallBack
    {
        [OperationContract(IsOneWay = true)]
        void PriceUpdate(string ticker, double price);
    }

    public class ServerStock : IServerStock
    {
        public void RegisterForUpdates(string ticker)
        {
            Update bgWorker = new Update();
            bgWorker.callback = OperationContext.Current.GetCallbackChannel<IClientCallBack>();

            Thread t = new Thread(new ThreadStart(bgWorker.SendUpdateToClient));
            t.IsBackground=true;
            t.Start();
        }
    }

    public class Update
    {
        public IClientCallBack callback = null;
        public void SendUpdateToClient()
        {
            Random p = new Random();
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(6000);
                try
                {
                    callback.PriceUpdate("msft", 100.00 + p.NextDouble());
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error sending update to client");
                }
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost serviceHost = new ServiceHost(
                typeof(ServerStock), new Uri("http://localhost:8000"));
            serviceHost.AddServiceEndpoint(
                typeof(IServerStock), new WSDualHttpBinding(), "");

            ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
            behavior.HttpGetEnabled = true;
            serviceHost.Description.Behaviors.Add(behavior);

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

            serviceHost.Open();
            Console.ReadLine();
        }
    }
}

Client side configuration file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsDualHttpBinding>
                <binding name="WSDualHttpBinding_IServerStock" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00" />
                    <security mode="Message">
                        <message clientCredentialType="Windows" negotiateServiceCredential="true"
                            algorithmSuite="Default" />
                    </security>
                </binding>
            </wsDualHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8000/" binding="wsDualHttpBinding"
                bindingConfiguration="WSDualHttpBinding_IServerStock" contract="ServiceReference1.IServerStock"
                name="WSDualHttpBinding_IServerStock">
                <identity>
                    <userPrincipalName value="aja-PC\aja" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using ConsoleApplication3.ServiceReference1;

public class CallBackHandler:IServerStockCallback 
{
    static InstanceContext site = new InstanceContext(new CallBackHandler());
    static ServerStockClient proxy = new ServerStockClient(site);

    public void PriceUpdate(string ticker, double price)
    {
        Console.WriteLine("received alert at : {0}. {}1:{2}",
            System.DateTime.Now, ticker, price);
    }
    static void Main(string[] args)
    {
        proxy.RegisterForUpdates("MSFT");
        Console.ReadLine();
    }
}

a) When client code is executed, service keeps reporting “The communication object system.ServiceModel.Channels.ServiceChannel cannot ne used for communication because it has been aborted”. Any idea what is causing the exception and how to fix it?

b) Also, when if I make proxy an instance member instead of a static member, then the following code throws an exception System.TypeInitializationException: The type initializer for CallBackHandler’ threw an exception. ---> System.ArgumentNullException. Value cannot be null

static void Main(string[] args)
{
    CallBackHandler handler1 = new CallBackHandler();
    handler1.proxy.RegisterForUpdates("MSFT");
    Console.ReadLine();
}

It’s obvious from the code I’ve posted that CallbackHandler only has a default constructor, so why the exception?

thank you