2 // MoonlightChannelBaseExtension.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2009 Novell, Inc. http://www.novell.com
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.CodeDom.Compiler;
31 using System.Collections.Generic;
32 using System.Collections.ObjectModel;
34 using System.Reflection;
35 using System.ServiceModel;
36 using System.ServiceModel.Channels;
37 using System.ServiceModel.Description;
38 using System.ServiceModel.Dispatcher;
40 namespace Mono.ServiceContractTool
42 class MoonlightChannelBaseContext
44 public MoonlightChannelBaseContractExtension Contract;
45 public List<MoonlightChannelBaseOperationExtension> Operations = new List<MoonlightChannelBaseOperationExtension> ();
47 public CodeTypeDeclaration ClientType { get; set; }
48 public CodeTypeDeclaration ChannelType { get; set; }
50 public void FindClientType (ServiceContractGenerationContext context)
52 var cd = context.Contract;
53 string name = cd.Name + "Client";
55 name = name.Substring (1);
57 foreach (CodeNamespace cns in context.ServiceContractGenerator.TargetCompileUnit.Namespaces)
58 foreach (CodeTypeDeclaration ct in cns.Types)
59 if (ct == context.ContractType)
60 foreach (CodeTypeDeclaration ct2 in cns.Types)
61 if (ct2.Name == name) {
65 throw new Exception (String.Format ("Contract '{0}' not found", name));
71 foreach (var op in Operations)
76 class MoonlightChannelBaseContractExtension : IContractBehavior, IServiceContractGenerationExtension
78 public MoonlightChannelBaseContractExtension (MoonlightChannelBaseContext mlContext)
80 ml_context = mlContext;
83 MoonlightChannelBaseContext ml_context;
86 public void AddBindingParameters (ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
88 throw new NotSupportedException ();
91 public void ApplyClientBehavior (
92 ContractDescription description,
93 ServiceEndpoint endpoint,
96 throw new NotSupportedException ();
99 public void ApplyDispatchBehavior (
100 ContractDescription description,
101 ServiceEndpoint endpoint,
102 DispatchRuntime dispatch)
104 throw new NotSupportedException ();
107 public void Validate (
108 ContractDescription description,
109 ServiceEndpoint endpoint)
111 throw new NotSupportedException ();
114 // IServiceContractGenerationExtensions
116 public void GenerateContract (
117 ServiceContractGenerationContext context)
119 this.context = context;
120 ml_context.Contract = this;
123 ServiceContractGenerationContext context;
127 ContractDescription cd = context.Contract;
128 ml_context.FindClientType (context);
129 var parentClass = ml_context.ClientType;
131 string name = cd.Name + "Channel";
133 name = name.Substring (1);
135 var gt = new CodeTypeReference (cd.Name);
136 var clientBaseType = new CodeTypeReference ("System.ServiceModel.ClientBase", gt);
137 // this omits namespace, but should compile
138 var channelBase = new CodeTypeReference ("ChannelBase", gt);
139 var type = new CodeTypeDeclaration (name);
140 parentClass.Members.Add (type);
141 type.BaseTypes.Add (channelBase);
142 type.BaseTypes.Add (new CodeTypeReference (cd.Name));
143 type.TypeAttributes |= TypeAttributes.NestedPrivate;
145 ml_context.ChannelType = type;
147 // .ctor(ClientBase<T> client)
148 var ctor = new CodeConstructor ();
149 ctor.Attributes = MemberAttributes.Public;
150 ctor.Parameters.Add (
151 new CodeParameterDeclarationExpression (
152 clientBaseType, "client"));
153 ctor.BaseConstructorArgs.Add (
154 new CodeArgumentReferenceExpression ("client"));
155 type.Members.Add (ctor);
159 class MoonlightChannelBaseOperationExtension : IOperationBehavior, IOperationContractGenerationExtension
161 public MoonlightChannelBaseOperationExtension (MoonlightChannelBaseContext mlContext)
163 ml_context = mlContext;
166 MoonlightChannelBaseContext ml_context;
168 // IOperationBehavior
170 public void AddBindingParameters (
171 OperationDescription description,
172 BindingParameterCollection parameters)
174 throw new NotSupportedException ();
177 public void ApplyDispatchBehavior (
178 OperationDescription description,
179 DispatchOperation dispatch)
181 throw new NotSupportedException ();
184 public void ApplyClientBehavior (
185 OperationDescription description,
186 ClientOperation proxy)
188 throw new NotSupportedException ();
191 public void Validate (
192 OperationDescription description)
194 throw new NotSupportedException ();
197 // IOperationContractGenerationContext
199 public void GenerateOperation (OperationContractGenerationContext context)
201 this.context = context;
202 ml_context.Operations.Add (this);
205 OperationContractGenerationContext context;
209 var type = ml_context.ChannelType;
210 var od = context.Operation;
212 CodeMemberMethod cm = new CodeMemberMethod ();
213 type.Members.Add (cm);
214 cm.Name = "Begin" + od.Name;
215 cm.Attributes = MemberAttributes.Public
216 | MemberAttributes.Final;
218 var inArgs = new List<CodeParameterDeclarationExpression > ();
219 var outArgs = new List<CodeParameterDeclarationExpression > ();
221 foreach (CodeParameterDeclarationExpression p in context.BeginMethod.Parameters) {
223 cm.Parameters.Add (p);
225 inArgs.RemoveAt (inArgs.Count - 1);
226 inArgs.RemoveAt (inArgs.Count - 1);
228 // cm.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (AsyncCallback)), "asyncCallback"));
229 // cm.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (object)), "userState"));
230 cm.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
232 var argsDecl = new CodeVariableDeclarationStatement (
235 new CodeArrayCreateExpression (typeof (object), inArgs.ConvertAll<CodeExpression> (decl => new CodeArgumentReferenceExpression (decl.Name)).ToArray ()));
236 cm.Statements.Add (argsDecl);
238 var args = new List<CodeExpression> ();
239 args.Add (new CodePrimitiveExpression (od.Name));
240 args.Add (new CodeVariableReferenceExpression ("args"));
241 args.Add (new CodeArgumentReferenceExpression ("asyncCallback"));
242 args.Add (new CodeArgumentReferenceExpression ("userState"));
244 CodeExpression call = new CodeMethodInvokeExpression (
245 new CodeBaseReferenceExpression (),
249 if (cm.ReturnType.BaseType == "System.Void")
250 cm.Statements.Add (new CodeExpressionStatement (call));
252 cm.Statements.Add (new CodeMethodReturnStatement (call));
254 // EndXxx() implementation
256 cm = new CodeMemberMethod ();
257 cm.Attributes = MemberAttributes.Public
258 | MemberAttributes.Final;
259 type.Members.Add (cm);
260 cm.Name = "End" + od.Name;
262 var res = new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (IAsyncResult)), "result");
263 cm.Parameters.Add (res);
265 cm.ReturnType = context.EndMethod.ReturnType;
267 string resultArgName = "result";
268 argsDecl = new CodeVariableDeclarationStatement (
271 new CodeArrayCreateExpression (typeof (object), new CodePrimitiveExpression (outArgs.Count)));
272 cm.Statements.Add (argsDecl);
274 call = new CodeCastExpression (
275 context.EndMethod.ReturnType,
276 new CodeMethodInvokeExpression (
277 new CodeBaseReferenceExpression (),
279 new CodePrimitiveExpression (od.Name),
280 new CodeVariableReferenceExpression ("args"),
281 new CodeArgumentReferenceExpression (resultArgName)));
283 if (cm.ReturnType.BaseType == "System.Void")
284 cm.Statements.Add (new CodeExpressionStatement (call));
286 cm.Statements.Add (new CodeMethodReturnStatement (call));