Welcome to MSDN Blogs Sign in | Join | Help

Couldn't get better than this. Wenlong has pretty much detailed out to the gory details of understanding WCF scalability in these posts.

  1. WCF Request Throttling and Server Scalability
  2. Orcas SP1 Improvement: Asynchronous WCF HTTP Module/Handler for IIS7 for Better Server Scalability

The fact you realize is that one bottle neck is enough to kill your scalability.

IIts been a long wait. After working with customers for getting out their token service and doing all the claim based black magic, finally we have a framework. Its not a bubble gum and match stick situation more and its a full framework.

If you want to build applications and solve your federation problems which i have had a lot of previous posts on then you really want to take a look at this. Vittorio is put up quite a cool set of links and a very neat overview which I don't want to cut paste here.

The one thing i have seen is the ease of integrating with Zermatt. Those of you who want to just go to the gory details head out to Keith's post-  or white paper directly on connect-

I still remember working with Vittorio and Martin in getting up the STS during the indigo beta days .. nice to see this out which really makes it easy to get your security around your solution. I would like to emphasize on the fact that claim's based approach is a security solution and not just an approach. The spec is so rich if you have the time to digest it cause it breaks down complex problems of multi-hop scenario and delegation really simple. Transformations are another area which I am interested in and would see how Zermat solves this problems.

Happy spelunking.

Have you ever wanted to do something like this .

    // Define a service contract.

    [ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]

    public interface ICalculator

    {

        [OperationContract]

        [PerfOperationBehavior]

        double Add(double n1, double n2);

        [OperationContract]

        double Subtract(double n1, double n2);

       

        [OperationContract]       

        double Multiply(double n1, double n2);

       

        [OperationContract]

        double Divide(double n1, double n2);

 

    }

Where you probably wanted to write some code to log the time for the operation or just update some performance counter on the server. If you are already familiar with Operation invoker then the rest rest of the post is just a waste of time since i just wanted to show how the operation invoker could be used pretty much inject your code into the pipeline to see what is the execution time of your operation.

These are pretty much the steps you need to do.

  1. Create an operation behavior obviously since you want to attach to the operation.
  2. Implement the IOperationInvoker for kind of intercepting operation invocation.
  3. Attach a counter extension to log the start and end of the operation.  

And you pretty much have your behavior you can just add on the operation.

Here is the behavior and the classes required to implement this and shows a very bare bone implementation of the ticks that would occur between invocations of an operation.

FInd the full solution attached below.

using System;

using System.Collections.Generic;

using System.Text;

using System.ServiceModel.Description;

using System.ServiceModel.Dispatcher;

using System.ServiceModel;

using System.Diagnostics;

 

namespace Microsoft.Samples.Wcf.Performance

{

    [AttributeUsage(AttributeTargets.Method)]

    public class PerfOperationBehavior : System.Attribute, IOperationBehavior

    {

        #region IOperationBehavior Members

 

        void IOperationBehavior.AddBindingParameters(OperationDescription operationDescription,

            System.ServiceModel.Channels.BindingParameterCollection bindingParameters)

        {

        }

 

        void IOperationBehavior.ApplyClientBehavior(OperationDescription operationDescription,

            System.ServiceModel.Dispatcher.ClientOperation clientOperation)

        {

        }

 

        void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription,

            System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)

        {

            dispatchOperation.Invoker = new PerfCounterOperationInvoker(dispatchOperation.Invoker);

        }

 

        void IOperationBehavior.Validate(OperationDescription operationDescription)

        {

        }

 

        #endregion

    }

 

 

    internal class PerfCounterOperationInvoker : IOperationInvoker

    {

        IOperationInvoker innerOperationInvoker;

 

        public PerfCounterOperationInvoker(IOperationInvoker invoker)

        {

            this.innerOperationInvoker = invoker;

        }

 

        #region IOperationInvoker Members

 

        object[] IOperationInvoker.AllocateInputs()

        {

            return this.innerOperationInvoker.AllocateInputs();

        }

 

        object IOperationInvoker.Invoke(object instance, object[] inputs, out object[] outputs)

        {

            OperationContext.Current.Extensions.Add(new PerfOperationContextExtension());

            try

            {

                return this.innerOperationInvoker.Invoke(instance, inputs, out outputs);               

            }

            finally

            {

                OperationContext.Current.Extensions.Remove(

                    OperationContext.Current.Extensions.Find<PerfOperationContextExtension>());

            }

        }

 

        IAsyncResult IOperationInvoker.InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)

        {

            OperationContext.Current.Extensions.Add(new PerfOperationContextExtension());

            return this.innerOperationInvoker.InvokeBegin(instance, inputs, callback, state);

        }

 

        object IOperationInvoker.InvokeEnd(object instance, out object[] outputs, IAsyncResult result)

        {

            OperationContext.Current.Extensions.Remove(

                OperationContext.Current.Extensions.Find<PerfOperationContextExtension>());

            return this.innerOperationInvoker.InvokeEnd(instance, out outputs, result);

        }

 

        bool IOperationInvoker.IsSynchronous

        {

            get { return this.innerOperationInvoker.IsSynchronous; }

        }

 

        #endregion

    }

 

    internal class PerfOperationContextExtension : IExtension<OperationContext>

    {

        long ticks;

       

        #region IExtension<OperationContext> Members

 

        public void Attach(OperationContext owner)

        {

            ticks = DateTime.Now.Ticks;

        }

 

        public void Detach(OperationContext owner)

        {

            ticks = DateTime.Now.Ticks - ticks;

 

            Debug.WriteLine(string.Format("Operation : {0} took {1} ticks",

                                    owner.IncomingMessageHeaders.Action,

                                    ticks));

        }

        #endregion

    }

}

 

 

 

 

 

The snippet below might not be for the faint hearted. Primarily since its quite gory wcf. I realized that there is so much abstraction in the Service model's channel layers thats its only justice that someone does a simple sample in how to send and read raw messages. I would suggest you to understand the ICommunicationObject by Nicholas before this.

I would not be diving into security and behaviors for this post but just wanted to touch upon using a simple IRequest and IReply channel. Now for those of you not familiar with MEP this would be a good time to figure out what are the different kinds of MEP (message exchange patterns) that WCF support. I would like to point you to http://blogs.msdn.com/drnick/archive/2007/03/08/channel-shapes.aspx where Nicholas has given a nice diagram for this.

In this post i use the HTTP model which is enabled through the Request reply pattern. The service in short is an Http listener and uses, as the name would suggest a, ChannelListener and the client which is capable of sending a message would use the channel factory. Both of these are created from the Binding.

If you program in WCF you come across a lot of references to the channel stack. One of the key take aways of this pattern is that the underlying channel has some duties delegated to it to be performed by the above layer and there are some fundament rules that have to be obeyed by every channel in the channel stack

You can take a look below on how raw strings can be sent across. The intent of this sample is to show how the binding is used to create the channel Listeners and the channel factory. 

1. The Channel Listener - The channel listener used here uses the Http listener and to start the listening service we use the IReplyChannel . We can invoke RecieveRequest which would give us the calling transport channel. This can be used to respond to the calling client. We can send a reply back to the caller using this RequestContext.

  1. Use the Binding to build the channel listener.
  2. Open the listener.
  3. Get the transport channel using AcceptChannel();
  4. Open the transport.


2. Channel Factory - To send a message across to the listener we use the binding to create the channel factory.

  1. Build the channel factory usign the Binding.
  2. Buid the channel to send using the channel factory
  3. send the message to the server using the Request on the IRequestChannel. As you would notice the request method also give your an output message which is what the server responds with.

    Message
    response = channel.Request(msg);

 

You can check out the full sample here.

using System;

using System.Collections.Generic;

using System.Text;

using System.ServiceModel;

using System.ServiceModel.Channels;

using System.Threading;

 

namespace WcfRawMessages

{

    class Program

    {

        static void Main(string[] args)

        {

            //Start the listener

            ServiceHelpers.StartListener();

 

            //Invoke with test messages.

            for (int i = 0; i < 10; i++)

            {

                TestClientHelper.SendTestMessage();

            }

 

 

            Console.ReadLine();

 

            ServiceHelpers.Stop();

        }

 

        public class BindingHelpers

        {

            public static Uri Address = new Uri("http://localhost:8089");

            public static Binding GetBinding()

            {

                CustomBinding binding = new CustomBinding();

 

                //add the encoder and the binding

                MessageEncodingBindingElement mbe = new TextMessageEncodingBindingElement();

                mbe.MessageVersion = MessageVersion.None;

                binding.Elements.Add(mbe);

                binding.Elements.Add(new HttpTransportBindingElement());

 

                return binding;

            }

        }

 

        public class ServiceHelpers

        {

            static IReplyChannel transportChannel;

            public static void StartListener()

            {

                Binding binding = BindingHelpers.GetBinding();

                IChannelListener<IReplyChannel> listener = binding.BuildChannelListener<IReplyChannel>(BindingHelpers.Address);

                listener.Open();

                transportChannel = listener.AcceptChannel();

                transportChannel.Open();

 

                Thread t = new Thread(delegate(object state)

              {

                  //Gory while loop to recieve messages from the transport

                  while (true)

                  {

                      try

                      {

                          //Use the request context to recieve a message

                          RequestContext request = transportChannel.ReceiveRequest();

                          if (request != null)

                          {

                              Message msg = request.RequestMessage;

                              Console.WriteLine(msg.GetBody<string>());

 

                              //Send the response…

                              Message replymessage = Message.CreateMessage(msg.Version, "http://responseAction/");

                              request.Reply(replymessage);

                              request.Close();

                              msg.Close();

                              replymessage.Close();

                          }

                      }

                      catch (CommunicationException ex)

                      {

                          Console.WriteLine("Communication Exception " + ex.Message);

                      }

 

                      if (transportChannel.State != CommunicationState.Opened)

                          break;

                  }

              });

                t.Start();

            }

 

            internal static void Stop()

            {

                transportChannel.Close();

                //transportChannel.Abort();

            }

        }

 

        public class TestClientHelper

        {

            static IChannelFactory<IRequestChannel> factory;

            static int counter = 0;

            public static void SendTestMessage()

            {

                Binding binding = BindingHelpers.GetBinding();

 

                //Create the channel factor.

                if (factory == null)

                {

                    factory = binding.BuildChannelFactory<IRequestChannel>(BindingHelpers.Address);

                    factory.Open();

                }

 

                //Create the channel.

                IRequestChannel channel = factory.CreateChannel(new EndpointAddress(BindingHelpers.Address));

                channel.Open();

 

                Message msg = Message.CreateMessage(binding.MessageVersion, "", "Body Text" + counter++);

                Message response = channel.Request(msg);

                channel.Close();

                msg.Close();

                response.Close();

 

            }

        }

    }

}

 

 

 

After quite a long blog on managed semaphores this would be quite a refresher. :)

When trying to connect your XBOX 360 to your vista with Media center things can get pretty interesting. There are quite a few posts that would tell you trouble shooting issues. This is pertaining to IPSEC and a Vista machine that belongs to a domain with pretty stringent IPSEC group policy and you bring your laptop home but your xbox just cant connect to the vista machine. For direct connectivity refer http://support.microsoft.com/kb/932161 and other posts on support.microsoft.com.

If you get this message in your Security Audit log like "dropped packet in clear text" where the IP is that of your xbox then you could check these steps:

1. Check if your Xbox connects to Xbox live without any issues.
2. Check if your machine also connects to the internet without any problems over the same .
3: Open advanced firewall settings and navigate to Monitoring->Connection security rules and check if your home lan net is exempted from the IPSec rule policy. usually the range is Endpoint 2 IP address:192.168.0.0-192.168.1.255.
4. Finally check if your xbox and your system lies in these ranges for the policy to permit.In my case i had to change my router address to these ranges..

There were many posts the suggested turning of IPSEC but this seems to be a better way IMHO :)

F