Custom TraceListener writing trace messages to the .NET Services Service Bus
Next generation of a success story: WSCF.blue for WCF goes Beta 1

Generating async WCF OperationContract signatures with a T4 template


From time to time it happens that people want to use the async programming model in WCF based on the IAsyncResult approach - either on the client or the service side. Writing all the asynchronous operation contract signatures is quite a tedious and error-prone task. Given this fact, design-time code generation with a T4 template may come in very handy for this purpose.
The following is my first try to create such a T4 template and it seems to work for the scenarios I need it for. Please refer to code below to see how to use the template: it is easy and straight-forward.

<#
/*
   Copyright (c) 2009, thinktecture (http://www.thinktecture.com).
   All rights reserved.

   Permission is hereby granted to use this software, for both commercial
   and non-commercial purposes, without limitations and free of charge.
   Permission is hereby granted to copy and distribute the software for
   non-commercial purposes. A commercial distribution is NOT allowed without
   prior written permission of the authors.

   This software is supplied "AS IS". The authors disclaim all warranties,
   expressed or implied, including, without limitation, the warranties of
   merchantability and of fitness for any purpose. The authors assume no
   liability for direct, indirect, incidental, special, exemplary, or
   consequential damages, which may result from the use of this software,
   even if advised of the possibility of such damage.
*/
#>
<#@ template debug="true" hostspecific="true" #>
<#@ output extension="cs" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Collections.Generic" #>
<#   
    // USAGE:
    // 1. Drop this file into your VS project
    // 2. Rename this file to match this pattern: {YOUR_SERVICECONTRACT_FILE}Async.tt
    // 3. The async version of your original service contract gets generated as
    //    {YOUR_SERVICECONTRACT_FILE}Async.cs
   
    EnvDTE.DTE dte = GetEnvDTE();

    string sourceFileName = dte.Solution.FindProjectItem(Host.TemplateFile).Name;
    sourceFileName = sourceFileName.Replace("Async.tt", ".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);
       
    //System.Diagnostics.Debugger.Break();
#>
using System;
using System.ServiceModel;

namespace <#= codeNamespace.Name #>
{
    [ServiceContract]
    public interface <#= codeInterface.Name #>Channel :
        <#= codeInterface.Name#>
    {                   
        <#
            PushIndent("        ");
           
            int methodCount = 0;
           
            foreach (CodeFunction method in codeFunctions)
            {
                if(methodCount > 0)
                {
                    WriteLine(String.Empty);
                    WriteLine(String.Empty);
                }
               
                WriteAsyncOperationContract(method);
                WriteLine(string.Empty);
               
                methodCount ++;
            }
           
            ClearIndent();
        #>
    }
}

<#+
    private void WriteAsyncOperationContract(CodeFunction method)
    {
        string operationContractValue = TryGetOperationContractValue(method);
       
        WriteLine("[OperationContract(");
       
        if(String.IsNullOrEmpty(operationContractValue))
        {           
            Write("    Action = \"");
            Write(method.Name + "\",");
            WriteLine(String.Empty);
            Write("    ReplyAction = \"");
            Write(method.Name + "Reply\",");
            WriteLine(String.Empty);
        }
        else
        {
            ClearIndent();
            WriteLine("            " + operationContractValue + ",");
            PushIndent("        ");
        }
       
        WriteLine("    AsyncPattern = true)]");
       
        Write("IAsyncResult Begin");
        Write(method.Name);
        Write("(");
               
        foreach(CodeElement element in method.Parameters)
        {
            int count = 0;           
            CodeParameter parameter = element as CodeParameter;
       
            if (parameter != null)
            {
                Write(parameter.Type.AsString + " ");
                Write(parameter.Name);
               
                if(count < method.Parameters.Count)
                    Write(", ");
               
                count++;
            }
        }
       
        Write("AsyncCallback callback, object asyncState);");
       
        WriteLine(String.Empty);
        WriteLine(String.Empty);
       
        Write(method.Type.AsString + " ");
        Write("End");
        Write(method.Name);
        Write("(IAsyncResult result);");       
    }
   
    private string TryGetOperationContractValue(CodeFunction method)
    {
        string attributeValue = String.Empty;
       
        foreach(CodeElement attributeElement in method.Attributes)
        {
            CodeAttribute attribute = attributeElement as CodeAttribute;
           
            if(attribute != null)
            {       
                if(attribute.Name == "OperationContract" || attribute.Name == "OperationContractAttribute")
                {
                    attributeValue = attribute.Value;
                    break;
                }
            }
        }
       
        return attributeValue;
    }
   
    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;
    }
#>

This is it - T4 programming reminds me of my very old days as a classical COM and ASP programmer... :)


Comments

Feed You can follow this conversation by subscribing to the comment feed for this post.

jordan retro 11

Experience is the child of thought , and thought is the child of action. We cannot learn men from books. Do you think so?

tibia gold

if(String.IsNullOrEmpty(operationContractValue))
{
Write(" Action = \"");
Write(method.Name + "\",");
WriteLine(String.Empty);
Write(" ReplyAction = \"");
Write(method.Name + "Reply\",");
WriteLine(String.Empty);
}
else
{
ClearIndent();
WriteLine(" " + operationContractValue + ",");
PushIndent(" ");
}
i think the above porgrame have some somd bugs.

ugg boots outlet

How great minds think alike.

supra shoes

A burnt child dreads the fire.

air jordan shoes

Don't waste life in doubts and fears.

air jordan

Her advice to me was to work harder!!

nike air max

*One of these days is none of these days!!!

Air Jordan

&we are get together!

moncler jackets

oh, I really like the style of your writing!

supra skytops

[ this is good]

Beats Headphones

Thank You for posting this. i really enjoyed reading this!!

discount coach bags

[ this is good]

Property

Everyone dreams of having his own house. If you too want to have your own house, read this blog where you will find tips to help you find your dream house.

Taobao

That's not his. Steve's is black*_*

taobao agent

nous allons louer une voiture pour le week-end*_*

Nick

It's a Very helpful article for me. Actually, I am fond of reading online punjabi news. Thanks for writing such a complete ..And,I wantn't to miss them.
Thank you for sharing..

Cheap taobao agent

He is a good friend that speaks well of us behind our backs.
*_*

Taobao buy

*Forget about stupidity, discover your ability.

Air Jordan

When I am working on a problem I never think about beauty. I only think about how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong. Do you agree?

Supra Shoes

We all enhance people's quality of life and the pursuit of a new life concept noble, elegant, romantic and warm atmosphere, its transmission is a new philosophy of life.

Inversiones en oro

I've been reading your post and I think have very good information, I would like to know the methodology you use to write your post.

Inversiones en oro

I've been reading your post and I think have very good information, I would like to know the methodology you use to write your post.

Property

Wow! I was searching this kind of code for a long time and finally I found this code on your post

Discount Ed Hardy Christian

and traditional festivals, will be the most cohesive a festival, while

oakley sunglasses

*=*Open innovation has not spurred improved innovation implementation, just justified spending less with no real plans to achieve growth. With open innovation, of course, failures no longer belong to the company because the "open environment" didn't produce anything - hence innovation simply wasn't possible .=*=

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been saved. Comments are moderated and will not appear until approved by the author. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment

Comments are moderated, and will not appear until the author has approved them.

Your Information

(Name is required. Email address will not be displayed with the comment.)