Extending the WCF Stack

In my last post I created a custom serializer that could be injected into the WCF plumbing between the dispatcher and the service class that allowed us to debug errors that occurred during serialization. This operation behaviour could be applied to a method signature in the service contract :
 
[ServiceContract()]
public interface IMyService
{
	[OperationContract]
	[DebuggableSerializer]
	Thing GetThing(Flavour flavour); 
	
	[OperationContract]
	[DebuggableSerializer]
	Thing[] GetOneOfEach();
}
or to the implementation of that method in the service class :
 
[DebuggableSerializer]
public Thing[] GetOneOfEach()
{
	List<Thing> things = new List<Thing>();
	foreach(Flavour f in Enum.GetValues(typeof(Flavour)))
	{
		things.Add(this.GetThing(f));
	}
	return things.ToArray();
}
However, what if I wanted to apply this behaviour as a ServiceBehavior, ContractBehavior or EndpointBehavior rather than an OperationBehavior i.e. if I wanted all the operations in my service implementation or interface to use it and I don’t want to have to go through and add the attribute to every method ? How can I use my [DebuggableSerializer] attribute to decorate a service class, interface or even better, apply the behaviour to the service or endpoint using a config file so I don’t have to change my code at all ?
 
So, in this post I am going to extend my [DebuggableSerializer] attribute so it can be used on a service class or interface and I am going to extend the System.ServiceModel.Configuration.BehaviorExtensionElement to allow me to control and apply that behaviour from my config file to either a service or a specific endpoint.
 
My attribute in the previous example looked like this :
 
public class DebuggableSerializer : Attribute, IOperationBehavior
but now we want to use it as a ServiceBehavior, ContractBehavior and an EndpointBehavior as well as an OperationBehavior, so we’ll implement the IServiceBehavior, IContractBehavior and IEndpointBeahvior  interfaces :
 
public class DebuggableSerializer : Attribute, IOperationBehavior, 
	IServiceBehavior, IEndpointBehavior, IContractBehavior
IServiceBehavior has three methods for which we need to add implementations and IContractBehavior and IEndpointBehavior have 4 :
 
#region IServiceBehavior Members 

public void AddBindingParameters(ServiceDescription serviceDescription,
	ServiceHostBase serviceHostBase, 
	System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints,
	BindingParameterCollection bindingParameters)
{
	ReplaceDataContractSerializerOperationBehavior(serviceDescription);
}

public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
	ServiceHostBase serviceHostBase)
{
	ReplaceDataContractSerializerOperationBehavior(serviceDescription);
} 

public void Validate(ServiceDescription serviceDescription,
	ServiceHostBase serviceHostBase)
{
} 

#endregion

#region IEndpointBehavior Members 

public void AddBindingParameters(ServiceEndpoint endpoint,
	BindingParameterCollection bindingParameters)
{
} 

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

public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
	EndpointDispatcher endpointDispatcher)
{
	ReplaceDataContractSerializerOperationBehavior(endpoint);
} 

public void Validate(ServiceEndpoint endpoint)
{
}

#endregion

#region IContractBehavior Members 

public void AddBindingParameters(ContractDescription contractDescription,
	ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{ 
} 

public void ApplyClientBehavior(ContractDescription contractDescription,
	ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
	ReplaceDataContractSerializerOperationBehavior(contractDescription);
} 

public void ApplyDispatchBehavior(ContractDescription contractDescription,
	ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
	ReplaceDataContractSerializerOperationBehavior(contractDescription);
} 

public void Validate(ContractDescription contractDescription,
	ServiceEndpoint endpoint)
{ 
} 

#endregion
We also need to provide 3 overloads of the ReplaceDataContractSerializerOperationBehavior method, one that takes ServiceDescription, one that takes ServiceEndpoint and one that takes ContractDescription instead of OperationDescription. The method that takes ServiceDescription will call the method that takes ServiceEndpoint for each Endpoint and the method that takes ServiceEndpoint will call the method that takes ContractDescription and the method that takes ContractDescription will call the method that takes OperationDescription for each OperationDescription in its contract.
 
private static void ReplaceDataContractSerializerOperationBehavior(
	ServiceDescription description)
{
	foreach (ServiceEndpoint endpoint in description.Endpoints)
	{
		ReplaceDataContractSerializerOperationBehavior(endpoint);
	}
}

private static void ReplaceDataContractSerializerOperationBehavior(
	ContractDescription description)
{
	foreach (OperationDescription desc in description.Operations)
	{
		ReplaceDataContractSerializerOperationBehavior(desc);
	}
} 

private static void ReplaceDataContractSerializerOperationBehavior(
	ServiceEndpoint endpoint)
{
	// ignore mex
	if (endpoint.Contract.ContractType == typeof(IMetadataExchange))
	{
		return;
	}
	ReplaceDataContractSerializerOperationBehavior(endpoint.Contract);
}
So now we can take our DebuggableSerializer attribute and place it on the service class or interface :
 
[DebuggableSerializer]
public class MyService : IMyService
{ ... }

[DebuggableSerializer]
public interface IMyService
{ ... }
We now have an attribute that can be used to replace the serializer on a service contract or an operation contract or a service operation or on a whole service class or an endpoint of a service. The final step is to be able to add this behaviour to a service or an endpoint from within our configuration rather than in code. For this we need to create a BehaviorExtensionElement that will create an instance of our DebuggableSerializer behaviour. This is very simple :
 
public class UseDebuggableSerializer : BehaviorExtensionElement
{ 
	public override Type BehaviorType
	{
		get { return typeof(DebuggableSerializer); }
	}
	
	protected override object CreateBehavior()
	{
		return new DebuggableSerializer();
	}
}
Next, in our config file, we need to define this behaviour extension :
 
<system.serviceModel>
	<extensions>
		<behaviorExtensions>
			<add name="UseDebuggableSerializer"
				type="WCFLibrary.UseDebuggableSerializer, WCFLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
		</behaviorExtensions>
	</extensions>
	<!-- elided -->
</system.serviceModel>
To add this behaviour to a service we add the extension to the service’s assigned behaviour :
 
<system.serviceModel>
	<!-- elided -->
	<behaviors>
		<serviceBehaviors>
			<behavior name="MetadataExchange">
				<serviceMetadata httpGetEnabled="true" />
				<UseDebuggableSerializer />
			</behavior>
		</serviceBehaviors>
	</behaviors>
	<!-- elided -->
</system.serviceModel>
To add it to an endpoint we define an endpoint behaviour and add the extension to that :
 
<system.serviceModel>
	<!-- elided -->
	<behaviors>
		<endpointBehaviors>
			<behavior name="DebuggableSerializer">
				<UseDebuggableSerializer />
			</behavior>
		</endpointBehaviors>
	</behaviors>
	<!-- elided -->
	<service behaviorConfiguration="MetadataExchange" 
		name="WCFLibrary.MyService">
	<endpoint
		address="net.tcp://localhost:7000/MyService"
		behaviorConfiguration="DebuggableSerializer"
		binding="netTcpBinding"
		name="TCP_7000_MyService"
		contract="WCFLibrary.IMyService" />
	</service>
	<!-- elided -->
</system.serviceModel>

Advertisements

Debugging the WCF Stack

As if starting developing with WCF wasn’t a hard enough paradigm shift what with getting used to sharing schema instead of type and being cruelly abstracted away from all our lovely plumbing, the abstraction itself it can throw some interesting curve-balls. It’s all very well taking the plumbing and abstracting it away but what happens when errors occur down there…out of our reach ? The errors may still be in our code but if they are being hit by the DataContractSerializer for instance it’s hard to handle them or even catch them, for that matter. To illustrate the problem and provide a possible solution, here’s an example.
 
First we’ll create a nice simple service library.
 
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization; 

namespace WCFLibrary
{
	[ServiceContract()]
	public interface IMyService
	{
		[OperationContract]
		Thing GetThing(Flavour flavour); 
		
		[OperationContract]
		Thing[] GetOneOfEach();
	} 
	
	public class MyService : IMyService
	{ 
		#region IMyService Members 
		public Thing GetThing(Flavour flavour)
		{
			switch (flavour)
			{
				case Flavour.Orange:
					return new Thing("Ollie", Flavour.Orange);
				case Flavour.Raspberry:
					return new Thing("Roger", Flavour.Raspberry);
				case Flavour.Strawberry:
					return new Thing("Sally", Flavour.Strawberry);
				case Flavour.Banana:
					return new Thing("Bernice", Flavour.Banana);
				default:
					throw new FaultException("No such flavour");
			}
		} 

		public Thing[] GetOneOfEach()
		{
			List<Thing> things = new List<Thing>();
			foreach(Flavour f in Enum.GetValues(typeof(Flavour)))
			{	
				things.Add(this.GetThing(f));
			}
			return things.ToArray();
		} 
		#endregion
	}
	
	public enum Flavour
	{
		Strawberry,
		Raspberry,
		Orange,
		Banana
	} 

	[DataContract]
	public class Thing
	{
		string name;
		Flavour flavour; 
		public Thing(string name, Flavour flavour)
		{
			this.Name = name;
			this.Flavour = flavour;
		}
		
		[DataMember]
		public string Name
		{
			get { return name; }
			set { name = value; }
		} 

		[DataMember]
		public Flavour Flavour
		{
			get { return flavour; }
			set { flavour = value; }
		}
	}
}
Then a host application.
 
using System;
using System.Collections.Generic;
using System.Text; 
using System.ServiceModel;

namespace WCFHost
{
	class Program
	{
		static void Main(string[] args)
		{ 
			using (ServiceHost host = new ServiceHost(
				typeof(WCFLibrary.MyService),	
				new Uri("http://localhost:7001/MyService")))
			{
				host.Closed += new EventHandler(host_Closed);
				host.Open();
				Console.WriteLine(
					"{0} is running at {1}.\nPress any key to close and exit...",
					host.Description.ServiceType.FullName,
					host.BaseAddresses[0].ToString());
				Console.ReadKey(true);
			}	 
		}
		
		static void host_Closed(object sender, EventArgs e)
		{
			Console.WriteLine("{0} closed.",
				((ServiceHost)sender).Description.ServiceType.FullName);
		}
	}
}
With the following config :
 
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<system.serviceModel>
		<behaviors>
			<serviceBehaviors>
				<behavior name="MetadataExchange">
					<serviceMetadata httpGetEnabled="true" />
				</behavior>
			</serviceBehaviors>
		</behaviors>
		<services>
			<service behaviorConfiguration="MetadataExchange" 
				name="WCFLibrary.MyService">
			<endpoint address="net.tcp://localhost:7000/MyService" 
				binding="netTcpBinding"
				bindingConfiguration="" name="TCP_7000_MyService"
				contract="WCFLibrary.IMyService" />
			</service>
		</services>
	</system.serviceModel>
</configuration>
And finally having generated a client proxy we can call it like this :
 
using System;
using System.Collections.Generic;
using System.Text; 
using WCFClient.MyService; 
namespace WCFClient
{
	class Program
	{
		static void Main(string[] args)
		{
			using (MyServiceClient proxy = new MyServiceClient())
			{
				foreach (Thing thing in proxy.GetOneOfEach())
				{
					Console.WriteLine("{0} {1}", 
						thing.Name, 
						thing.Flavour.ToString());
				}
			}
			Console.ReadKey(true);
		}
	}
}
Now, we’ll introduce an error in the service that will not be encountered until the Data Contract class is serialized, i.e. it will occur out of scope of the actual service method call. We are going to change this line in our GetThing service method :
 
case Flavour.Banana:
	return new Thing("Bernice", Flavour.Banana);
to this :
 
case Flavour.Banana:
	return new Thing("Bernice", (Flavour)9);
So we are sneakily casting the integer value 9 into the integer-based enum Flavour even though it’s not a valid value of Flavour. I have actually seen a live version of this error where some unexpected integer values got into a database column so the line actually looked more like this :
 
return new Thing("Bernice", (Flavour)reader.GetInt32(3));
When the service is run and called by the client no error is seen in the service even when debugging and the error appears on the client as a timeout. So, imagine this error is intermittent because it only occurs in a very few out of thousands of database records. Some clients are complaining of timeout errors even though the service isn’t busy and there are no errors on the server side. We can’t debug this and there doesn’t seem to be anywhere we can put a try-catch block. What we really need to be able to do is debug into the DataContractSerializer but we can’t. One option is to enable tracing in the service diagnostics. This can be done either using the WCF Configuration Editor :
 
configeditor
 
or by editing the service config :
 
<system.diagnostics>
	<sources>
		<source name="System.ServiceModel" 
			switchValue="Verbose,ActivityTracing"
			propagateActivity="true">
			<listeners>
				<add type="System.Diagnostics.DefaultTraceListener" 
					name="Default">
					<filter type="" />
				</add>
				<add name="ServiceModelTraceListener">
					<filter type="" />
				</add>
			</listeners>
		</source>
	</sources>
	<sharedListeners>
		<add initializeData="c:\temp\app_tracelog.svclog"
			type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
			name="ServiceModelTraceListener" 
			traceOutputOptions="LogicalOperationStack, DateTime, Timestamp, ProcessId, ThreadId, Callstack">
			<filter type="" />
		</add>
	</sharedListeners>
</system.diagnostics>
If we run the service again and make the same call we can view the resulting trace log in the Service Trace Viewer :
 
traceviewer
 
There we can clearly see the exception that occurred. The great thing about the tracing and the Trace Viewer is that if we run tracing on all the consumers and services for a particular activity and enable activity propagation we can get the trace logs from all participants and the Trace Viewer will stitch them together for us so we can see the whole thing end to end and step through.
 
This approach is great in many instances but sometimes when debugging it’s a bit "after the fact" and actually what you’d like is to be be able to set a break point or have the debugger catch it in the act so you can get in and look at the stack.
 
To help with this we really need our own serializer but the serializers (DataContractSerializer and NetDataContractSerializer) are sealed. However, XmlObjectSerializer that they both inherit from is not and it is this type that is used so maybe be can hook in there somehow. I can create a class that inherits from XmlObjectSerializer but I don’t want to write my own serializer…way too much work. However, I can use this class as a wrapper for the actual serializer and delegate to it. This effectively injects my debuggable code into the hard-to-debug WCF plumbing. Here’s my DebuggableDataContractSerializer :
 
public class DebuggableDataContractSerializer : XmlObjectSerializer
{
	private XmlObjectSerializer _Serializer;
	
	public DebuggableDataContractSerializer(XmlObjectSerializer serializerToUse)
	{
		if (serializerToUse == null)
		{
			throw new ArgumentException("Argument cannot be null.", "serializerToUse");
		}
		this._Serializer = serializerToUse;
	}
	
	public override bool Equals(object obj)
	{
		return this._Serializer.Equals(obj);
	}
		
	public override bool IsStartObject(XmlDictionaryReader reader)
	{
		return this._Serializer.IsStartObject(reader);
	}
	
	public override object ReadObject(XmlDictionaryReader reader)
	{
		return this._Serializer.ReadObject(reader);
	}
	
	public override object ReadObject(XmlReader reader)
	{
		return this._Serializer.ReadObject(reader);
	} 
	
	public override object ReadObject(XmlReader reader, bool verifyObjectName)
	{
		return this._Serializer.ReadObject(reader, verifyObjectName);
	}
	
	public override string ToString()
	{
		return this._Serializer.ToString();
	}
	
	public override int GetHashCode()
	{
		return this._Serializer.GetHashCode();
	}
	
	public override bool IsStartObject(XmlReader reader)
	{
		return this._Serializer.IsStartObject(reader);
	}
	
	public override object ReadObject(System.IO.Stream stream)
	{
		return this._Serializer.ReadObject(stream);
	}
	
	public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
	{
		return this._Serializer.ReadObject(reader, verifyObjectName);
	} 

	public override void WriteEndObject(XmlDictionaryWriter writer)
	{
		this._Serializer.WriteEndObject(writer);
	} 
	
	public override void WriteEndObject(XmlWriter writer)
	{
		this._Serializer.WriteEndObject(writer);
	} 
	
	public override void WriteObject(System.IO.Stream stream, object graph)
	{
		this._Serializer.WriteObject(stream, graph);
	} 
	
	public override void WriteObject(XmlDictionaryWriter writer, object graph)
	{
		this._Serializer.WriteObject(writer, graph);
	} 
	
	public override void WriteObject(XmlWriter writer, object graph)
	{
		this._Serializer.WriteObject(writer, graph);
	} 
	
	public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
	{
		this._Serializer.WriteObjectContent(writer, graph);
	} 
	
	public override void WriteObjectContent(XmlWriter writer, object graph)
	{
		this._Serializer.WriteObjectContent(writer, graph);
	} 
	
	public override void WriteStartObject(XmlDictionaryWriter writer, object graph)
	{
		this._Serializer.WriteStartObject(writer, graph);
	} 
	
	public override void WriteStartObject(XmlWriter writer, object graph)
	{
		this._Serializer.WriteStartObject(writer, graph);
	}
}
Now I need to get my serializer swapped out with the real one. I remembered seeing a blog post by Aaron Skonnard way back in April ’06 in which he showed how to substitute the NetDataContractSerializer for the DataContractSerializer so let’s try that here :
 
public class DebuggableSerializer : Attribute, IOperationBehavior
{ 
	public void AddBindingParameters(OperationDescription description,
		BindingParameterCollection parameters)
	{
	}
	
	public void ApplyClientBehavior(OperationDescription description,
		ClientOperation proxy)
	{
		ReplaceDataContractSerializerOperationBehavior(description);
	} 
	
	public void ApplyDispatchBehavior(OperationDescription description,
		DispatchOperation dispatch)
	{
		ReplaceDataContractSerializerOperationBehavior(description);
	} 
	
	public void Validate(OperationDescription description)
	{
	} 
	
	private static void ReplaceDataContractSerializerOperationBehavior(
		OperationDescription description)
	{
		DataContractSerializerOperationBehavior dcsOperationBehavior =
			description.Behaviors.Find<DataContractSerializerOperationBehavior>();
		if (dcsOperationBehavior != null)
		{
			description.Behaviors.Remove(dcsOperationBehavior);
			description.Behaviors.Add(
				new DebuggableDataContractSerializerOperationBehavior(description));
		}
	}
} 
	
public class DebuggableDataContractSerializerOperationBehavior
		: DataContractSerializerOperationBehavior
{
	
	public DebuggableDataContractSerializerOperationBehavior(
		OperationDescription operationDescription) : base(operationDescription)
	{ 
	} 
	
	public override XmlObjectSerializer CreateSerializer(Type type, string name,
	string ns, IList<Type> knownTypes)
	{
		DataContractSerializer dcs = new DataContractSerializer(type, name,
			ns, knownTypes);
		DebuggableDataContractSerializer mdcs = new DebuggableDataContractSerializer(dcs);
		return mdcs;
	} 
	
	public override XmlObjectSerializer CreateSerializer(Type type,
		XmlDictionaryString name,
		XmlDictionaryString ns, IList<Type> knownTypes)
	{
		DataContractSerializer dcs = new DataContractSerializer(type, name, ns, knownTypes);
		DebuggableDataContractSerializer mdcs = new DebuggableDataContractSerializer(dcs);
		return mdcs;
	}
}
Now we add our new custom attribute to our service method and we are good to go.
 
[ServiceContract()]
public interface IMyService
{
	[OperationContract]
	[DebuggableSerializer]
	Thing GetThing(Flavour flavour); 

	[OperationContract]
	[DebuggableSerializer]
	Thing[] GetOneOfEach();
}
 
debugging
 
I have since written an article on how to extend this concept so that it can be used as a ServiceBehavior, ContractBehavior or EndpointBehavior. See Extending the WCF Stack.

On a clear day you can see CodingHorror from here…

What I love about the blogosphere is that for every lazy, fairweather blogger like me there is an inspired one feverishly blogging the stuff I think better than I ever could  so I can just link to it like this : Go Jeff !

Quick ‘n’ Dirty Redirects in DotNetNuke

I have recently been involved in some SEO work on a website written in DotNetNuke. SEO (Search Engine Optimization) is the arcane and mystical art of making your website simultaneously appear interesting/relevant to both users and and search engine bots, most especially the GoogleBot. One of the keys to this it not to have duplicate content on your website, that is to say, pages that appear to be the same that are available via different URLs. If you do this, the GoogleBot will think you are trying to trick it and it devalues the relevance of that content. As a result, if you move content from one URL to another you need to 301 (permanently redirect) the old URL to the new URL.
 
A common way to do this is to buy or write a DNN module that redirects and install it on your site on the pages that should be redirected. This is a pain though because it means that you have to keep those pages in your portal even though you don’t need them any more and each request to them has to load the page and the module before it is redirected.
 
The fact is that DNN is constantly internally redirecting anyway using a technique called URL rewriting. The "real" address of most pages in a DNN portal is /Default.aspx?tabid=1234 where 1234 is a unique identifier for a "page" of content in DNNs database. This rewriting is done by an HttpModule whose configuration is stored in an xml file in the root of the portal (/SiteURLs.config). An example of a URLRewriter rule can be seen here :
 
<RewriterRule>
	<LookFor>.*/MyNiceURL.aspx</LookFor>
	<SendTo>~/Default.aspx?tabid=1234</SendTo>
</RewriterRule>
It occurred to me that it would be easier just to hijack this mechanism and with a very small tweak add permanent (301) and temporary (302) redirects to its features. A new rule would look something like this :
 
<RewriterRule Type="Permanent">
	<LookFor>.*/MyNiceURL.aspx</LookFor>
	<SendTo>~/Default.aspx?tabid=1234</SendTo>
</RewriterRule>
The Type attribute could have values of Permanet, Temporary or Rewrite (the default) or be absent. We then need to make a couple of simple changes to the URLRewriter module which, thanks to open source, we can.
Someone emailed me about this so I thought I’d add a quick clarification. The URLRewriter can only rewrite the path segment of the URL. So if you give it a rule that looks like this :
 
<RewriterRule>
	<LookFor>.*/MyNiceURL.aspx</LookFor>
	<SendTo>http://www.mydomain.com/Default.aspx?tabid=1234</SendTo>
</RewriterRule>
it will instead perform a Response.Redirect. This sends a 302 to the client, not a 301, so without this modification we still have no way of sending a 301 and we can only send a 302 if we include the whole url, i.e. we have limited control over how the rewriter behaves.

First we add an enum to represent our rule type in RewriterRule.vb:
 
Public Enum RewriterRuleType
        Rewrite = 0
        Permanent = 1
        Temporary = 2
End Enum
Then we add the new public property and private field to the RewriterRule class :
 
Private _ruleType As RewriterRuleType = RewriterRuleType.Rewrite

Public Property RuleType() As RewriterRuleType

    Get
        Return _ruleType
    End Get

    Set(ByVal Value As RewriterRuleType)
        _ruleType = Value
    End Set

End Property
We also need to modify the GetConfig method of the RewriteConfiguration class so it knows about our new XML attribute :
 
...

For Each nav As XPathNavigator In doc.CreateNavigator.Select("RewriterConfig/Rules/RewriterRule")

    Dim rule As New RewriterRule()

    rule.LookFor = nav.SelectSingleNode("LookFor").Value

    rule.SendTo = nav.SelectSingleNode("SendTo").Value

    ' >>> begin new code

    Try

        rule.RuleType = CType(System.Enum.Parse(GetType(RewriterRuleType), nav.GetAttribute("Type", ""), False), RewriterRuleType)

    Catch ex As Exception

        ' Do nothing, either there was no attribute or it contained an invalid value
        ' NB : yes this is a dirty hack but this is a blog post not production code

    End Try

    ' >>> end new code

    Config.Rules.Add(rule)

Next

...
Next we need to modify the RewriteURL method of the URLRewriteModule class so it can take different actions based on the newly added Rule Type :
 
(NB : the ruleType variable has been declared at the top of the method and is assigned to as soon as a matching rule is found.)
 
...

If

 intMatch <> -1 Then

    ' >>> begin new code 

    Select Case (ruleType)

        Case Config.RewriterRuleType.Permanent

            RewriterUtils.PermanentlyRedirectURL(app.Context, sendTo)

        Case Config.RewriterRuleType.Rewrite

            ' >>> begin old code 

            If rules(intMatch).SendTo.StartsWith("~") Then

                ' rewrite the URL for internal processing

                RewriterUtils.RewriteUrl(app.Context, sendTo)

            Else

                ' it is not possible to rewrite the domain portion of the URL so redirect to the new URL

                Response.Redirect(sendTo, True)

            End If

            ' >>> end old code 



        Case Config.RewriterRuleType.Temporary

            RewriterUtils.TemporarilyRedirectURL(app.Context, sendTo)

    End Select

    ' >>> end new code 

End If

...
 
Finally, we add these new actions to the RewriterUtils class :
 
Friend

 Shared Sub TemporarilyRedirectURL(ByVal context As HttpContext, ByVal sendToUrl As String)

    context.Response.Clear()

    context.Response.Status = "302 Found"

    context.Response.AddHeader("Location", sendToUrl)

    context.Response.End()

End Sub

 

Friend Shared Sub PermanentlyRedirectURL(ByVal context As HttpContext, ByVal sendToUrl As String)

    context.Response.Clear()

    context.Response.Status = "301 Moved Permanently"

    context.Response.AddHeader("Location", sendToUrl)

    context.Response.End()

End Sub
 
We can then compile the DNN source and replace the DotNetNuke.HttpModules.UrlRewrite.dll in our DNN installation with the newly compiled one.

Oh yes. You will be mine…

I have a birthday coming up so….happy birthday to me 🙂
Ibanez AW140QMECE (Vintage Violin Finish)
Top Solid Engelmann Spruce
Back & Sides Quilted Maple
Neck Mahogany
Pickup Fishman® Sonicore Pickup
Pre-Amp Fishman® Classic 4T Blend Preamp
Tuning Machines Gold Grover Tuning Machine
Nut & Saddles Ibanez Ivorex II
Bridge Pins Ibanez Advantage Bridge Pins
Rosette Abalone
Strings D’Addario EXP
Fretboard Rosewood

You can count on WCF

One of the many great things about WCF which you don’t often hear people talking about is that it comes fully instrumented out of the box. That’s right, the WCF runtime has full instrumentation baked right in, ready for you to use to performance profile and monitor your services and all you have to do to start using it is flick a switch in your service config and run performance monitor (perfmon.exe).
 
If you’ve been a serious windows user for any length of time you will almost certainly have come across perfmon. It is one of the essential tools for quick, easy system and application profiling and many applications (like SQL Server, MSMQ, the CLR, the WCF Runtime, ASP.NET etc) come with their own specific perfmon counters which let you peek under the hood when they are running. Perfmon lets you capture and display data generated by these counters, monitor customized thresholds and take actions when thresholds are breached. It is a massively useful tool.
 
WCF adds four sets of counters to the system. The first three are ServiceModelService, ServiceModelEndpoint and ServiceModelOperation. As you can probably guess from the names, these counters give you different levels of granularity when profiling so you can capture data at the service level, at the endpoint level and at the individual service method level. The final one is SMSvcHost. This is a set of instrumentation counters attached to the .NET TCP Port Sharing Service that lets different services listen on the same port and I will leave this set for another time.
The first three contain the counters listed below (or a subset thereof) :
 

  • Calls
  • Call Duration
  • Calls Failed
  • Calls Failed Per Second
  • Calls Faulted
  • Calls Faulted Per Second
  • Calls Outstanding
  • Instances
  • Instances Created Per Second
  • Queued Messages Dropped
  • Queued Messages Dropped Per Second
  • Queued Messages Rejected
  • Queued Messages Rejected Per Second
  • Queued Poison Messages
  • Queued Poison Messages Per Second
  • Reliable Messaging Messages Dropped
  • Reliable Messaging Messages Dropped Per Second
  • Reliable Messaging Sessions Faulted
  • Reliable Messaging Sessions Faulted Per Second
  • Security Calls Not Authorized
  • Security Calls Not Authorized Per Second
  • Security Validation and Authentication Failures
  • Security Validation and Authentication Failures Per Second
  • Transacted Operatoins Aborted
  • Transacted Operations Aborted Per Second
  • Transacted Operations Committed
  • Transacted Operations Committed Per Second
  • Transacted Operations In Doubt
  • Transacted Operations In Doubt Per Second
  • Transactions Flowed
  • Transactions Flowed Per Second

Now, I mentioned the flick of a switch in the service config to enable this feature which is off by default, so here it is :

 

<system.serviceModel>
    <diagnostics wmiProviderEnabled="false" performanceCounters="All" />
    <!--
      ... your other service config here...
    -->
</system.serviceModel>
 
That’s all that is required. As you can see, it is also possible to provide access to this instrumentation via WMI by switching the value of the wmiProviderEnabled attribute to true so you can write your own monitoring tools and scripts or use other 3rd party tools that use WMI.
 
As an example I have written a very simple service class :
 
using System;
using System.ServiceModel;
using System.Runtime.Serialization;

namespace WCFTestService
{

    [ServiceContract]
    public interface IMyService
    {

        [OperationContract]
        Foo GetFoo();

        [OperationContract]
        void SetFoo(Foo foo);

    }

    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
    public class MyService : IMyService
    {

        #region IMyService Members

        public Foo GetFoo()
        {
            System.Threading.Thread.Sleep(200);
            return new Foo("Hello");
        }

        public void SetFoo(Foo foo)
        {
            System.Threading.Thread.Sleep(200);
            Console.WriteLine("Bar = " + foo.Bar);
        }

        #endregion
    }

    [DataContract]
    public class Foo
    {

	public Foo(string bar)
	{
		this.Bar = bar;
	}

	private string _Bar = string.Empty;
	[DataMember]
         public string Bar
         {
            get
            {
                return this._Bar;
            }
            set
            {
                this._Bar = value;
            }
         }
    }
}
 
A simple host executable :
 
using System;
using System.ServiceModel;

namespace WCFTestHost
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost host = new ServiceHost(typeof(WCFTestService.MyService), new Uri("http://localhost:7001/MyService"));
            host.Open();
            Console.WriteLine("Service Running. Press any key to exit...");
            Console.ReadKey();
        }
    }
}

…and here is the config for the host executable :

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<system.serviceModel>
		<diagnostics wmiProviderEnabled="false" performanceCounters="All" />
		<behaviors>	
			<serviceBehaviors>
				<behavior name="MetadataExchange">
					<serviceMetadata httpGetEnabled="true" />
				</behavior>
			</serviceBehaviors>
		</behaviors>
		<services>
			<service behaviorConfiguration="MetadataExchange" 
				name="WCFTestService.MyService">
				<endpoint 
					address="net.tcp://localhost:7000/MyService" 
					binding="netTcpBinding" 
					contract="WCFTestService.IMyService" />
			</service>
		</services>
	</system.serviceModel>
</configuration>
Finally, here is a multi-threaded test consumer for the service:
 
using System;
using System.Collections.Generic;
using System.Threading;
using WCFTestClient.WCFTestService;

namespace WCFTestClient{

	class Program 
	{ 
		static void Main(string[] args) 
		{ 
			try 
			{ 
				WaitCallback fire = delegate(object proxy) { 
					Random r = new Random(System.Environment.TickCount); 
					int i = r.Next(1,3); 
					if (i==1) 
					{ 
						string s = ((MyServiceClient)proxy).GetFoo().Bar; 
						Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + " : " + s); 
					} 
					else 
					{ 
						((MyServiceClient)proxy).SetFoo(new Foo(){Bar = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString()}); 
					} 
					
					using (proxy as IDisposable) { } 
				};
					
				Action<MyServiceClient> queueUp = delegate(MyServiceClient proxy) 
				{ 
					ThreadPool.QueueUserWorkItem(fire, proxy); 
				};
				
				List<MyServiceClient> proxies = new List<MyServiceClient>(); 
				
				for (int i = 0; i < 100; i++) { 
					proxies.Add(new MyServiceClient()); 
				} 
				
				proxies.ForEach(queueUp); 
			} 
			catch(Exception ex) 
			{ 
				Console.WriteLine(ex.ToString()); 
			} 
			
			Console.ReadKey(); 
		} 
	}
}
 
So, here are the facts. The service is configured as a singleton. I have inserted a Thread.Sleep(200) into both methods to simulate more complex activity. The client is multi-threaded (via the thread pool) and will create 100 proxies which will randomly call one of the two service methods.
 
What is this likely to mean in performance terms ? Well, firstly services are inherently single threaded meaning that they will only process one call at a time. Therefore, if the call duration on our service is 200 miliseconds (give or take) then the best performance in terms of calls processed per second we can hope for is 5.
 
So let’s profile our service and see if we’re right. Here’s our output :
 
snap01
 
As you can see our 100 proxies made 100 service calls and our singleton made sure that there was only ever one instance processing those calls so instances created per second briefly hit 1.
 
Call duration averaged at .0201 seconds thanks to our Thread.Sleep(200) and as a result calls max per second was 5.009.
 
So what happens if we reduce our call duration to 100 milliseconds (Thread.Sleep(100)) ? What we should see is calls taking half as long and therefore being processed twice as fast.
 
snap02
 
The graph is pretty much identical except that max calls per second is now 10 and the 100 calls have been processed in half the time. As predicted.
 
You can continue this testing increasing the sleep latency up to somewhere between 800 and 900 milliseconds after which the client will throw an exception when it fails to connect with the service with in the default 1 second timeout. After that you either have to increase the timeouts on the consumer, increase the ListenBacklog or MaxConnections (which both default to 10) on the service, reduce the latency of the service, reduce the number of concurrent calls, abandon the singleton in favour of PerCall instance mode or set the ConcurrencyMode of the singleton to Multiple so that it can be accessed by multiple threads.
 
<gotchas>
1) If you want to monitor a specific service instance then the instance must be running when you go to add the counters to the graph.
2) When the service instance stops running the graph will freeze (i.e. stop capturing data) but will restart when you restart the service.
3) Setting up and configuring perfmon graphs can be time consuming so you can save them as counter logs, however you can also save a graph as html which will produce an html page with an embedded perfmon graph complete with all your counters and configurations. You can just open this page in your browser to start monitoring. This also means you can build and keep or publish a library of useful graphs.
</gotchas>

Am I ready to go contracting ?

I have been working as contract/freelance for some years now and I’ve worked in a lot of different places. I meet a lot of talented people who are “permies” and I quite often get asked variations on the question, “I am thinking of going contract, what do you think ?”. I’m normally quite happy to give people advice on things like this. I am certainly happy to go through the pros and cons, the ups and downs, the ins and outs of life as a contractor. I will regale people with anecdotes, epic tales of heroism and horror, triumph and tragedy, success and suckiness etc, but at the end of the day my answer to the question “Am I ready to go contracting ?” or “Should I go contracting ?” will always be “No”, and I will tell you why.
Becoming a contractor is, above all, a leap of faith. It requires tremendous self-confidence, chutzpah, front, balls whatever you want to call it. You have got to be 100% sure of yourself. Sure you can get the job, sure you can do it, sure you can keep it or find another one quick. You have to be able to go and do the work every day, run the risks and go home every night and get a good nights sleep. If you are the kind of person who will lose sleep over the uncertainty associated with contract employment, “don’t even go there, Girlfriend”. You may be able to do the job but you will be tired and miserable.
And that’s why I say “No”. The very fact that you are asking the question means you aren’t ready. You will be ready when you know you are ready. If you need anyone else other than yourself to convince you that you should go contracting then you shouldn’t. You have to make that decision on your own and carry the weight and responsibility of it on your own. If there’s anything worse than finding yourself in the sh*t, it’s finding yourself in it and thinking “If only I hadn’t listened to whatshisname!”
%d bloggers like this: