Productivity: Auto generate WCF Service Contracts using T4 template.

The purpose of this T4 template is to auto generate WCF Service Contracts with appropriate ServiceContract, OperationContract (with Name for overloads) and FaultContract attributes from an existing WCF Service implementation class.

The template adds Name property of the OperationContract if the method is overloaded and, for simplicity, a number is appended to the name of the method. You should change this Name property afterwards specially for 3rd party consumption.

The template will check for out/ref parameters and generate the contract accordingly.

USAGE:
1. Drop this file into your VS project (VS 2008+).
2. Rename this file to match this pattern: {Your_Service_Implementation_File}.tt
3. The WCF Service Contract gets generated as {Your_Service_Implementation_File}.cs in the same project when you save the file.
4. In the world of SOA, you must move this Service Contract to a common assembly outside of the implementation project. So, be sure to move the file (and rename the interface as needed) and change the namespace to match the namespace in the common assembly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
<#
/*
   The purpose of this T4 template is to auto generate WCF Service Contracts
   with appropriate ServiceContract, OperationContract (with Name for overloads)
   and FaultContract<Type> attributes from an existing WCF Service implementation class.
 
   The template adds Name property of the OperationContract if the method is overloaded and,
   for simplicity, a number is appended to the name of the method. You should change this Name
   property afterwards specially for 3rd party consumption.
 
   The template will check of out/ref parameters and generate the contract accordingly.
 
   USAGE:
   1. Drop this file into your VS project (VS 2008+).
   2. Rename this file to match this pattern: {Your_Service_Implementation_File}.tt
   3. The WCF Service Contract gets generated as {Your_Service_Implementation_File}.cs in the same project when you save the file.
   4. In the world of SOA, you must move this Service Contract to a common assembly outside of the implementation project.
      So, be sure to move the file (and rename the interface as needed) and change the namespace to match the namespace in the
      common assembly.
*/
#>
<#@ template debug="true" hostspecific="true" #>
<#@ output extension="cs" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ assembly name="EnvDTE80" #>
<#@ import namespace="EnvDTE80" #>
<#   
    //Get reference to VS Development environment.
    EnvDTE.DTE dte = GetEnvDTE();
 
    //Extract source file name from this template (.tt) file.
    string sourceFileName = dte.Solution.FindProjectItem(Host.TemplateFile).Name;
     
    //sourceFileName is your Your_Service_Implementation_File
    sourceFileName =sourceFileName.Replace(".tt", ".cs"); 
    
    ProjectItem enumProjectItem = dte.Solution.FindProjectItem(sourceFileName);
    FileCodeModel codeModel = enumProjectItem.FileCodeModel;
 
    CodeNamespace codeNamespace = FindNamespace(codeModel.CodeElements);
    CodeClass codeClass = FindClass(codeModel.CodeElements);
    List<CodeFunction> codeFunctions = GetPublicMethodList(codeClass.Children);
         
     
#>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Configuration;
using System.Reflection;
using System.ServiceModel.Configuration;
using System.Runtime.Serialization;
 
namespace <#= codeNamespace.Name #>
{
    [ServiceContract(Namespace="http://www.yourdomain.com" +"/<#= codeNamespace.Name #>")]
    public interface I<#= codeClass.Name #>
    {                   
        <#
            PushIndent("        ");
             
            int methodCount = 0;
             
            foreach (CodeFunction method in codeFunctions)
            {
                if(methodCount > 0)
                {
                    WriteLine(String.Empty);
                    WriteLine(String.Empty);
                }
                 
                if(codeClass.Name==method.Name)
                {
                    continue; //skip the constructor(s)
                }
                WriteSyncOperationContract(method, methodCount);
                WriteLine(string.Empty);
                 
                methodCount ++;
            }
             
            ClearIndent();
        #>
    }
}
 
<#+
    private void WriteSyncOperationContract(CodeFunction method, int methodNumber)
    {
         
        if(method.IsOverloaded==true)
        {
            WriteLine("&#91;OperationContract(Name=" +"\"" +method.Name +methodNumber.ToString()  +"\")&#93;");
        }
        else
        {
            WriteLine("&#91;OperationContract&#93;");
        }
         
        WriteLine("//&#91;FaultContract(typeof(your_custom_serializable_type))&#93;");
        Write(method.Type.AsString);
        Write(" ");
        Write(method.Name);
        Write("(");
 
        int count = 1;
         
        foreach(CodeElement element in method.Parameters)
        {
            CodeParameter parameter = element as CodeParameter;
             
            if (parameter != null)
            {
                CodeParameter2 parameter2=(CodeParameter2) parameter;
                 
                if(parameter2.ParameterKind ==vsCMParameterKind.vsCMParameterKindRef)
                {
                    Write("ref");
                    Write(" ");
                }
                else if(parameter2.ParameterKind ==vsCMParameterKind.vsCMParameterKindOut)
                {
                    Write("out");
                    Write(" ");
                }
 
 
                 
                Write(parameter.Type.AsString + " ");
                Write(parameter.Name);
 
                if(count < method.Parameters.Count)
                {
                    Write(", ");
                }
                 
                count++;
            }
        }
 
        Write(");");  
    }
 
    private CodeNamespace FindNamespace(CodeElements elements)
    {
        foreach (CodeElement element in elements)
        {
            CodeNamespace ns = element as CodeNamespace;
         
            if (ns != null)
                return ns;
        }
     
        return null;
    }
     
    private CodeClass FindClass(CodeElements elements)
    {
        foreach (CodeElement element in elements)
        {
            CodeClass codeClass = element as CodeClass;
         
            if (codeClass != null)
                return codeClass;
     
            codeClass = FindClass(element.Children);
     
            if (codeClass != null)
                return codeClass;
        }
     
        return null;
    }
     
    private List<CodeFunction> GetPublicMethodList(CodeElements elements)
    {
        List<CodeFunction> methods = new List<CodeFunction>();
         
        foreach (CodeElement element in elements)
        {
            CodeFunction method = element as CodeFunction;
         
            if (method != null &&method.Access==vsCMAccess.vsCMAccessPublic)
            {
                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;
    }
#>

Acknowledgement:
http://weblogs.thinktecture.com/cweyer/2009/06/generating-async-wcf-operationcontract-signatures-with-a-t4-template.html

Leave a Reply