WCF

Write a WCF Test App to Connect to Multiple URLs

Posted on

Scenario: you have deployed your WCF web service to multiple servers, including

  • Localhost
  • Dev server
  • Integration Server
  • Training server
  • etc.

It would be nice to connect and test to each server with the exact same code! Who wants to write a different app just to connect to a different server with the exact same service.

Screen shot showing a single app connecting to a different server, chosen from the combo box
Screen shot showing a single app connecting to a different server, chosen from the combo box

In the sample above, I get all the available URLs from my config file (in the section “system.serviceModel/Client”). This is convenient if you have established service references in the normal manner. However, it it not necessary to do this.

Part One: Establish a WCF Client/Proxy using a URL Provided at Run Time

We will take advantage of the constructor signature that accepts a URL and a contract. Obviously, the URL will vary according to which server we connect to! If all the servers use the same WSDL, we can use a single contract name; in this case, I use the one from my config file.

public static localInventorySvc.InventorySvcClient BuildClient(string serviceUrl) {
    localInventorySvc.InventorySvcClient result;

    //This is a binding from my config file; it is also possible to
    //construct one in code (but I don't need to)
    string contractName = "BasicHttpBinding_IInventorySvc";

    //The new client/proxy will connect to the URL provided to us:
    result = new localInventorySvc.InventorySvcClient(contractName, serviceUrl);
    return result;
}

At this point, we can just use our client like one we constructed any other way, such as this:

localInventorySvc.InventorySvcClient myClient = BuildClient(cboUrls.Text);
localInventorySvc.GetInventoryDataRequest myRequest = new localInventorySvc.GetInventoryDataRequest();
myClient.getInventoryData(myRequest);

I have simplified the code – I skipped providing the parameters for my request object, but that is rather trivial.

Part Two (Optional) Get URLs from your Config File

Every time you create a new service reference, your config file holds the details, including the URL. This is rather convenient. The only issue is figuring-out the proper syntax to access that data. If you include a using statement for “System.ServiceModel” in your code, you can retrieve a ClientSection object using the configuration manager.

private void Window_Loaded(object sender, RoutedEventArgs e) {
    //Iterate the endoints from the config file and add them to the combo box:
    List<string> allUris = new List<string>();
    ClientSection clientSection;
    //This is the tricky part:
    clientSection = (ClientSection) ConfigurationManager
                    .GetSection("system.serviceModel/client");
    if (clientSection != null) {
        foreach (ChannelEndpointElement ep in clientSection.Endpoints) {
            allUris.Add(((ChannelEndpointElement)ep).Address.AbsoluteUri);
        }
    }
    //Now that we have all the urls, display them in the combo box:
    cboUrls.ItemsSource = allUris;
    if (allUris.Count > 0)
        cboUrls.SelectedIndex = 0;
}

Config File

Here, you can see the two URLs which appear in my combo box; obviously you can add more when you add service references.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
          <wsHttpBinding>
            <binding name="BasicHttpBinding_IInventorySvc" />
            <binding name="BasicHttpBinding_IInventorySvc1" />
          </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:49830/InventorySvc.svc" 
                  binding="wsHttpBinding"
                  bindingConfiguration="BasicHttpBinding_IInventorySvc" 
                  contract="localInventorySvc.IInventorySvc"
                  name="wsHttpBinding_IInventorySvc" />
            <endpoint address="http://localhost/UniversalMessageProcessor/InventorySvc.svc"
                binding="wsHttpBinding" 
                bindingConfiguration="BasicHttpBinding_IInventorySvc1"
                contract="deployedInventorySvc.IInventorySvc" 
                name="wsHttpBinding_IInventorySvc1" />
        </client>
    </system.serviceModel>
</configuration>

 Download the code! Remember, you won’t have the same service references, so you will need to tweak the project to run it.

Simplify Repeated Code with Delegates and Generic Methods

Posted on Updated on

Scenario: Repeated Code in All my Web Methods

  • I’m writing a bunch of WCF web methods
  • They all have chunks of nearly identical code
    • (For example: code for logging, authentication, validation, error handling, etc.)
  • But each method has a certain number of lines of code that are unique
  • The upshot is that every time I add a new web method, I add a huge amount of code that is the same as before
  • And every time we change our general procedure (i.e different logging, different validation, etc.), I need to modify that repeated code, a task that is error prone and boring

What You will Learn

If you read this post, you will see a practical sample of how to:

  • Use delegates to execute code that is unique for each of your individual web service methods
  • Use a generic method to handle process all your web methods, using any request or response data types
  • Use interfaces to add power to you generic methods!

See below for a simplified description of these powerful techniques. The code sample download link is at the end.

Important Principal: Do Not Repeat Yourself!

I have a deadline, and I would like to meet it by avoiding repeated code. I’ll bet you also have a deadline, and maybe you would like to keep your job by meeting that deadline!

Also, my client deserves easy-to-maintain code, so I will write my code to give them the power to easily make changes in one place and have it affect all my web methods. Testing is also easier when you avoid repeating yourself, because you have fewer lines to test.

What I’m talking about is the “best practice” called “DRY”, or Do not Repeat Yourself. In my experience, sophisticated/productive programmers all use DRY, whereas most corporate drones have no frigging clue. Which is why most of their code sucks, IMHO!

The “UniversalMessageProcessor” I describe in this post will show you how to avoid repeating yourself by using delegates, generic methods, and a few other things, thus helping you meet your deadline and give your clients the easy-to-maintain code they deserve.

Sample Code – Shows the Essence of my Repeated Code

Read my simplified sample immediately below to get an idea of the repeated code that I wish to improve a la DRY:

public ResponseType1 GetData1(RequestType1 request){
	try {
		//Simplified representation of the repeated authentication code
		//(Use your imagination to envision longer code)
		CheckAuthentication(request.Credentials);
                //Also repeated in every web method, yada yada yada
		ValidateRequest(request);
                //Another chunk of repeated code that is actually more like 15 lines:
		LogRequest(request);
		//Simplified representation of the lengthy code to copy the result from BLL into 
		//the response we send to service partner, again, imagine 30 lines instead of 2)
                bllResult = Bll.GetReponseType1(request);
		ReponseType1 myResponse = CopyBllResultToResponse(bllResult);
		LogResponse(myResponse);
		return myResponse
	} catch (Exception ex) {
		LogError(ex, request);
	}
}

In other words, I have a bunch of web methods that follow the simplified pattern above, except they use ‘ResponseType2’, ‘ResponseType3’, etc. Only the portion in yellow is unique to each web method; otherwise they are (mostly) similar. I would like to avoid all this repeated code! But first, let’s make sure we understand a couple of techniques I will use, delegates and generic methods:

Nutshell Definitions for ‘Delegate’ and ‘Generic Method’

Delegates: a Variable to Hold Your Code

In a nutshell, a delegate (sometimes called a function pointer) is how you represent your code as a variable (i.e. as a First Class Object) which you can pass to other methods. Like this (over simplified) sample:

Func<int, string> GetSign = (i) => {
	if (i < 0)
		return "-";
	else if (i > 0)
		return ("+");
	else
		return "";
};

//Usage:
string s1 = GetSign(5);
Console.WriteLine(s1);
//Output will be "+"

GetSign‘ is a delegate, and I can pass it to another method, because it is a variable. You may also see folks declare delegates using the ‘Action‘ keyword, instead of the ‘Func‘ keyword I used above.

For another example of passing delegates as parameters, take a look at how I used them to solve a puzzle: https://actualrandy.wordpress.com/2014/09/18/calculator-letters-puzzle-solved/

Generic Methods – Work on Any Data Type!

In another nutshell, a generic method is a method which does the same work regardless of parameter type. Here’s a quick sample from the MSDN site:

static void Swap<T>(ref T lhs, ref T rhs)
{
    T temp;
    temp = lhs;
    lhs = rhs;
    rhs = temp;
}
//Usage:
string s1 = "A", s2 = "B";
Swap<string>(s1, s2);
int i1 = 1, i2 = 2;
Swap<int>(i1, i2);

In this sample, ‘T‘ could be int, string, DateTime, or any other data type you need!

Enough Background, Here’s the Code!

The code for this post is available for download at the bottom of the article. I will discuss the important portions here. The download code has two web methods (but my production code has a lot more, I simplified my sample for your sake). Let’s look at my first web method, which returns a list of locations associated with the caller’s service center:

public GetLocationServiceCenterResponse GetLocationByServiceCenter(GetLocationServiceCenterRequest request) {
    //The delegate performs the work which only applies to this 
    //web method; the common work is performed by ProcessMessage
    Func<IRequestWithCredential, IReturnMessageResponse, BllResult> getBllResult = (req, response) => {
        //cast to the type we need:
        GetLocationServiceCenterRequest getLocRequest = (GetLocationServiceCenterRequest)req;

        //Invoke the Business-Logic-Layer method that does the database work:
        BllResult theBllResult = BllMain.GetLocationServiceCenter(getLocRequest);

        //Here we will copy the result from the ReturnTable into the response
        //Note that the ReturnTable is a weakly-typed DataTable that varies according to the method
        GetLocationServiceCenterResponse getLocResponse = (GetLocationServiceCenterResponse)response;
        getLocResponse.Locations = new List<LocationInfo>();
        if (theBllResult.ReturnCode == BllConstants.SUCCESS) {
            //Copy the weakly-typed data from the BllResult into our response:
            foreach (DataRow dr in theBllResult.ReturnTable.Rows) {
                LocationInfo curLoc = new LocationInfo();
                curLoc.Location = (string)dr["LocationID"];
                curLoc.Description = (string)dr["Description"];
                curLoc.LocationType = (string)dr["LocationType"];
                getLocResponse.Locations.Add(curLoc);
            }
        }

        return theBllResult;
    };
    //End of delegate body

    //Now, do all the work, using the delegate we built above:
    GetLocationServiceCenterResponse result = ProcessMessage<GetLocationServiceCenterRequest, GetLocationServiceCenterResponse>
                        (request, "getLocationServiceCenter", getBllResult);
    return result;
}

As you can see above, the main thing I do is declare my delegate, ‘getBllResult’, and then pass it to a medhod called ‘ProcessMessage’. The delegate begins in the highlighted code. Just to refresh your memory, this delegate handles the work that is unique to finding locations by service center.

Also, take a look at how I invoke ‘ProcessMessage’ – I tell it the input and output types (GetLocationServiceCenterRequest, GetLocationServiceCenterResponse) in between the angle brackets:

result = ProcessMessage<GetLocationServiceCenterRequest, GetLocationServiceCenterResponse> ...

If you download my code, you will see that I do almost the exact same thing with my second web method. The only difference is that my second method declares the delegate to handle different types of data. This means that all the web methods are greatly shortened, because all they do is define a delegate and call ProcessMessage!

Now Look at My ‘Universal’ ProcessMessage Method

The following is a simplified sample – I cut-out approximately 50 lines of logging/authentication, etc., just so you can read it easier!

public TResult ProcessMessage<TRequest, TResult>
1		(TRequest request, 
2		 string methodName, 
3		 Func<IRequestWithCredential, IReturnMessageResponse, BllResult> getBllResult
		)
4	where TResult : IReturnMessageResponse, new()
5	where TRequest : IRequestWithCredential 
{
6   TResult result = new TResult();
    _Logger.Log(LogLevel.Info, methodName + " started...");
    result.ReturnMessage.ReturnMessageDetails = new List<ReturnMessageDetail>();
    try {
        if (AuthenticateApp(request.credential)) {
            _Logger.Log(LogLevel.Info, methodName + " validating request");
            List<ValidationResult> lstValidationResults = new List<ValidationResult>();
            //The GeneralValidator uses reflection to validate any class and its child members
7           if (_Validator.ValidateComplexObject<TRequest>(request, lstValidationResults)) {
                //Execute the function passed to us
8               BllResult bllResult = getBllResult(request, result);

                if (bllResult != null && bllResult.ReturnCode == BllConstants.FAIL) {
                    result.ReturnMessage.ReturnCode = BllConstants.FAIL;
                    result.ReturnMessage.ReturnText = ERR_MESSAGE;
                } else if (bllResult != null) {
                    //We got the result we wanted, set the appropriate values in our result
                    result.ReturnMessage.ReturnCode = bllResult.ReturnCode;
                    result.ReturnMessage.ReturnText = bllResult.ErrorMessage;
                }
            } else {
                //Validation failed
                CopyValidationResultsToResponse(result, lstValidationResults);
                }
            }
        } else {
            //Invalid authentication
            result.ReturnMessage = new ReturnMessage{ ReturnCode = BllConstants.FAIL, 
                  ReturnText = "Your credentials suck --> no data for you, ya filthy hacker!"};
        }
    } catch (Exception ex) {
        while (ex != null) {
            result.ReturnMessage = new ReturnMessage{ ReturnText =  ex.Message };
            _Logger.Log(LogLevel.Error, ex.Message);
            ex = ex.InnerException;
        }
    }
9    return result;
}

 Explanation!

I injected some line numbers into my sample above, and they are linked to the numbered bullet points below:

  1. TRequest request – My method takes a generic input type ‘TRequest’, which could be, for example, ‘GetServiceCenterRequest’
  2. string methodName – The method uses your method name for logging
  3. Func<…, …, …> getBllResult – Third parameter is my delegate, which I will execute on line 8 (highlighted). Remember, the delegate is the code which is unique to each web method. Also remember, the point of using a delegate is that I can pass delegates like parameters!
  4. where TResult : IReturnMessageResponse, new() Generic methods allow you to use the ‘Where’ clause to restrict what types of data they will process. In this case, I require that the result/ouput type (‘TResult’) implement a simple interface called ‘IReturnMessageResponse’. That allows me to write code like this: ‘result.ReturnMessage = new ReturnMessage’, because the interface declares that every implementor has such an object. (Sample code below.)
    • new()” here, my ‘where-clause’ also requires that TRequest expose a constructor, which allows me to write the code on line 6
  5. where TRequest : IRequestWithCredential – Here, I require that the input paramter (‘TRequest’) implement a different interface, ‘IRequestWithCredential’. In a nutshell, every class that implements this interface has a Credential object.
  6. TResult result = new TResult() – because of my where-clause on line 4, the compiler knows my input parameter has a constructor it can call! Also, the class of my result is TResult, which can be any class, (subject to my where clause)
  7. ValidateComplexObject – Refer to my previous post on writing a universal validator using DataAnnotations and Reflection.
  8. BllResult bllResult = getBllResult(request, result) – here is where I invoke the delegate!. This is the whole point of my post, i.e. use the delegate inside a generic method to perform work that is unique to each web method. Note that my teammates wrote the BLL (Business Logic Layer) to always return a class called bllResult, each result has a table with different data).
  9. return result; – Since I declared this method to return TResult, my generic method will return whatever class type you need, such as a response object for GetLocationsByServiceCenter.

My Two Interfaces

OK, I promised above that I would list my interfaces, as you can see, they are really simple. Just to refresh your memory,

  • All my request classes implement IRequestWithCredential
  • And all my response classes implement IReturnMessageResponse
  • By doing so, the compiler is not confused when I execute code like ‘request.Credential = null’, or similar actions
  • I.e., any time I refer to something defined the the interface, the compiler is happy!
//First interface:
public interface IReturnMessageResponse
{
    ReturnMessage ReturnMessage { get; set; }
}

//Second interface
public interface IRequestWithCredential
{
    Credential credential { get; set; }
}

 Summary

  1. When you write your code, you should avoid repeating yourself, because it will help you meet your deadline and shrink your code.
  2. If you are writing a web interface, you can find lots of repeated code to optimize, depending on how much logging, authentication, validation, etc. you are required to do. (But the same principle applies to other code!)
  3. You can create a generic method that will work for any of your response classes and request classes, that is step one to saving a ton of code!
  4. Your generic method can accept a delegate input parameter; you method will execute that method to handle code that is unique to each web method.
  5. You can constrain your generic method using the ‘where-clause’; one use is that it tells the compiler that your types implement an interface

By applying these techniques, you should be able to reduce your web method code by 20%-50%, depending on how much repeated code you have. That’s a big savings, and should really speed things up.

Link download to the Code

Save Time With My Universal Validator

Posted on Updated on

Extend DataAnnotations to Handle Complex Objects

It is super easy and convenient to perform validation using the .NET DataAnnotations namespace. It allows you to describe validation using tags (attributes) on your classes. You can then ask .NET to validate an instance of your class. You will find it very easy to validate your simple classes with no “children”, using the built-in capabilities. In this article, I will show you how to handle more complex classes.

UniversalValidator
Unlike the built-in Validator, my UniversalValidator will look at nested classes, such as the items in the LineItems list displayed here. Note that the results textbox shows the list of Validation I returned from validation.

Situations Handled by my Universal Validator

For example, my validator will handle a PurchaseOrder class with a List of LineItems, or a list of suppliers, or containing two instances of an address class (for billing and shipping). The list of LineItems, Address instances, or list of suppliers are what I mean when I refer to ‘nested’ classes, i.e. child classes. Without my Universal Validator, you would need to add a bunch of custom code for every child class.

How You Will Benefit

Here’s a couple scenarios: you will find this useful when validating input in your web service, or when implementing an SOA (Service-Oriented Architecture). In that case, you will wish to validate the data sent to you by your e-commerce partners, or by folks in your organization invoking your web methods. When you use my UniversalValidator (or your own version), you can save time and meet your deadlines! Plus, you get the undying satisfaction of telling your e-commerce partners that they screwed-up!

But first, let’s get some background on the built-in validation in the DataAnnotations namesapce.

Sample Class with Validation Attributes

using System.ComponentModel.DataAnnotations;
    public class Customer{
        [Required]
        [MaxLength(50)]
        public string Name { get; set; }

        [Required]
        [CreditCard]
        public string CreditCard{ get; set; }

        [Phone]
        public string Phone{ get; set; }

        [Required]
        [EmailAddress]
        public string Email{ get; set; }
    }

You can easily validate an instance of this class like this:

Customer sally = new Customer {
	Name = "Sally", 
        CreditCard = "378282246310005", 
        Phone = "(208) 555-1212",
	Email = "Sally@Example.com"
};
List<ValidationResult> lstResults = new List<ValidationResult>();
ValidationContext myContext = new ValidationContext(sally);
bool isValid = Validator.TryValidateObject(sally, myContext, lstResults);

If any property is invalid, the Validator will return false, and lstResults will receive a list of information which you can thento give to your partners for feedback. For example, if you put letters into Sally’s phone number, you will receive the message “The PhoneNumber field is not a valid phone number.”

The nice part of this scheme is that it is really easy to see what the validation rules are; you just look at the class definition; the tags are obvious. There are a number of additional tags, including a Range tag and a Regular Expression tag. The range (double) is for numbers and allows you to specify min/max for any number; the regular expression tag allows you to enforce string patterns of your choice. You can also create your own custom validation tags, but you would rarely need that.

Problem: Nested Classes Are Not Validated!

The problem with this built-in validation is: it only looks at the top-level objects of the class being validated. For example, it won’t look at a list of line items and enforce your validation rules on them. Fortunately, my Universal Validator is designed for this scenario.

Use Reflection to Enhance Validation

Using reflection, you can get a list of properties for any class. If any of those properties are other classes, or a list of other classes, you can then take appropriate steps to validate them too! This gets around the problem of basic validation, because now you can detect the items which would not ordinarily be validated. The best technique to use is recursion, i.e. call my method ValidateComplexObject on a child class instance, from within ValidateComplexObject. This allows you to handle an unlimited number of grand-children classes/ great-grand-children, etc.

Here’s the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System.Collections;

namespace UniversalValidator
{
  /// <summary>
  /// Uses DataAnnotations to validate class instances
  /// </summary>
  public class GeneralValidator {
    private Type _EnumerableType;
    private Type[] _NonPrimitiveDontValidate;
    private Type _OurType;
    //We will use the 'Invoke' method on this MethodInfo
    //After converting it to a Generic method
    private MethodInfo validateComplexMi;

    /// <summary>Constructor</summary>
    public GeneralValidator() {
      //We will avoid recursive validation on these types
      _NonPrimitiveDontValidate = new[] { typeof(string), 
            typeof(DateTime), 
            typeof(Guid), 
            typeof(decimal), 
            typeof(Type) };
      _OurType = typeof(GeneralValidator);
      _EnumerableType = typeof(IEnumerable);
      validateComplexMi = _OurType.GetMethod("ValidateComplexObject");
    }

    /// <summary>
    /// Uses the validation system to evaluate complex types passed in
    /// Note that this is a 'generic' method
    /// so that parameter 'validateMe' is strongly-typed
    /// </summary>
    /// <typeparam name="T">Generic type</typeparam>
    /// <param name="validateMe">An object to validate</param>
    /// <param name="lstValidationResult">List of results</param>
    /// <returns>True if all itemse a valid, false otherwise</returns>
    public bool ValidateComplexObject<T>(T validateMe, List<ValidationResult> lstValidationResult) {
      bool result = false;

      if (validateMe == null) {
        return true;
      }
      ValidationContext validationContext = new ValidationContext(validateMe);
      //Do the basic validation on top-level members here:
      result = Validator.TryValidateObject(validateMe, 
        validationContext, lstValidationResult, true);

      Type typeToValidate = typeof(T);
      //Reflection will give us every property in the class
      PropertyInfo[] allProperties = typeToValidate.GetProperties(BindingFlags.Instance 
                      | BindingFlags.Public | BindingFlags.DeclaredOnly);

      foreach (PropertyInfo pi in allProperties) {
        //Only validate 'nested' class members
        if (!pi.PropertyType.IsPrimitive 
          && !_NonPrimitiveDontValidate.Contains(pi.PropertyType)) {
          
          //Check if we have a list, array, etc:
          if (TypeImplementsIEnumerable(pi.PropertyType)) {
            IEnumerable theList = (IEnumerable) pi.GetValue(validateMe);
            List<ValidationResult> childElementResults = new List<ValidationResult>();
            if (theList != null)
              //Validtae each entry in the list/array/etc.
              foreach (var elt in (pi.GetValue(validateMe) as IEnumerable)) {
                //Whatever type the element is, we make a MethodInfo
                //to match that type, then invoke it
                MethodInfo genericMi = validateComplexMi
                        .MakeGenericMethod(new Type[] { elt.GetType() });
                bool curResult = (bool)genericMi
                    .Invoke(this, new object[] { elt, childElementResults});
                if (!curResult) {
                  foreach (ValidationResult res in childElementResults) {
                    //Make the message easier to understand by adding information about its parent
                    res.ErrorMessage += " (" + pi.Name + ")";
                    lstValidationResult.Add(res);
                  }
                }
                result &= curResult;
              }
          } else {
            //Not a list, so recurse
            MethodInfo genericMi = validateComplexMi
                .MakeGenericMethod(new Type[] { pi.PropertyType }); 
            result &= (bool)genericMi
              .Invoke(this, new object[] { pi.GetValue(validateMe), lstValidationResult });
          }
        }
      }
      return result;
    }

    /// <summary>
    /// Detects whether the parameter is a list or array, etc.
    /// </summary>
    /// <param name="typeToCheck">A type that might be Enumerable</param>
    /// <returns>True if the type implements IEnumerable, false otherwise</returns>
    public bool TypeImplementsIEnumerable(Type typeToCheck) {
      //If the type implements IEnumerable, return true
      //This will include arrays, lists, dictionaries, etc
      return typeToCheck.GetInterfaces().Any(t => t == _EnumerableType);
    }
  }
}

 Key Points

  • GetProperties gives us all the properties, such as Customer Name/CreditCard/Phone and LineItems
  • We have already validated the Name, CreditCard and Phone (
  • We avoid validating these because they type, ‘string’, is contained in our array ‘_NonPrimitiveDontValidate’
  • But when we get to LineItems, its type is not in our array, and it is not a primitive type
  • Next, we detect that LineItems implements ‘IEnumerable’, so we will loop through its members and recursively validate each individual LineItem
  • We get the child list by invoking ‘pi.GetValue’, which is a way to get the value of any class member using a PropertyInfo object, in our case, ‘pi’.
  • The one weak point is: we don’t want to validate ‘built-in classes’ like DateTime/Guid, etc., and I may not have anticipated all those classes. If you have such a piece of date, an instance of a built-in class, please add its type to my array ‘_NonPrimitiveDontValidate’.

Download the code here!

Generate Your WCF Files From Your Spreadsheet

Posted on

Meet your Deadlines with T4 Template Files

Here’s my situation: we’re building an SOA and spending a long time on our design process. We need to revise our methods and parameters repeatedly, and we’re building a lot of methods and classes. We also need to build some documentation (a specification file). We have a tight deadline, so, after we finally finish modifying all those method signatures, we need to quickly build an interface for our B2B partners. It would be really nice if I could build, or rebuild, all those classes from a master definition file!

Solution

  1. Enter all the method definitions in an Excel file
  2. Also enter the data classes and their parameters in the same Excel file
  3. After all the revisions and negotiations, use the data in the Excel file to generate the code files using T4 templates
  4. Also generate the spec file using the same process

Remarks

I built a project using T4 templates to generate my code files. Note that the data contract files for WCF are mostly boiler plate, but it is still a lot of work. I can use the results to build WSDL in a few seconds. The benefits is that our B2B partners can code against that WSDL immediately, and I can update it easily.

I’m quite happy with the results. Running the app is easy, and there are no issues like improper casing for names or inconsistent spellings. Plus, when we make changes, the spec file can be immediately regenerated and be completely consistent with the code. Furthermore, it easy to write the my code generator; actually I built a working prototype one afternoon.

ScreenShot
Screen shot showing the inputs to generate the classes. The namesapces and other textboxes are auto-suggested from reading the master definition file.
All these classes were created in a split second when I clicked the button. They define the guts of a WCF web service.
I generated all these classes in a split second by clicking the button. They define the guts of a WCF web service. As mentioned above, the data classes are mostly boiler plate, the service contract (interface 100% usable straight from auto-generation)  and we can customize the service file as necessary.

,

How it Works

You can add a T4 Template file to any .NET project. T4 templates are designed for generating code from sources like a master definition file, database file, etc. T4 templates are a mixture of text (payload) and markup (your code that injects varying content). Here’s a sample for my auto-generation project:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".txt" #>
<#@ import namespace="AutogenerateWCF.SupportingClasses" #>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace <#= NamesapceToUse #>
{
    public class <#= ServiceClassName #> : <#= InterfaceName #>
    {
<# foreach(MethodInfo mi in Methods) { #>
	<#= mi.ReturnType #> <#= mi.Name #>(<#= mi.FormattedParameterList #>){
		return new NotImplementedException();
	}

<# } #>
	}
}

In the sample above, all my markup is in between the tags <# and #>. The markup references class properties on my T4 class. I wrote my T4 class to expose properties called “NamespaceToUse”, “ServiceClassName” and “Methods”. When I use my template (explained in depth below), it generates output that looks like the following:

using System.Runtime.Serialization;
using System.ServiceModel;

namespace B2BWebServcies
{
    public class B2BHPServices : IB2BWebServcies
    {
		GetLocationResponse getLocationServiceCenter(Credential credential, GetLocationServiceCenterRequest request){
			return new NotImplementedException();
		}

		GetInventoryDataResponse getInventoryData(Credential credential, GetInventoryDataRequest Request){
			return new NotImplementedException();
		}
	}
}

 Adding a T4 Template to Your Project

Add a new item to your project; for the type, choose ‘Text Template’:

How to Add a T4 Template to your Porject
How to Add a T4 Template to your Porject


After you add your Template file, change its Custom Tool to ‘TextTemplatingFilePreprocessor’

Select your new T4 file and change its custom tool to 'TextTemplatingFilePreprocessor'
Select your new T4 file and change its custom tool to ‘TextTemplatingFilePreprocessor’

Now, add a partial class with the same class name as your template file. The partial class will hold the properties you will utilize in your markup, such as ‘NamespaceToUse’. Next, populate your markup, injecting class properties where necessary.

To use your template,

  1. Set the class properties using whatever data source you need; in my case, I loaded from my master definition file (exported from Excel)
  2. Invoke your template class’s TransformText method – this returns a string containing your final output!

To learn more, download my sample code here.