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
, bool generateAsync
)
80 ml_context
= mlContext
;
81 generate_async
= generateAsync
;
84 MoonlightChannelBaseContext ml_context
;
88 public void AddBindingParameters (ContractDescription contractDescription
, ServiceEndpoint endpoint
, BindingParameterCollection bindingParameters
)
90 throw new NotSupportedException ();
93 public void ApplyClientBehavior (
94 ContractDescription description
,
95 ServiceEndpoint endpoint
,
98 throw new NotSupportedException ();
101 public void ApplyDispatchBehavior (
102 ContractDescription description
,
103 ServiceEndpoint endpoint
,
104 DispatchRuntime dispatch
)
106 throw new NotSupportedException ();
109 public void Validate (
110 ContractDescription description
,
111 ServiceEndpoint endpoint
)
113 throw new NotSupportedException ();
116 // IServiceContractGenerationExtensions
118 public void GenerateContract (
119 ServiceContractGenerationContext context
)
121 this.context
= context
;
122 ml_context
.Contract
= this;
125 ServiceContractGenerationContext context
;
129 ContractDescription cd
= context
.Contract
;
130 ml_context
.FindClientType (context
);
131 var parentClass
= ml_context
.ClientType
;
133 string name
= cd
.Name
+ "Channel";
135 name
= name
.Substring (1);
137 var gt
= new CodeTypeReference (cd
.Name
);
138 var clientBaseType
= new CodeTypeReference ("System.ServiceModel.ClientBase", gt
);
139 // this omits namespace, but should compile
140 var channelBase
= new CodeTypeReference ("ChannelBase", gt
);
141 var type
= new CodeTypeDeclaration (name
);
142 parentClass
.Members
.Add (type
);
143 type
.BaseTypes
.Add (channelBase
);
144 type
.BaseTypes
.Add (new CodeTypeReference (cd
.Name
));
145 type
.TypeAttributes
|= TypeAttributes
.NestedPrivate
;
147 ml_context
.ChannelType
= type
;
149 // .ctor(ClientBase<T> client)
150 var ctor
= new CodeConstructor ();
151 ctor
.Attributes
= MemberAttributes
.Public
;
152 ctor
.Parameters
.Add (
153 new CodeParameterDeclarationExpression (
154 clientBaseType
, "client"));
155 ctor
.BaseConstructorArgs
.Add (
156 new CodeArgumentReferenceExpression ("client"));
157 type
.Members
.Add (ctor
);
160 // protected override TChannel CreateChannel()
161 var creator
= new CodeMemberMethod ();
162 creator
.Name
= "CreateChannel";
163 creator
.Attributes
= MemberAttributes
.Family
| MemberAttributes
.Override
;
164 creator
.ReturnType
= gt
;
165 creator
.Statements
.Add (
166 new CodeMethodReturnStatement (
167 new CodeCastExpression (
169 new CodeObjectCreateExpression (
170 new CodeTypeReference (name
),
171 new CodeThisReferenceExpression ()))));
172 parentClass
.Members
.Add (creator
);
176 class MoonlightChannelBaseOperationExtension
: IOperationBehavior
, IOperationContractGenerationExtension
178 public MoonlightChannelBaseOperationExtension (MoonlightChannelBaseContext mlContext
, bool generateAsync
)
180 ml_context
= mlContext
;
181 generate_async
= generateAsync
;
184 MoonlightChannelBaseContext ml_context
;
187 // IOperationBehavior
189 public void AddBindingParameters (
190 OperationDescription description
,
191 BindingParameterCollection parameters
)
193 throw new NotSupportedException ();
196 public void ApplyDispatchBehavior (
197 OperationDescription description
,
198 DispatchOperation dispatch
)
200 throw new NotSupportedException ();
203 public void ApplyClientBehavior (
204 OperationDescription description
,
205 ClientOperation proxy
)
207 throw new NotSupportedException ();
210 public void Validate (
211 OperationDescription description
)
213 throw new NotSupportedException ();
216 // IOperationContractGenerationContext
218 public void GenerateOperation (OperationContractGenerationContext context
)
220 this.context
= context
;
221 ml_context
.Operations
.Add (this);
224 OperationContractGenerationContext context
;
234 public void FixupSync ()
236 var type
= ml_context
.ChannelType
;
237 var od
= context
.Operation
;
239 // sync method implementation
240 CodeMemberMethod cm
= new CodeMemberMethod ();
241 type
.Members
.Add (cm
);
243 cm
.Attributes
= MemberAttributes
.Public
244 | MemberAttributes
.Final
;
246 var inArgs
= new List
<CodeParameterDeclarationExpression
> ();
247 var outArgs
= new List
<CodeParameterDeclarationExpression
> ();
249 foreach (CodeParameterDeclarationExpression p
in context
.SyncMethod
.Parameters
) {
251 cm
.Parameters
.Add (p
);
254 cm
.ReturnType
= context
.SyncMethod
.ReturnType
;
256 var argsDecl
= new CodeVariableDeclarationStatement (
259 new CodeArrayCreateExpression (typeof (object), inArgs
.ConvertAll
<CodeExpression
> (decl
=> new CodeArgumentReferenceExpression (decl
.Name
)).ToArray ()));
260 cm
.Statements
.Add (argsDecl
);
262 var args
= new List
<CodeExpression
> ();
263 args
.Add (new CodePrimitiveExpression (od
.Name
));
264 args
.Add (new CodeVariableReferenceExpression ("args"));
266 CodeExpression call
= new CodeMethodInvokeExpression (
267 new CodeBaseReferenceExpression (),
271 if (cm
.ReturnType
.BaseType
== "System.Void")
272 cm
.Statements
.Add (new CodeExpressionStatement (call
));
274 cm
.Statements
.Add (new CodeMethodReturnStatement (new CodeCastExpression (context
.SyncMethod
.ReturnType
, call
)));
277 public void FixupAsync ()
279 var type
= ml_context
.ChannelType
;
280 var od
= context
.Operation
;
282 // BeginXxx() implementation
283 CodeMemberMethod cm
= new CodeMemberMethod ();
284 type
.Members
.Add (cm
);
285 cm
.Name
= "Begin" + od
.Name
;
286 cm
.Attributes
= MemberAttributes
.Public
287 | MemberAttributes
.Final
;
289 var inArgs
= new List
<CodeParameterDeclarationExpression
> ();
290 var outArgs
= new List
<CodeParameterDeclarationExpression
> ();
292 foreach (CodeParameterDeclarationExpression p
in context
.BeginMethod
.Parameters
) {
294 cm
.Parameters
.Add (p
);
296 inArgs
.RemoveAt (inArgs
.Count
- 1);
297 inArgs
.RemoveAt (inArgs
.Count
- 1);
299 // cm.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (AsyncCallback)), "asyncCallback"));
300 // cm.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (object)), "userState"));
301 cm
.ReturnType
= new CodeTypeReference (typeof (IAsyncResult
));
303 var argsDecl
= new CodeVariableDeclarationStatement (
306 new CodeArrayCreateExpression (typeof (object), inArgs
.ConvertAll
<CodeExpression
> (decl
=> new CodeArgumentReferenceExpression (decl
.Name
)).ToArray ()));
307 cm
.Statements
.Add (argsDecl
);
309 var args
= new List
<CodeExpression
> ();
310 args
.Add (new CodePrimitiveExpression (od
.Name
));
311 args
.Add (new CodeVariableReferenceExpression ("args"));
312 args
.Add (new CodeArgumentReferenceExpression ("asyncCallback"));
313 args
.Add (new CodeArgumentReferenceExpression ("userState"));
315 CodeExpression call
= new CodeMethodInvokeExpression (
316 new CodeBaseReferenceExpression (),
320 if (cm
.ReturnType
.BaseType
== "System.Void")
321 cm
.Statements
.Add (new CodeExpressionStatement (call
));
323 cm
.Statements
.Add (new CodeMethodReturnStatement (call
));
325 // EndXxx() implementation
327 cm
= new CodeMemberMethod ();
328 cm
.Attributes
= MemberAttributes
.Public
329 | MemberAttributes
.Final
;
330 type
.Members
.Add (cm
);
331 cm
.Name
= "End" + od
.Name
;
333 var res
= new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (IAsyncResult
)), "result");
334 cm
.Parameters
.Add (res
);
336 cm
.ReturnType
= context
.EndMethod
.ReturnType
;
338 string resultArgName
= "result";
339 argsDecl
= new CodeVariableDeclarationStatement (
342 new CodeArrayCreateExpression (typeof (object), new CodePrimitiveExpression (outArgs
.Count
)));
343 cm
.Statements
.Add (argsDecl
);
345 call
= new CodeCastExpression (
346 context
.EndMethod
.ReturnType
,
347 new CodeMethodInvokeExpression (
348 new CodeBaseReferenceExpression (),
350 new CodePrimitiveExpression (od
.Name
),
351 new CodeVariableReferenceExpression ("args"),
352 new CodeArgumentReferenceExpression (resultArgName
)));
354 if (cm
.ReturnType
.BaseType
== "System.Void")
355 cm
.Statements
.Add (new CodeExpressionStatement (call
));
357 cm
.Statements
.Add (new CodeMethodReturnStatement (call
));