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
}
}