Freigeben über


ICallContextInitializer Example

Here's the promised sample demonstrating how to set up a call context initializer. The basics really are quite basic so there isn't much to explain in terms of the ICallContextInitializer or the service behavior. I've created a web service with a single operation and attached the call context initializer to the dispatch path for that operation. The only thing the call context initializer does (as well as the web service) is trace the thread ids, but the pattern of any call context initializer is going to be exactly the same regardless of what you actually do in those methods.

To make up for the simplicity though, I've thrown in a bit of a subtle point about the threading model of the dispatcher. You can try the example out yourself to see what changes happen to the invocation patterns as you move between the three bindings (plain TCP, one-way TCP, and security over one-way TCP). This may be the subject of a future article once I get the chance to write about it.

 using System;
using System.Threading;
using System.ServiceModel;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;

[ServiceContract(SessionMode=SessionMode.Allowed)]
interface IService
{
   [OperationContract(IsOneWay=true)]
   void Ping(int id);
}

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Single, InstanceContextMode=InstanceContextMode.PerCall)]
class Service : IService
{
   public void Ping(int id)
   {
      Console.WriteLine("Invoke: Client{1} Server{0}", Thread.CurrentThread.ManagedThreadId, id);
      Thread.Sleep(new Random().Next(500));
   }
}

class CallContextInitializer : ICallContextInitializer
{
   public void AfterInvoke(object correlationState)
   {
      Console.WriteLine("AfterInvoke: Server{0}", Thread.CurrentThread.ManagedThreadId);
   }

   public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
   {
      Console.WriteLine("BeforeInvoke: Server{0}", Thread.CurrentThread.ManagedThreadId);
      return null;
   }
}

class CallContextInitializerBehavior : IEndpointBehavior
{
   public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
   {
   }

   public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
   {
   }

   public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
   {
      endpointDispatcher.DispatchRuntime.Operations["Ping"].CallContextInitializers.Add(new CallContextInitializer());
   }

   public void Validate(ServiceEndpoint endpoint)
   {
   }
}

class Program
{
   static void Service(object binding)
   {
      ServiceHost host = new ServiceHost(typeof(Service), new Uri("net.tcp://localhost/"));
      ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IService), (Binding)binding, "");
      endpoint.Behaviors.Add(new CallContextInitializerBehavior());
      host.Open();
      Console.ReadLine();
      host.Close();
   }

   static void Client(object proxy)
   {
      Console.WriteLine(String.Format("Invoke: Client{0}", Thread.CurrentThread.ManagedThreadId));
      ((IService)proxy).Ping(Thread.CurrentThread.ManagedThreadId);
   }

   static void Main(string[] args)
   {
      CustomBinding binding = new CustomBinding(new TcpTransportBindingElement());

//      binding.Elements.Insert(0, new OneWayBindingElement());

//      SecurityBindingElement security = SecurityBindingElement.CreateSspiNegotiationBindingElement(false);
//      binding.Elements.Insert(0, new CompositeDuplexBindingElement());
//      binding.Elements.Insert(0, SecurityBindingElement.CreateSecureConversationBindingElement(security));

      new Thread(new ParameterizedThreadStart(Service)).Start(binding);
      ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, "net.tcp://localhost/");
      factory.Open();
      IService proxy = factory.CreateChannel();
      for (int i = 0; i < 10; i++)
      {
         new Thread(new ParameterizedThreadStart(Client)).Start(proxy);
      }
   }
}

Next time: Socket Failures

Comments

  • Anonymous
    April 23, 2007
    Today's article is about a little-known extensibility point that runs shortly before and after a service

  • Anonymous
    May 01, 2007
    In the last article on call context initializers , the sample program included three bindings to try