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... :)
Experience is the child of thought , and thought is the child of action. We cannot learn men from books. Do you think so?
Posted by: jordan retro 11 | 07/09/2010 at 11:33 AM
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.
Posted by: tibia gold | 10/08/2010 at 10:24 AM
How great minds think alike.
Posted by: ugg boots outlet | 11/03/2010 at 08:34 AM
A burnt child dreads the fire.
Posted by: supra shoes | 11/04/2010 at 07:55 AM
Don't waste life in doubts and fears.
Posted by: air jordan shoes | 11/05/2010 at 09:01 AM
Her advice to me was to work harder!!
Posted by: air jordan | 11/16/2010 at 01:44 AM
*One of these days is none of these days!!!
Posted by: nike air max | 11/16/2010 at 08:44 AM
&we are get together!
Posted by: Air Jordan | 11/16/2010 at 10:05 AM
oh, I really like the style of your writing!
Posted by: moncler jackets | 11/17/2010 at 03:28 AM
[ this is good]
Posted by: supra skytops | 11/22/2010 at 03:49 AM
Thank You for posting this. i really enjoyed reading this!!
Posted by: Beats Headphones | 11/25/2010 at 03:10 AM
[ this is good]
Posted by: discount coach bags | 12/16/2010 at 09:29 AM
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.
Posted by: Property | 12/22/2010 at 08:44 AM
That's not his. Steve's is black*_*
Posted by: Taobao | 12/30/2010 at 04:25 AM
nous allons louer une voiture pour le week-end*_*
Posted by: taobao agent | 01/04/2011 at 03:10 AM
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..
Posted by: Nick | 01/05/2011 at 07:23 AM
He is a good friend that speaks well of us behind our backs.
*_*
Posted by: Cheap taobao agent | 01/05/2011 at 09:32 AM
*Forget about stupidity, discover your ability.
Posted by: Taobao buy | 01/17/2011 at 08:16 AM
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?
Posted by: Air Jordan | 02/17/2011 at 04:37 PM
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.
Posted by: Supra Shoes | 02/28/2011 at 04:45 AM
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.
Posted by: Inversiones en oro | 04/12/2011 at 05:50 PM
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.
Posted by: Inversiones en oro | 04/12/2011 at 06:00 PM
Wow! I was searching this kind of code for a long time and finally I found this code on your post
Posted by: Property | 04/27/2011 at 10:16 AM
and traditional festivals, will be the most cohesive a festival, while
Posted by: Discount Ed Hardy Christian | 05/11/2011 at 05:29 AM
*=*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 .=*=
Posted by: oakley sunglasses | 05/19/2011 at 09:39 AM