If you don't want to use a lot of money on service virtualization tools you can create a simple autogenerated WCF facade service that does a little bit of the things the big service virtualization tools does.

This gives you the option to hide service between one common service. The services behind this service could be a service from your backend system, a service from your CRM system and it might even be some external services.

You could do it manually, but then you would have to update it each time one of the backend services changes and with the human factor as an error source. Visual Studio gives you the option to use text templates which can be used to generate code.

Start by creating a WCF Service Application in Visual Studio and add a text template to this project, which will give you a *.tt file. This is the file that you will edit to create the autogenerated code. You might want to read a bit about it at MSDN before reading on. Here is the link.

Working with tt files is like going back in time. Back to the time with ASP and where you don't have intellisense. I stongly recommend to use Visual Studio 2012 that at least gives you a good debug option.

The first part of the tt file is the part where you specify which .Net namespace you want to use. The tt files knows nothing about the references that you have in your project, which I found out the hard way. My initial thoughts were to use reflection to get information about the services that I was going to work with, but I got into problems when I wanted to work with service references. So I ended up using the EnvDTE namespace, where you work with the FileCodeModel in Visual Studio. So this gives me this first part of the tt file:

<#@ template debug="true" hostspecific="true" #>
<#@ output extension="cs" #>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="System.Xml" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Collections.Generic" #>

I wanted to control which services got autogenerated in an XML file, so I at a *.mapping file to the solution where I created a structure with the name of the service I wanted.

Based on this I could load the FileCodeModel and find the CodeFunctions that needed to be exposed.

 <#   
    
 EnvDTE.DTE dte = GetEnvDTE();
 string myFile = this.Host.ResolvePath("AutoGeneratedFacade.Mapping");
 XmlDocument xdoc = new XmlDocument();
 xdoc.Load(myFile);
 foreach (XmlNode node in xdoc.SelectNodes(@"//class/name"))
 {
      string sourceFileName = node.InnerText;
      sourceFileName = @"Service References\" + sourceFileName + @"\Reference.cs";
      ProjectItem enumProjectItem = dte.Solution.FindProjectItem(sourceFileName);
      FileCodeModel codeModel = enumProjectItem.FileCodeModel;

      CodeNamespace codeNamespace = FindNamespace(codeModel.CodeElements);
      CodeInterface codeInterface = FindInterface(codeModel.CodeElements);
      List<CodeFunction> codeFunctions = FindMethods(codeInterface.Children);
 #>

In the above code there are a couple of utility functions:

<#+
    
    private CodeNamespace FindNamespace(CodeElements elements)
     {
         foreach (CodeElement element in elements)
         {
             CodeNamespace ns = element as CodeNamespace;
        
            if (ns != null)
                 return ns;
         }
    
        return null;
     }
    
    private CodeInterface FindInterface(CodeElements elements)
     {
         foreach (CodeElement element in elements)
         {
             CodeInterface codeInterface = element as CodeInterface;
        
            if (codeInterface != null)
                 return codeInterface;
    
            codeInterface = FindInterface(element.Children);
    
            if (codeInterface != null)
                 return codeInterface;
         }
    
        return null;
     }
    
    private List<CodeFunction> FindMethods(CodeElements elements)
     {
         List<CodeFunction> methods = new List<CodeFunction>();
        
        foreach (CodeElement element in elements)
         {
             CodeFunction method = element as CodeFunction;
        
            if (method != null)
                 methods.Add(method);           
        }
    
        return methods;
     }
    
    private EnvDTE.DTE GetEnvDTE()
     {
         IServiceProvider hostServiceProvider = (IServiceProvider)Host;
        
        if (hostServiceProvider == null)
                throw new Exception("Host property returned unexpected value (null)");
        
        EnvDTE.DTE dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
        
        if (dte == null)
                throw new Exception("Unable to retrieve EnvDTE.DTE");
    
        return dte;
     }
 #>

With the CodeFunctions in hand I am now able to create the new interface and class implementation for the autogenerated WCF facade service:

<#+
private void WriteInterface(CodeFunction method)
{
    foreach(CodeElement element in method.Attributes)
    {
         string at = "";
         CodeAttribute att = element as CodeAttribute;
        
         if (att != null)
         {
              at = at + "[";
              at = at + att.Name;
              at = at + "(";
              at = at + att.Value;
              at = at + ")]";
              WriteLine(at);
         }
    }
        
    Write(method.Type.AsString);
    Write(" ");
    Write(method.Name);
    Write("(");
    string sparameter = "";        
    foreach(CodeElement element in method.Parameters)
    {
        int count = 0;           
        CodeParameter parameter = element as CodeParameter;
        
        if (parameter != null)
        {
            sparameter =sparameter + parameter.Type.AsString + " ";
            sparameter = sparameter + parameter.Name;
                
            if(count < method.Parameters.Count)
                sparameter = sparameter + ", ";
                
            count++;
        }
    }
    sparameter = sparameter.Substring(0,sparameter.Length -2);
    Write(sparameter);
    Write(");");
}
#>

And with the interface I am able to create the class the implements the interface:

<#+
private void WriteServiceClass(CodeFunction method, string servicename)
{
     Write("public ");
     Write(method.Type.AsString);
     Write(" ");
     Write(method.Name);
     Write("(");
     string sparameter = "";
     string sparameternames = "";        
     foreach(CodeElement element in method.Parameters)
     {
         int count = 0;           
         CodeParameter parameter = element as CodeParameter;
        
         if (parameter != null)
         {
             sparameter =sparameter + parameter.Type.AsString + " ";
             sparameter = sparameter + parameter.Name;
             sparameternames = sparameternames + parameter.Name;
             if(count < method.Parameters.Count)
             {
                 sparameter = sparameter + ", ";
                 sparameternames = sparameternames + ", ";
              }  
              count++;
         }
     }
     sparameter = sparameter.Substring(0,sparameter.Length -2);
     Write(sparameter);
     Write(")");
     WriteLine(String.Empty);
     WriteLine("{");
     PushIndent("        ");
     Write("FacadeService.");
     Write(servicename);
     Write(".");
     Write(servicename);
     Write("Client service = new FacadeService.");
     Write(servicename);
     Write(".");
     Write(servicename);
     Write("Client();");
     WriteLine(String.Empty);
     Write("return service.");
     Write(method.Name);
     sparameternames = sparameternames.Substring(0,sparameternames.Length -2);
     Write("(");
     Write(sparameternames);
     Write(");");
     WriteLine(String.Empty);
     ClearIndent();
     PushIndent("        ");
    WriteLine("}")  
}
#>

The final piece is to change the SVC file to point to the autogenerated class with changes to the Service and Codebehind attributes.

I used this article as inspiration and borrowed some lines of code from it.

With this I just have to update the service proxy and save the tt file to update my facade service and I don't have to write copy paste code.

Random posts:
Help me, help you. You know how ;-) (click, click, click...)