WCF Beta 2 Code: ServiceThrottleBehavior in code, config, and custom attribute


I just wrote this quickly for an example for the forum, and I thought I'd post it more completely here. The ServiceThrottleBehavior is used to control various throughput settings that help keep your application well-balanced against loads.


Programmatically, you'd do this:


using System;
using System.Configuration;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Design;


namespace Microsoft.WCF.Documentation
{
  class HostApplication
  {


    static void Main()
    {
      HostApplication app = new HostApplication();
      app.Run();
    }


    private void Run()
    {
      // Get base address from app settings in configuration if you want.
      Uri baseAddress = new Uri(ConfigurationManager.AppSettings["baseAddress"]);


      // Create a ServiceHost for the service type and provide the base address.
      using (ServiceHost serviceHost = new ServiceHost(typeof(SampleService), baseAddress))
      {
          try
          {
            ServiceThrottlingBehavior throttle = serviceHost.Description.Behaviors.Find<ServiceThrottlingBehavior>();
            if (throttle == null)
            {
              throttle = new ServiceThrottlingBehavior();
              throttle.MaxConcurrentCalls = 1;
              throttle.MaxConnections = 1;
              throttle.MaxInstances = 1;
              throttle.MaxPendingOperations = 1;
              serviceHost.Description.Behaviors.Add(throttle);
            }
            else
              Console.WriteLine("Prior to ServiceHost.Open: A ServiceThrottleBehavior has already been configured for this host.");
            // Open the ServiceHostBase to create listeners and start listening for messages.
            serviceHost.Open();


            // The service can now be accessed.
            Console.WriteLine("The service is ready.");
            Console.WriteLine("Press <ENTER> to terminate service.");
            Console.WriteLine();
            Console.ReadLine();


            // Close the ServiceHostBase to shutdown the service.
            serviceHost.Close();
          }
          catch (TimeoutException timeProblem)
          {
              Console.WriteLine("The service operation timed out. " + timeProblem.Message);
          }
          catch (CommunicationException commProblem)
          {
              Console.WriteLine("There was a communication problem. " + commProblem.Message);
          }
      }
    }
  }
}


But if you wanted to do this using a configuation file, you'd do this:


 


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <!-- use appSetting to configure base address provided by host -->
    <add key="baseAddress" value="
http://localhost:8080/ServiceMetadata" />
  </appSettings>
  <system.serviceModel>
    <services>
      <service
        type="Microsoft.WCF.Documentation.SampleService,HostApplication"
        behaviorConfiguration="Throttled" >
        <endpoint
          address="/SampleService"
          binding="wsHttpBinding"
          contract="Microsoft.WCF.Documentation.ISampleService,HostApplication"
         />
      </service>
    </services>
    <behaviors>
      <behavior  name="Throttled">
        <throttling maxConcurrentCalls="1" maxConnections="1" maxInstances="1" maxPendingOperations="1"/>
      </behavior>
    </behaviors>
  </system.serviceModel>
</configuration>


Finally, if you really like this, but don't want to do the programmatic work in your host (for example, to use it in code but in WAS/IIS), you can do the same work in a custom attribute, like so:


using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Design;
using System.Text;


namespace Microsoft.WCF.Documentation
{
  [ServiceContract(Namespace="Microsoft.WCF.Documentation")]
  public interface ISampleService{
    [OperationContract]
    string SampleMethod(string msg);
  }


  [ServiceThrottling(1,1,1,1)]
  class SampleService : ISampleService
  {
  #region ISampleService Members


  public string  SampleMethod(string msg)
  {
    ServiceThrottle currentThrottle = OperationContext.Current.ServiceThrottle;
    Console.WriteLine("Service called. Current throttle values: " );
    Console.WriteLine("MaxConcurrentCalls: {0}.", currentThrottle.MaxConcurrentCalls.ToString());
    Console.WriteLine("MaxConnections: {0}.", currentThrottle.MaxConnections.ToString());
    Console.WriteLine("MaxInstances: {0}.", currentThrottle.MaxInstances.ToString());
    Console.WriteLine("MaxPendingOperations: {0}.", currentThrottle.MaxPendingOperations.ToString());
    return "The service greets you: " + msg;
  }


  #endregion
  }


  [AttributeUsage(AttributeTargets.Class)]
  public class ServiceThrottlingAttribute : Attribute, IServiceBehavior
  {
    private ServiceThrottlingBehavior throttle;


    public ServiceThrottlingAttribute(
      int maxConcurrentCalls,
      int maxConnections,
      int maxInstances,
      int maxPendingOperations)
    {
      this.throttle = new ServiceThrottlingBehavior();
      throttle.MaxConcurrentCalls = maxConcurrentCalls;
      throttle.MaxConnections = maxConnections;
      throttle.MaxInstances = maxInstances;
      throttle.MaxPendingOperations = maxPendingOperations;
    }
   
    #region IServiceBehavior Members


    public void ApplyBehavior(
      ServiceDescription description,
      ServiceHostBase serviceHostBase,
      System.Collections.ObjectModel.Collection<DispatchBehavior> behaviors,
      System.Collections.ObjectModel.Collection<BindingParameterCollection> parameters
    )
    {


      ServiceThrottlingBehavior currentThrottle = description.Behaviors.Find<ServiceThrottlingBehavior>();
      if (currentThrottle == null)
      {
        description.Behaviors.Add(this.throttle);
        Console.WriteLine("Throttling added by the ServiceThrottleAttribute.");
      }
      else
      {
        Console.WriteLine("In ServiceThrottleAttribute.ApplyBehavior: "
        + "A ServiceThrottleBehavior has already been configured for this host.");
      }
    }


    #endregion
  }
}


 


 


Skip to main content