The purpose of this T4 template is to auto generate WCF Service Contracts with appropriate ServiceContract, OperationContract (with Name for overloads) and FaultContract
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("[OperationContract(Name=" +"\"" +method.Name +methodNumber.ToString() +"\")]"); } else { WriteLine("[OperationContract]"); } WriteLine("//[FaultContract(typeof(your_custom_serializable_type))]"); 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