1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
4 #pragma warning disable 1634, 1691
5 namespace System
.ServiceModel
.Description
8 using System
.Collections
.Generic
;
9 using System
.Collections
.ObjectModel
;
10 using System
.ComponentModel
;
13 using System
.ServiceModel
;
14 using System
.ServiceModel
.Administration
;
15 using System
.ServiceModel
.Channels
;
16 using System
.ServiceModel
.Dispatcher
;
17 using System
.ServiceModel
.Web
;
19 public class WebHttpBehavior
: IEndpointBehavior
, IWmiInstanceProvider
21 internal const string GET
= "GET";
22 internal const string POST
= "POST";
23 internal const string WildcardAction
= "*";
24 internal const string WildcardMethod
= "*";
25 internal static readonly string defaultStreamContentType
= "application/octet-stream";
26 internal static readonly string defaultCallbackParameterName
= "callback";
27 const string AddressPropertyName
= "Address";
28 WebMessageBodyStyle defaultBodyStyle
;
29 WebMessageFormat defaultOutgoingReplyFormat
;
30 WebMessageFormat defaultOutgoingRequestFormat
;
31 XmlSerializerOperationBehavior
.Reflector reflector
;
32 UnwrappedTypesXmlSerializerManager xmlSerializerManager
;
34 public WebHttpBehavior()
36 defaultOutgoingRequestFormat
= WebMessageFormat
.Xml
;
37 defaultOutgoingReplyFormat
= WebMessageFormat
.Xml
;
38 this.defaultBodyStyle
= WebMessageBodyStyle
.Bare
;
39 xmlSerializerManager
= new UnwrappedTypesXmlSerializerManager();
42 internal delegate void Effect();
44 public virtual WebMessageBodyStyle DefaultBodyStyle
46 get { return this.defaultBodyStyle; }
49 if (!WebMessageBodyStyleHelper
.IsDefined(value))
51 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new ArgumentOutOfRangeException("value"));
53 this.defaultBodyStyle
= value;
57 public virtual WebMessageFormat DefaultOutgoingRequestFormat
61 return this.defaultOutgoingRequestFormat
;
65 if (!WebMessageFormatHelper
.IsDefined(value))
67 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new ArgumentOutOfRangeException("value"));
69 this.defaultOutgoingRequestFormat
= value;
73 public virtual WebMessageFormat DefaultOutgoingResponseFormat
77 return this.defaultOutgoingReplyFormat
;
81 if (!WebMessageFormatHelper
.IsDefined(value))
83 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new ArgumentOutOfRangeException("value"));
85 this.defaultOutgoingReplyFormat
= value;
89 public virtual bool HelpEnabled { get; set; }
91 public virtual bool AutomaticFormatSelectionEnabled { get; set; }
93 public virtual bool FaultExceptionEnabled { get; set; }
95 internal Uri HelpUri { get; set; }
97 protected internal string JavascriptCallbackParameterName { get; set; }
99 public virtual void AddBindingParameters(ServiceEndpoint endpoint
, BindingParameterCollection bindingParameters
)
104 public virtual void ApplyClientBehavior(ServiceEndpoint endpoint
, ClientRuntime clientRuntime
)
106 if (endpoint
== null)
108 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperArgumentNull("endpoint");
110 if (clientRuntime
== null)
112 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperArgumentNull("clientRuntime");
114 WebMessageEncodingBindingElement webEncodingBindingElement
= endpoint
.Binding
.CreateBindingElements().Find
<WebMessageEncodingBindingElement
>();
115 if (webEncodingBindingElement
!= null && webEncodingBindingElement
.CrossDomainScriptAccessEnabled
)
117 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new NotSupportedException(SR2
.CrossDomainJavascriptNotsupported
));
119 #pragma warning disable 56506 // Microsoft, endpoint.Contract is never null
120 this.reflector
= new XmlSerializerOperationBehavior
.Reflector(endpoint
.Contract
.Namespace
, null);
121 foreach (OperationDescription od
in endpoint
.Contract
.Operations
)
122 #pragma warning restore 56506
124 #pragma warning disable 56506 // Microsoft, clientRuntime.Operations is never null
125 if (clientRuntime
.Operations
.Contains(od
.Name
))
126 #pragma warning restore 56506
128 ClientOperation cop
= clientRuntime
.Operations
[od
.Name
];
129 IClientMessageFormatter requestClient
= GetRequestClientFormatter(od
, endpoint
);
130 IClientMessageFormatter replyClient
= GetReplyClientFormatter(od
, endpoint
);
131 cop
.Formatter
= new CompositeClientFormatter(requestClient
, replyClient
);
132 cop
.SerializeRequest
= true;
133 cop
.DeserializeReply
= od
.Messages
.Count
> 1 && !IsUntypedMessage(od
.Messages
[1]);
136 AddClientErrorInspector(endpoint
, clientRuntime
);
139 public virtual void ApplyDispatchBehavior(ServiceEndpoint endpoint
, EndpointDispatcher endpointDispatcher
)
141 if (endpoint
== null)
143 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperArgumentNull("endpoint");
145 if (endpointDispatcher
== null)
147 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperArgumentNull("endpointDispatcher");
149 WebMessageEncodingBindingElement webEncodingBindingElement
= endpoint
.Binding
.CreateBindingElements().Find
<WebMessageEncodingBindingElement
>();
150 if (webEncodingBindingElement
!= null && webEncodingBindingElement
.CrossDomainScriptAccessEnabled
)
152 ISecurityCapabilities securityCapabilities
= endpoint
.Binding
.GetProperty
<ISecurityCapabilities
>(new BindingParameterCollection());
153 if (securityCapabilities
.SupportsClientAuthentication
)
155 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new NotSupportedException(SR2
.CrossDomainJavascriptAuthNotSupported
));
157 if (endpoint
.Contract
.Behaviors
.Contains(typeof(JavascriptCallbackBehaviorAttribute
)))
159 JavascriptCallbackBehaviorAttribute behavior
= endpoint
.Contract
.Behaviors
[typeof(JavascriptCallbackBehaviorAttribute
)] as JavascriptCallbackBehaviorAttribute
;
160 this.JavascriptCallbackParameterName
= behavior
.UrlParameterName
;
164 this.JavascriptCallbackParameterName
= defaultCallbackParameterName
;
166 endpointDispatcher
.DispatchRuntime
.MessageInspectors
.Add(new JavascriptCallbackMessageInspector(this.JavascriptCallbackParameterName
));
168 if (this.HelpEnabled
)
170 this.HelpUri
= new UriTemplate(HelpPage
.OperationListHelpPageUriTemplate
).BindByPosition(endpoint
.ListenUri
);
172 #pragma warning disable 56506 // Microsoft, endpoint.Contract is never null
173 this.reflector
= new XmlSerializerOperationBehavior
.Reflector(endpoint
.Contract
.Namespace
, null);
174 #pragma warning restore 56506
177 endpointDispatcher
.AddressFilter
= new PrefixEndpointAddressMessageFilter(endpoint
.Address
);
178 endpointDispatcher
.ContractFilter
= new MatchAllMessageFilter();
179 // operation selector
180 #pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime is never null
181 endpointDispatcher
.DispatchRuntime
.OperationSelector
= this.GetOperationSelector(endpoint
);
182 #pragma warning restore 56506
183 // unhandled operation
184 string actionStarOperationName
= null;
185 #pragma warning disable 56506 // Microsoft, endpoint.Contract is never null
186 foreach (OperationDescription od
in endpoint
.Contract
.Operations
)
187 #pragma warning restore 56506
189 if (od
.Messages
[0].Direction
== MessageDirection
.Input
190 && od
.Messages
[0].Action
== WildcardAction
)
192 actionStarOperationName
= od
.Name
;
196 if (actionStarOperationName
!= null)
198 // WCF v1 installs any Action="*" op into UnhandledDispatchOperation, but WebHttpBehavior
199 // doesn't want this, so we 'move' that operation back into normal set of operations
200 #pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime.{Operations,UnhandledDispatchOperation} is never null
201 endpointDispatcher
.DispatchRuntime
.Operations
.Add(
202 endpointDispatcher
.DispatchRuntime
.UnhandledDispatchOperation
);
203 #pragma warning restore 56506
206 FormatSelectingMessageInspector formatSelectingMessageInspector
= null;
207 string xmlContentType
= null;
208 string jsonContentType
= null;
211 if (webEncodingBindingElement
!= null)
213 XmlFormatMapping xmlFormatMapping
= new XmlFormatMapping(webEncodingBindingElement
.WriteEncoding
, webEncodingBindingElement
.ContentTypeMapper
);
214 JsonFormatMapping jsonFormatMapping
= new JsonFormatMapping(webEncodingBindingElement
.WriteEncoding
, webEncodingBindingElement
.ContentTypeMapper
);
216 xmlContentType
= xmlFormatMapping
.DefaultContentType
.ToString();
217 jsonContentType
= jsonFormatMapping
.DefaultContentType
.ToString();
219 if (AutomaticFormatSelectionEnabled
)
221 formatSelectingMessageInspector
= new FormatSelectingMessageInspector(this, new List
<MultiplexingFormatMapping
> { xmlFormatMapping, jsonFormatMapping }
);
222 endpointDispatcher
.DispatchRuntime
.MessageInspectors
.Add(formatSelectingMessageInspector
);
227 xmlContentType
= TextMessageEncoderFactory
.GetContentType(XmlFormatMapping
.defaultMediaType
, TextEncoderDefaults
.Encoding
);
228 jsonContentType
= JsonMessageEncoderFactory
.GetContentType(null);
231 #pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation is never null
232 // always install UnhandledDispatchOperation (WebHttpDispatchOperationSelector may choose not to use it)
233 endpointDispatcher
.DispatchRuntime
.UnhandledDispatchOperation
= new DispatchOperation(endpointDispatcher
.DispatchRuntime
, "*", WildcardAction
, WildcardAction
);
234 endpointDispatcher
.DispatchRuntime
.UnhandledDispatchOperation
.DeserializeRequest
= false;
235 endpointDispatcher
.DispatchRuntime
.UnhandledDispatchOperation
.SerializeReply
= false;
236 endpointDispatcher
.DispatchRuntime
.UnhandledDispatchOperation
.Invoker
= new HttpUnhandledOperationInvoker { HelpUri = this.HelpUri }
;
237 #pragma warning restore 56506
238 // install formatters and parameter inspectors
239 foreach (OperationDescription od
in endpoint
.Contract
.Operations
)
241 DispatchOperation dop
= null;
242 #pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime, DispatchRuntime.Operations are never null
243 if (endpointDispatcher
.DispatchRuntime
.Operations
.Contains(od
.Name
))
244 #pragma warning restore 56506
246 dop
= endpointDispatcher
.DispatchRuntime
.Operations
[od
.Name
];
248 #pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation is never null
249 else if (endpointDispatcher
.DispatchRuntime
.UnhandledDispatchOperation
.Name
== od
.Name
)
251 dop
= endpointDispatcher
.DispatchRuntime
.UnhandledDispatchOperation
;
253 #pragma warning restore 56506
256 IDispatchMessageFormatter requestDispatch
= GetRequestDispatchFormatter(od
, endpoint
);
257 IDispatchMessageFormatter replyDispatch
= GetReplyDispatchFormatter(od
, endpoint
);
259 MultiplexingDispatchMessageFormatter replyDispatchAsMultiplexing
= replyDispatch
as MultiplexingDispatchMessageFormatter
;
261 if (replyDispatchAsMultiplexing
!= null)
263 // here we are adding all default content types, despite the fact that
264 // some of the formatters in MultiplexingDispatchMessageFormatter might not be present
265 // i.e. the JSON formatter
267 replyDispatchAsMultiplexing
.DefaultContentTypes
.Add(WebMessageFormat
.Xml
, xmlContentType
);
268 replyDispatchAsMultiplexing
.DefaultContentTypes
.Add(WebMessageFormat
.Json
, jsonContentType
);
270 if (formatSelectingMessageInspector
!= null)
272 formatSelectingMessageInspector
.RegisterOperation(od
.Name
, replyDispatchAsMultiplexing
);
276 dop
.Formatter
= new CompositeDispatchFormatter(requestDispatch
, replyDispatch
);
277 dop
.FaultFormatter
= new WebFaultFormatter(dop
.FaultFormatter
);
278 dop
.DeserializeRequest
= (requestDispatch
!= null);
279 dop
.SerializeReply
= od
.Messages
.Count
> 1 && (replyDispatch
!= null);
283 if (this.HelpEnabled
)
285 HelpPage helpPage
= new HelpPage(this, endpoint
.Contract
);
286 DispatchOperation dispatchOperation
= new DispatchOperation(endpointDispatcher
.DispatchRuntime
, HelpOperationInvoker
.OperationName
, null, null)
288 DeserializeRequest
= false,
289 SerializeReply
= false,
290 Invoker
= new HelpOperationInvoker(helpPage
, endpointDispatcher
.DispatchRuntime
.UnhandledDispatchOperation
.Invoker
),
292 endpointDispatcher
.DispatchRuntime
.Operations
.Add(dispatchOperation
);
294 AddServerErrorHandlers(endpoint
, endpointDispatcher
);
297 internal virtual Dictionary
<string, string> GetWmiProperties()
299 Dictionary
<string, string> result
= new Dictionary
<string, string>();
300 result
.Add("DefaultBodyStyle", this.DefaultBodyStyle
.ToString());
301 result
.Add("DefaultOutgoingRequestFormat", this.DefaultOutgoingRequestFormat
.ToString());
302 result
.Add("DefaultOutgoingResponseFormat", this.DefaultOutgoingResponseFormat
.ToString());
306 internal virtual string GetWmiTypeName()
308 return "WebHttpBehavior";
311 void IWmiInstanceProvider
.FillInstance(IWmiInstance wmiInstance
)
313 if (wmiInstance
== null)
315 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperArgument("wmiInstance");
317 Dictionary
<string, string> properties
= this.GetWmiProperties();
318 foreach (string key
in properties
.Keys
)
320 wmiInstance
.SetProperty(key
, properties
[key
]);
324 string IWmiInstanceProvider
.GetInstanceType()
326 return GetWmiTypeName();
329 public virtual void Validate(ServiceEndpoint endpoint
)
331 if (endpoint
== null)
333 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperArgumentNull("endpoint");
335 ValidateNoMessageHeadersPresent(endpoint
);
336 ValidateBinding(endpoint
);
337 ValidateContract(endpoint
);
340 void ValidateNoMessageHeadersPresent(ServiceEndpoint endpoint
)
342 if (endpoint
== null || endpoint
.Address
== null)
346 EndpointAddress address
= endpoint
.Address
;
347 if (address
.Headers
.Count
> 0)
349 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(SR2
.GetString(SR2
.WebHttpServiceEndpointCannotHaveMessageHeaders
, address
)));
353 protected virtual void ValidateBinding(ServiceEndpoint endpoint
)
355 ValidateIsWebHttpBinding(endpoint
, this.GetType().ToString());
358 internal static string GetWebMethod(OperationDescription od
)
360 WebGetAttribute wga
= od
.Behaviors
.Find
<WebGetAttribute
>();
361 WebInvokeAttribute wia
= od
.Behaviors
.Find
<WebInvokeAttribute
>();
362 EnsureOk(wga
, wia
, od
);
367 else if (wia
!= null)
369 return wia
.Method
?? POST
;
377 internal static string GetWebUriTemplate(OperationDescription od
)
379 // return exactly what is on the attribute
380 WebGetAttribute wga
= od
.Behaviors
.Find
<WebGetAttribute
>();
381 WebInvokeAttribute wia
= od
.Behaviors
.Find
<WebInvokeAttribute
>();
382 EnsureOk(wga
, wia
, od
);
385 return wga
.UriTemplate
;
387 else if (wia
!= null)
389 return wia
.UriTemplate
;
397 internal static string GetDescription(OperationDescription od
)
399 object[] attributes
= null;
400 if (od
.SyncMethod
!= null)
402 attributes
= od
.SyncMethod
.GetCustomAttributes(typeof(DescriptionAttribute
), true);
404 else if (od
.BeginMethod
!= null)
406 attributes
= od
.BeginMethod
.GetCustomAttributes(typeof(DescriptionAttribute
), true);
408 else if (od
.TaskMethod
!= null)
410 attributes
= od
.TaskMethod
.GetCustomAttributes(typeof(DescriptionAttribute
), true);
413 if (attributes
!= null && attributes
.Length
> 0)
415 return ((DescriptionAttribute
)attributes
[0]).Description
;
423 internal static bool IsTypedMessage(MessageDescription message
)
425 return (message
!= null && message
.MessageType
!= null);
428 internal static bool IsUntypedMessage(MessageDescription message
)
434 return (message
.Body
.ReturnValue
!= null && message
.Body
.Parts
.Count
== 0 && message
.Body
.ReturnValue
.Type
== typeof(Message
)) ||
435 (message
.Body
.ReturnValue
== null && message
.Body
.Parts
.Count
== 1 && message
.Body
.Parts
[0].Type
== typeof(Message
));
438 internal static MessageDescription
MakeDummyMessageDescription(MessageDirection direction
)
440 MessageDescription messageDescription
= new MessageDescription("urn:dummyAction", direction
);
441 return messageDescription
;
444 internal static bool SupportsJsonFormat(OperationDescription od
)
446 // if the type is XmlSerializable, then we cannot create a json serializer for it
447 DataContractSerializerOperationBehavior dcsob
= od
.Behaviors
.Find
<DataContractSerializerOperationBehavior
>();
448 return (dcsob
!= null);
451 internal static void ValidateIsWebHttpBinding(ServiceEndpoint serviceEndpoint
, string behaviorName
)
453 Binding binding
= serviceEndpoint
.Binding
;
454 if (binding
.Scheme
!= "http" && binding
.Scheme
!= "https")
456 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(
457 SR2
.GetString(SR2
.WCFBindingCannotBeUsedWithUriOperationSelectorBehaviorBadScheme
,
458 serviceEndpoint
.Contract
.Name
, behaviorName
)));
460 if (binding
.MessageVersion
!= MessageVersion
.None
)
462 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(
463 SR2
.GetString(SR2
.WCFBindingCannotBeUsedWithUriOperationSelectorBehaviorBadMessageVersion
,
464 serviceEndpoint
.Address
.Uri
.AbsoluteUri
, behaviorName
)));
466 TransportBindingElement transportBindingElement
= binding
.CreateBindingElements().Find
<TransportBindingElement
>();
467 if (transportBindingElement
!= null && !transportBindingElement
.ManualAddressing
)
469 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(
470 SR2
.GetString(SR2
.ManualAddressingCannotBeFalseWithTransportBindingElement
,
471 serviceEndpoint
.Address
.Uri
.AbsoluteUri
, behaviorName
, transportBindingElement
.GetType().Name
)));
475 internal WebMessageBodyStyle
GetBodyStyle(OperationDescription od
)
477 WebGetAttribute wga
= od
.Behaviors
.Find
<WebGetAttribute
>();
478 WebInvokeAttribute wia
= od
.Behaviors
.Find
<WebInvokeAttribute
>();
479 EnsureOk(wga
, wia
, od
);
482 return wga
.GetBodyStyleOrDefault(this.DefaultBodyStyle
);
484 else if (wia
!= null)
486 return wia
.GetBodyStyleOrDefault(this.DefaultBodyStyle
);
490 return this.DefaultBodyStyle
;
494 internal IClientMessageFormatter
GetDefaultClientFormatter(OperationDescription od
, bool useJson
, bool isWrapped
)
496 DataContractSerializerOperationBehavior dcsob
= od
.Behaviors
.Find
<DataContractSerializerOperationBehavior
>();
501 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(SR2
.GetString(SR2
.JsonFormatRequiresDataContract
, od
.Name
, od
.DeclaringContract
.Name
, od
.DeclaringContract
.Namespace
)));
503 return CreateDataContractJsonSerializerOperationFormatter(od
, dcsob
, isWrapped
);
507 ClientRuntime clientRuntime
= new ClientRuntime("name", "");
508 ClientOperation cop
= new ClientOperation(clientRuntime
, "dummyClient", "urn:dummy");
509 cop
.Formatter
= null;
513 (dcsob
as IOperationBehavior
).ApplyClientBehavior(od
, cop
);
514 return cop
.Formatter
;
516 XmlSerializerOperationBehavior xsob
= od
.Behaviors
.Find
<XmlSerializerOperationBehavior
>();
519 xsob
= new XmlSerializerOperationBehavior(od
, xsob
.XmlSerializerFormatAttribute
, this.reflector
);
520 (xsob
as IOperationBehavior
).ApplyClientBehavior(od
, cop
);
521 return cop
.Formatter
;
527 protected virtual void AddClientErrorInspector(ServiceEndpoint endpoint
, ClientRuntime clientRuntime
)
529 if (!this.FaultExceptionEnabled
)
531 clientRuntime
.MessageInspectors
.Add(new WebFaultClientMessageInspector());
535 clientRuntime
.MessageVersionNoneFaultsEnabled
= true;
539 protected virtual void AddServerErrorHandlers(ServiceEndpoint endpoint
, EndpointDispatcher endpointDispatcher
)
541 if (!this.FaultExceptionEnabled
)
543 WebErrorHandler errorHandler
= new WebErrorHandler(this, endpoint
.Contract
, endpointDispatcher
.DispatchRuntime
.ChannelDispatcher
.IncludeExceptionDetailInFaults
);
544 endpointDispatcher
.DispatchRuntime
.ChannelDispatcher
.ErrorHandlers
.Add(errorHandler
);
548 protected virtual WebHttpDispatchOperationSelector
GetOperationSelector(ServiceEndpoint endpoint
)
550 return new WebHttpDispatchOperationSelector(endpoint
);
553 protected virtual QueryStringConverter
GetQueryStringConverter(OperationDescription operationDescription
)
555 return new QueryStringConverter();
558 protected virtual IClientMessageFormatter
GetReplyClientFormatter(OperationDescription operationDescription
, ServiceEndpoint endpoint
)
560 if (operationDescription
.Messages
.Count
< 2)
564 ValidateBodyParameters(operationDescription
, false);
566 if (TryGetStreamParameterType(operationDescription
.Messages
[1], operationDescription
, false, out type
))
568 return new HttpStreamFormatter(operationDescription
);
570 if (IsUntypedMessage(operationDescription
.Messages
[1]))
572 return new MessagePassthroughFormatter();
574 WebMessageBodyStyle style
= GetBodyStyle(operationDescription
);
576 if (UseBareReplyFormatter(style
, operationDescription
, GetResponseFormat(operationDescription
), out parameterType
))
578 return SingleBodyParameterMessageFormatter
.CreateXmlAndJsonClientFormatter(operationDescription
, parameterType
, false, this.xmlSerializerManager
);
582 MessageDescription temp
= operationDescription
.Messages
[0];
583 operationDescription
.Messages
[0] = MakeDummyMessageDescription(MessageDirection
.Input
);
584 IClientMessageFormatter result
;
585 result
= GetDefaultXmlAndJsonClientFormatter(operationDescription
, !IsBareResponse(style
));
586 operationDescription
.Messages
[0] = temp
;
591 internal virtual bool UseBareReplyFormatter(WebMessageBodyStyle style
, OperationDescription operationDescription
, WebMessageFormat responseFormat
, out Type parameterType
)
593 parameterType
= null;
594 return IsBareResponse(style
) && TryGetNonMessageParameterType(operationDescription
.Messages
[1], operationDescription
, false, out parameterType
);
597 protected virtual IDispatchMessageFormatter
GetReplyDispatchFormatter(OperationDescription operationDescription
, ServiceEndpoint endpoint
)
599 if (operationDescription
.Messages
.Count
< 2)
603 ValidateBodyParameters(operationDescription
, false);
604 WebMessageFormat responseFormat
= GetResponseFormat(operationDescription
);
606 // Determine if we should add a json formatter; If the ResponseFormat is json, we always add the json formatter even if the
607 // operation is XmlSerializerFormat because the formatter constructor throws the exception: "json not valid with XmlSerializerFormat" [Microsoft]
608 bool useJson
= (responseFormat
== WebMessageFormat
.Json
|| SupportsJsonFormat(operationDescription
));
610 IDispatchMessageFormatter innerFormatter
;
613 if (TryGetStreamParameterType(operationDescription
.Messages
[1], operationDescription
, false, out type
))
615 innerFormatter
= new ContentTypeSettingDispatchMessageFormatter(defaultStreamContentType
, new HttpStreamFormatter(operationDescription
));
617 else if (IsUntypedMessage(operationDescription
.Messages
[1]))
619 innerFormatter
= new MessagePassthroughFormatter();
624 WebMessageBodyStyle style
= GetBodyStyle(operationDescription
);
625 Dictionary
<WebMessageFormat
, IDispatchMessageFormatter
> formatters
= new Dictionary
<WebMessageFormat
, IDispatchMessageFormatter
>();
627 if (UseBareReplyFormatter(style
, operationDescription
, responseFormat
, out parameterType
))
629 formatters
.Add(WebMessageFormat
.Xml
, SingleBodyParameterMessageFormatter
.CreateDispatchFormatter(operationDescription
, parameterType
, false, false, this.xmlSerializerManager
, null));
632 formatters
.Add(WebMessageFormat
.Json
, SingleBodyParameterMessageFormatter
.CreateDispatchFormatter(operationDescription
, parameterType
, false, true, this.xmlSerializerManager
, this.JavascriptCallbackParameterName
));
637 MessageDescription temp
= operationDescription
.Messages
[0];
638 operationDescription
.Messages
[0] = MakeDummyMessageDescription(MessageDirection
.Input
);
639 formatters
.Add(WebMessageFormat
.Xml
, GetDefaultDispatchFormatter(operationDescription
, false, !IsBareResponse(style
)));
642 formatters
.Add(WebMessageFormat
.Json
, GetDefaultDispatchFormatter(operationDescription
, true, !IsBareResponse(style
)));
644 operationDescription
.Messages
[0] = temp
;
646 innerFormatter
= new MultiplexingDispatchMessageFormatter(formatters
, responseFormat
);
649 return innerFormatter
;
652 protected virtual IClientMessageFormatter
GetRequestClientFormatter(OperationDescription operationDescription
, ServiceEndpoint endpoint
)
654 WebMessageFormat requestFormat
= GetRequestFormat(operationDescription
);
655 bool useJson
= (requestFormat
== WebMessageFormat
.Json
);
656 WebMessageEncodingBindingElement webEncoding
= (useJson
) ? endpoint
.Binding
.CreateBindingElements().Find
<WebMessageEncodingBindingElement
>() : null;
657 IClientMessageFormatter innerFormatter
= null;
659 // get some validation errors by creating "throwAway" formatter
661 // validate that endpoint.Address is not null before accessing the endpoint.Address.Uri. This is to avoid throwing a NullRefException while constructing a UriTemplateClientFormatter
662 if (endpoint
.Address
== null)
664 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(
665 SR2
.GetString(SR2
.ServiceEndpointMustHaveNonNullAddress
, typeof(ServiceEndpoint
), typeof(ChannelFactory
), typeof(WebHttpEndpoint
), AddressPropertyName
, typeof(ServiceEndpoint
))));
668 UriTemplateClientFormatter throwAway
= new UriTemplateClientFormatter(operationDescription
, null, GetQueryStringConverter(operationDescription
), endpoint
.Address
.Uri
, false, endpoint
.Contract
.Name
);
669 int numUriVariables
= throwAway
.pathMapping
.Count
+ throwAway
.queryMapping
.Count
;
670 bool isStream
= false;
671 HideReplyMessage(operationDescription
, delegate()
673 WebMessageBodyStyle style
= GetBodyStyle(operationDescription
);
674 bool isUntypedWhenUriParamsNotConsidered
= false;
675 Effect doBodyFormatter
= delegate()
677 if (numUriVariables
!= 0)
679 EnsureNotUntypedMessageNorMessageContract(operationDescription
);
681 // get body formatter
682 ValidateBodyParameters(operationDescription
, true);
683 IClientMessageFormatter baseFormatter
;
685 if (TryGetStreamParameterType(operationDescription
.Messages
[0], operationDescription
, true, out parameterType
))
688 baseFormatter
= new HttpStreamFormatter(operationDescription
);
690 else if (UseBareRequestFormatter(style
, operationDescription
, out parameterType
))
692 baseFormatter
= SingleBodyParameterMessageFormatter
.CreateClientFormatter(operationDescription
, parameterType
, true, useJson
, this.xmlSerializerManager
);
696 baseFormatter
= GetDefaultClientFormatter(operationDescription
, useJson
, !IsBareRequest(style
));
698 innerFormatter
= baseFormatter
;
699 isUntypedWhenUriParamsNotConsidered
= IsUntypedMessage(operationDescription
.Messages
[0]);
701 if (numUriVariables
== 0)
703 if (IsUntypedMessage(operationDescription
.Messages
[0]))
705 ValidateBodyParameters(operationDescription
, true);
706 innerFormatter
= new MessagePassthroughFormatter();
707 isUntypedWhenUriParamsNotConsidered
= true;
709 else if (IsTypedMessage(operationDescription
.Messages
[0]))
711 ValidateBodyParameters(operationDescription
, true);
712 innerFormatter
= GetDefaultClientFormatter(operationDescription
, useJson
, !IsBareRequest(style
));
721 HideRequestUriTemplateParameters(operationDescription
, throwAway
, delegate()
723 CloneMessageDescriptionsBeforeActing(operationDescription
, delegate()
729 innerFormatter
= new UriTemplateClientFormatter(operationDescription
, innerFormatter
, GetQueryStringConverter(operationDescription
), endpoint
.Address
.Uri
, isUntypedWhenUriParamsNotConsidered
, endpoint
.Contract
.Name
);
731 string defaultContentType
= GetDefaultContentType(isStream
, useJson
, webEncoding
);
732 if (!string.IsNullOrEmpty(defaultContentType
))
734 innerFormatter
= new ContentTypeSettingClientMessageFormatter(defaultContentType
, innerFormatter
);
736 return innerFormatter
;
739 protected virtual IDispatchMessageFormatter
GetRequestDispatchFormatter(OperationDescription operationDescription
, ServiceEndpoint endpoint
)
741 IDispatchMessageFormatter result
= null;
742 // get some validation errors by creating "throwAway" formatter
743 UriTemplateDispatchFormatter throwAway
= new UriTemplateDispatchFormatter(operationDescription
, null, GetQueryStringConverter(operationDescription
), endpoint
.Contract
.Name
, endpoint
.Address
.Uri
);
744 int numUriVariables
= throwAway
.pathMapping
.Count
+ throwAway
.queryMapping
.Count
;
745 HideReplyMessage(operationDescription
, delegate()
747 WebMessageBodyStyle style
= GetBodyStyle(operationDescription
);
748 Effect doBodyFormatter
= delegate()
750 if (numUriVariables
!= 0)
752 EnsureNotUntypedMessageNorMessageContract(operationDescription
);
754 // get body formatter
755 ValidateBodyParameters(operationDescription
, true);
757 if (TryGetStreamParameterType(operationDescription
.Messages
[0], operationDescription
, true, out type
))
759 result
= new HttpStreamFormatter(operationDescription
);
764 if (UseBareRequestFormatter(style
, operationDescription
, out parameterType
))
766 result
= SingleBodyParameterMessageFormatter
.CreateXmlAndJsonDispatchFormatter(operationDescription
, parameterType
, true, this.xmlSerializerManager
, this.JavascriptCallbackParameterName
);
770 result
= GetDefaultXmlAndJsonDispatchFormatter(operationDescription
, !IsBareRequest(style
));
774 if (numUriVariables
== 0)
776 if (IsUntypedMessage(operationDescription
.Messages
[0]))
778 ValidateBodyParameters(operationDescription
, true);
779 result
= new MessagePassthroughFormatter();
781 else if (IsTypedMessage(operationDescription
.Messages
[0]))
783 ValidateBodyParameters(operationDescription
, true);
784 result
= GetDefaultXmlAndJsonDispatchFormatter(operationDescription
, !IsBareRequest(style
));
793 HideRequestUriTemplateParameters(operationDescription
, throwAway
, delegate()
795 CloneMessageDescriptionsBeforeActing(operationDescription
, delegate()
801 result
= new UriTemplateDispatchFormatter(operationDescription
, result
, GetQueryStringConverter(operationDescription
), endpoint
.Contract
.Name
, endpoint
.Address
.Uri
);
806 static void CloneMessageDescriptionsBeforeActing(OperationDescription operationDescription
, Effect effect
)
808 MessageDescription originalRequest
= operationDescription
.Messages
[0];
809 bool thereIsAReply
= operationDescription
.Messages
.Count
> 1;
810 MessageDescription originalReply
= thereIsAReply
? operationDescription
.Messages
[1] : null;
811 operationDescription
.Messages
[0] = originalRequest
.Clone();
814 operationDescription
.Messages
[1] = originalReply
.Clone();
817 operationDescription
.Messages
[0] = originalRequest
;
820 operationDescription
.Messages
[1] = originalReply
;
824 internal virtual bool UseBareRequestFormatter(WebMessageBodyStyle style
, OperationDescription operationDescription
, out Type parameterType
)
826 parameterType
= null;
827 return IsBareRequest(style
) && TryGetNonMessageParameterType(operationDescription
.Messages
[0], operationDescription
, true, out parameterType
);
830 static Collection
<MessagePartDescription
> CloneParts(MessageDescription md
)
832 MessagePartDescriptionCollection bodyParameters
= md
.Body
.Parts
;
833 Collection
<MessagePartDescription
> bodyParametersClone
= new Collection
<MessagePartDescription
>();
834 for (int i
= 0; i
< bodyParameters
.Count
; ++i
)
836 MessagePartDescription copy
= bodyParameters
[i
].Clone();
837 bodyParametersClone
.Add(copy
);
839 return bodyParametersClone
;
842 static void EnsureNotUntypedMessageNorMessageContract(OperationDescription operationDescription
)
844 // Called when there are UriTemplate parameters. UT does not compose with Message
845 // or MessageContract because the SOAP and REST programming models must be uniform here.
846 bool isUnadornedWebGet
= false;
847 if (GetWebMethod(operationDescription
) == GET
&& GetWebUriTemplate(operationDescription
) == null)
849 isUnadornedWebGet
= true;
851 if (IsTypedMessage(operationDescription
.Messages
[0]))
853 if (isUnadornedWebGet
)
855 // WebGet will give you UriTemplate parameters by default.
856 // We need a special error message for this case to prevent confusion.
857 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(
858 SR2
.GetString(SR2
.GETCannotHaveMCParameter
, operationDescription
.Name
, operationDescription
.DeclaringContract
.Name
, operationDescription
.Messages
[0].MessageType
.Name
)));
862 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(SR2
.GetString(
863 SR2
.UTParamsDoNotComposeWithMessageContract
, operationDescription
.Name
, operationDescription
.DeclaringContract
.Name
)));
867 if (IsUntypedMessage(operationDescription
.Messages
[0]))
869 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(SR2
.GetString(
870 SR2
.UTParamsDoNotComposeWithMessage
, operationDescription
.Name
, operationDescription
.DeclaringContract
.Name
)));
874 static void EnsureOk(WebGetAttribute wga
, WebInvokeAttribute wia
, OperationDescription od
)
876 if (wga
!= null && wia
!= null)
878 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(
879 SR2
.GetString(SR2
.MultipleWebAttributes
, od
.Name
, od
.DeclaringContract
.Name
)));
883 static void HideReplyMessage(OperationDescription operationDescription
, Effect effect
)
885 MessageDescription temp
= null;
886 if (operationDescription
.Messages
.Count
> 1)
888 temp
= operationDescription
.Messages
[1];
889 operationDescription
.Messages
[1] = MakeDummyMessageDescription(MessageDirection
.Output
);
892 if (operationDescription
.Messages
.Count
> 1)
894 operationDescription
.Messages
[1] = temp
;
898 static void HideRequestUriTemplateParameters(OperationDescription operationDescription
, UriTemplateClientFormatter throwAway
, Effect effect
)
900 HideRequestUriTemplateParameters(operationDescription
, throwAway
.pathMapping
, throwAway
.queryMapping
, effect
);
903 internal static void HideRequestUriTemplateParameters(OperationDescription operationDescription
, UriTemplateDispatchFormatter throwAway
, Effect effect
)
905 HideRequestUriTemplateParameters(operationDescription
, throwAway
.pathMapping
, throwAway
.queryMapping
, effect
);
908 static void HideRequestUriTemplateParameters(OperationDescription operationDescription
, Dictionary
<int, string> pathMapping
, Dictionary
<int, KeyValuePair
<string, Type
>> queryMapping
, Effect effect
)
910 // mutate description to hide UriTemplate parameters
911 Collection
<MessagePartDescription
> originalParts
= CloneParts(operationDescription
.Messages
[0]);
912 Collection
<MessagePartDescription
> parts
= CloneParts(operationDescription
.Messages
[0]);
913 operationDescription
.Messages
[0].Body
.Parts
.Clear();
915 for (int i
= 0; i
< parts
.Count
; ++i
)
917 if (!pathMapping
.ContainsKey(i
) && !queryMapping
.ContainsKey(i
))
919 operationDescription
.Messages
[0].Body
.Parts
.Add(parts
[i
]);
920 parts
[i
].Index
= newIndex
++;
924 // unmutate description
925 operationDescription
.Messages
[0].Body
.Parts
.Clear();
926 for (int i
= 0; i
< originalParts
.Count
; ++i
)
928 operationDescription
.Messages
[0].Body
.Parts
.Add(originalParts
[i
]);
932 static bool IsBareRequest(WebMessageBodyStyle style
)
934 return (style
== WebMessageBodyStyle
.Bare
|| style
== WebMessageBodyStyle
.WrappedResponse
);
937 static bool IsBareResponse(WebMessageBodyStyle style
)
939 return (style
== WebMessageBodyStyle
.Bare
|| style
== WebMessageBodyStyle
.WrappedRequest
);
942 internal static bool TryGetNonMessageParameterType(MessageDescription message
, OperationDescription declaringOperation
, bool isRequest
, out Type type
)
949 if (IsTypedMessage(message
) || IsUntypedMessage(message
))
955 if (message
.Body
.Parts
.Count
> 1)
957 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(SR2
.GetString(SR2
.AtMostOneRequestBodyParameterAllowedForUnwrappedMessages
, declaringOperation
.Name
, declaringOperation
.DeclaringContract
.Name
)));
959 if (message
.Body
.Parts
.Count
== 1 && message
.Body
.Parts
[0].Type
!= typeof(void))
961 type
= message
.Body
.Parts
[0].Type
;
967 if (message
.Body
.Parts
.Count
> 0)
969 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(SR2
.GetString(SR2
.OnlyReturnValueBodyParameterAllowedForUnwrappedMessages
, declaringOperation
.Name
, declaringOperation
.DeclaringContract
.Name
)));
971 if (message
.Body
.ReturnValue
!= null && message
.Body
.ReturnValue
.Type
!= typeof(void))
973 type
= message
.Body
.ReturnValue
.Type
;
979 static bool TryGetStreamParameterType(MessageDescription message
, OperationDescription declaringOperation
, bool isRequest
, out Type type
)
982 if (message
== null || IsTypedMessage(message
) || IsUntypedMessage(message
))
988 bool hasStream
= false;
989 for (int i
= 0; i
< message
.Body
.Parts
.Count
; ++i
)
991 if (typeof(Stream
) == message
.Body
.Parts
[i
].Type
)
993 type
= message
.Body
.Parts
[i
].Type
;
999 if (hasStream
&& message
.Body
.Parts
.Count
> 1)
1001 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new ArgumentException(SR2
.GetString(SR2
.AtMostOneRequestBodyParameterAllowedForStream
, declaringOperation
.Name
, declaringOperation
.DeclaringContract
.Name
)));
1007 // validate that the stream is not an out or ref param
1008 for (int i
= 0; i
< message
.Body
.Parts
.Count
; ++i
)
1010 if (typeof(Stream
) == message
.Body
.Parts
[i
].Type
)
1012 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new ArgumentException(SR2
.GetString(SR2
.NoOutOrRefStreamParametersAllowed
, message
.Body
.Parts
[i
].Name
, declaringOperation
.Name
, declaringOperation
.DeclaringContract
.Name
)));
1015 if (message
.Body
.ReturnValue
!= null && typeof(Stream
) == message
.Body
.ReturnValue
.Type
)
1017 // validate that there are no out or ref params
1018 if (message
.Body
.Parts
.Count
> 0)
1020 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new ArgumentException(SR2
.GetString(SR2
.NoOutOrRefParametersAllowedWithStreamResult
, declaringOperation
.Name
, declaringOperation
.DeclaringContract
.Name
)));
1022 type
= message
.Body
.ReturnValue
.Type
;
1033 static void ValidateAtMostOneStreamParameter(OperationDescription operation
, bool request
)
1038 TryGetStreamParameterType(operation
.Messages
[0], operation
, true, out dummy
);
1042 if (operation
.Messages
.Count
> 1)
1044 TryGetStreamParameterType(operation
.Messages
[1], operation
, false, out dummy
);
1049 string GetDefaultContentType(bool isStream
, bool useJson
, WebMessageEncodingBindingElement webEncoding
)
1053 return defaultStreamContentType
;
1057 return JsonMessageEncoderFactory
.GetContentType(webEncoding
);
1065 IDispatchMessageFormatter
GetDefaultDispatchFormatter(OperationDescription od
, bool useJson
, bool isWrapped
)
1067 DataContractSerializerOperationBehavior dcsob
= od
.Behaviors
.Find
<DataContractSerializerOperationBehavior
>();
1072 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(SR2
.GetString(SR2
.JsonFormatRequiresDataContract
, od
.Name
, od
.DeclaringContract
.Name
, od
.DeclaringContract
.Namespace
)));
1074 return CreateDataContractJsonSerializerOperationFormatter(od
, dcsob
, isWrapped
);
1078 EndpointDispatcher dummyED
= new EndpointDispatcher(new EndpointAddress("http://localhost/"), "name", "");
1079 DispatchRuntime dispatchRuntime
= dummyED
.DispatchRuntime
;
1080 DispatchOperation dop
= new DispatchOperation(dispatchRuntime
, "dummyDispatch", "urn:dummy");
1081 dop
.Formatter
= null;
1085 (dcsob
as IOperationBehavior
).ApplyDispatchBehavior(od
, dop
);
1086 return dop
.Formatter
;
1088 XmlSerializerOperationBehavior xsob
= od
.Behaviors
.Find
<XmlSerializerOperationBehavior
>();
1091 xsob
= new XmlSerializerOperationBehavior(od
, xsob
.XmlSerializerFormatAttribute
, this.reflector
);
1092 (xsob
as IOperationBehavior
).ApplyDispatchBehavior(od
, dop
);
1093 return dop
.Formatter
;
1099 internal virtual DataContractJsonSerializerOperationFormatter
CreateDataContractJsonSerializerOperationFormatter(OperationDescription od
, DataContractSerializerOperationBehavior dcsob
, bool isWrapped
)
1101 return new DataContractJsonSerializerOperationFormatter(od
, dcsob
.MaxItemsInObjectGraph
, dcsob
.IgnoreExtensionDataObject
, dcsob
.DataContractSurrogate
, isWrapped
, false, JavascriptCallbackParameterName
);
1104 IClientMessageFormatter
GetDefaultXmlAndJsonClientFormatter(OperationDescription od
, bool isWrapped
)
1106 IClientMessageFormatter xmlFormatter
= GetDefaultClientFormatter(od
, false, isWrapped
);
1107 if (!SupportsJsonFormat(od
))
1109 return xmlFormatter
;
1111 IClientMessageFormatter jsonFormatter
= GetDefaultClientFormatter(od
, true, isWrapped
);
1112 Dictionary
<WebContentFormat
, IClientMessageFormatter
> map
= new Dictionary
<WebContentFormat
, IClientMessageFormatter
>();
1113 map
.Add(WebContentFormat
.Xml
, xmlFormatter
);
1114 map
.Add(WebContentFormat
.Json
, jsonFormatter
);
1115 // In case there is no format property, the default formatter to use is XML
1116 return new DemultiplexingClientMessageFormatter(map
, xmlFormatter
);
1119 IDispatchMessageFormatter
GetDefaultXmlAndJsonDispatchFormatter(OperationDescription od
, bool isWrapped
)
1121 IDispatchMessageFormatter xmlFormatter
= GetDefaultDispatchFormatter(od
, false, isWrapped
);
1122 if (!SupportsJsonFormat(od
))
1124 return xmlFormatter
;
1126 IDispatchMessageFormatter jsonFormatter
= GetDefaultDispatchFormatter(od
, true, isWrapped
);
1127 Dictionary
<WebContentFormat
, IDispatchMessageFormatter
> map
= new Dictionary
<WebContentFormat
, IDispatchMessageFormatter
>();
1128 map
.Add(WebContentFormat
.Xml
, xmlFormatter
);
1129 map
.Add(WebContentFormat
.Json
, jsonFormatter
);
1130 return new DemultiplexingDispatchMessageFormatter(map
, xmlFormatter
);
1133 internal WebMessageFormat
GetRequestFormat(OperationDescription od
)
1135 WebGetAttribute wga
= od
.Behaviors
.Find
<WebGetAttribute
>();
1136 WebInvokeAttribute wia
= od
.Behaviors
.Find
<WebInvokeAttribute
>();
1137 EnsureOk(wga
, wia
, od
);
1140 return wga
.IsRequestFormatSetExplicitly
? wga
.RequestFormat
: this.DefaultOutgoingRequestFormat
;
1142 else if (wia
!= null)
1144 return wia
.IsRequestFormatSetExplicitly
? wia
.RequestFormat
: this.DefaultOutgoingRequestFormat
;
1148 return this.DefaultOutgoingRequestFormat
;
1152 internal WebMessageFormat
GetResponseFormat(OperationDescription od
)
1154 WebGetAttribute wga
= od
.Behaviors
.Find
<WebGetAttribute
>();
1155 WebInvokeAttribute wia
= od
.Behaviors
.Find
<WebInvokeAttribute
>();
1156 EnsureOk(wga
, wia
, od
);
1159 return wga
.IsResponseFormatSetExplicitly
? wga
.ResponseFormat
: this.DefaultOutgoingResponseFormat
;
1161 else if (wia
!= null)
1163 return wia
.IsResponseFormatSetExplicitly
? wia
.ResponseFormat
: this.DefaultOutgoingResponseFormat
;
1167 return this.DefaultOutgoingResponseFormat
;
1171 void ValidateBodyParameters(OperationDescription operation
, bool request
)
1173 string method
= GetWebMethod(operation
);
1176 ValidateGETHasNoBody(operation
, method
);
1178 // validate that if bare is chosen for request/response, then at most 1 parameter is possible
1179 ValidateBodyStyle(operation
, request
);
1180 // validate if the request or response body is a stream, no other body parameters
1182 ValidateAtMostOneStreamParameter(operation
, request
);
1185 void ValidateBodyStyle(OperationDescription operation
, bool request
)
1187 WebMessageBodyStyle style
= GetBodyStyle(operation
);
1189 if (request
&& IsBareRequest(style
))
1191 TryGetNonMessageParameterType(operation
.Messages
[0], operation
, true, out dummy
);
1193 if (!request
&& operation
.Messages
.Count
> 1 && IsBareResponse(style
))
1195 TryGetNonMessageParameterType(operation
.Messages
[1], operation
, false, out dummy
);
1199 void ValidateGETHasNoBody(OperationDescription operation
, string method
)
1203 if (!IsUntypedMessage(operation
.Messages
[0]) && operation
.Messages
[0].Body
.Parts
.Count
!= 0)
1205 if (!IsTypedMessage(operation
.Messages
[0]))
1207 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(
1208 SR2
.GetString(SR2
.GETCannotHaveBody
, operation
.Name
, operation
.DeclaringContract
.Name
, operation
.Messages
[0].Body
.Parts
[0].Name
)));
1212 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(
1213 SR2
.GetString(SR2
.GETCannotHaveMCParameter
, operation
.Name
, operation
.DeclaringContract
.Name
, operation
.Messages
[0].MessageType
.Name
)));
1219 void ValidateContract(ServiceEndpoint endpoint
)
1221 foreach (OperationDescription od
in endpoint
.Contract
.Operations
)
1223 ValidateNoOperationHasEncodedXmlSerializer(od
);
1224 ValidateNoMessageContractHeaders(od
.Messages
[0], od
.Name
, endpoint
.Contract
.Name
);
1225 ValidateNoBareMessageContractWithMultipleParts(od
.Messages
[0], od
.Name
, endpoint
.Contract
.Name
);
1226 ValidateNoMessageContractWithStream(od
.Messages
[0], od
.Name
, endpoint
.Contract
.Name
);
1227 if (od
.Messages
.Count
> 1)
1229 ValidateNoMessageContractHeaders(od
.Messages
[1], od
.Name
, endpoint
.Contract
.Name
);
1230 ValidateNoBareMessageContractWithMultipleParts(od
.Messages
[1], od
.Name
, endpoint
.Contract
.Name
);
1231 ValidateNoMessageContractWithStream(od
.Messages
[1], od
.Name
, endpoint
.Contract
.Name
);
1236 internal static bool IsXmlSerializerFaultFormat(OperationDescription operationDescription
)
1238 XmlSerializerOperationBehavior xsob
= operationDescription
.Behaviors
.Find
<XmlSerializerOperationBehavior
>();
1239 return (xsob
!= null && xsob
.XmlSerializerFormatAttribute
.SupportFaults
);
1242 void ValidateNoMessageContractWithStream(MessageDescription md
, string opName
, string contractName
)
1244 if (IsTypedMessage(md
))
1246 foreach (MessagePartDescription description
in md
.Body
.Parts
)
1248 if (description
.Type
== typeof(Stream
))
1250 throw System
.ServiceModel
.DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(
1251 new InvalidOperationException(System
.ServiceModel
.SR2
.GetString(System
.ServiceModel
.SR2
.StreamBodyMemberNotSupported
, this.GetType().ToString(), contractName
, opName
, md
.MessageType
.ToString(), description
.Name
)));
1257 void ValidateNoOperationHasEncodedXmlSerializer(OperationDescription od
)
1259 XmlSerializerOperationBehavior xsob
= od
.Behaviors
.Find
<XmlSerializerOperationBehavior
>();
1260 if (xsob
!= null && (xsob
.XmlSerializerFormatAttribute
.Style
== OperationFormatStyle
.Rpc
|| xsob
.XmlSerializerFormatAttribute
.IsEncoded
))
1262 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(SR2
.GetString(SR2
.RpcEncodedNotSupportedForNoneMessageVersion
, od
.Name
, od
.DeclaringContract
.Name
, od
.DeclaringContract
.Namespace
)));
1266 void ValidateNoBareMessageContractWithMultipleParts(MessageDescription md
, string opName
, string contractName
)
1268 if (IsTypedMessage(md
) && md
.Body
.WrapperName
== null)
1270 if (md
.Body
.Parts
.Count
> 1)
1272 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(
1273 SR2
.GetString(SR2
.InvalidMessageContractWithoutWrapperName
, opName
, contractName
, md
.MessageType
)));
1275 if (md
.Body
.Parts
.Count
== 1 && md
.Body
.Parts
[0].Multiple
)
1277 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(SR2
.GetString(SR2
.MCAtMostOneRequestBodyParameterAllowedForUnwrappedMessages
, opName
, contractName
, md
.MessageType
)));
1282 void ValidateNoMessageContractHeaders(MessageDescription md
, string opName
, string contractName
)
1284 if (md
.Headers
.Count
!= 0)
1286 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new InvalidOperationException(
1287 SR2
.GetString(SR2
.InvalidMethodWithSOAPHeaders
, opName
, contractName
)));
1291 internal class MessagePassthroughFormatter
: IClientMessageFormatter
, IDispatchMessageFormatter
1293 public object DeserializeReply(Message message
, object[] parameters
)
1298 public void DeserializeRequest(Message message
, object[] parameters
)
1300 parameters
[0] = message
;
1303 public Message
SerializeReply(MessageVersion messageVersion
, object[] parameters
, object result
)
1305 return result
as Message
;
1308 public Message
SerializeRequest(MessageVersion messageVersion
, object[] parameters
)
1310 return parameters
[0] as Message
;
1314 static internal JavascriptCallbackResponseMessageProperty
TrySetupJavascriptCallback(string callbackParameterName
)
1316 JavascriptCallbackResponseMessageProperty javascriptProperty
= null;
1317 if (!String
.IsNullOrEmpty(callbackParameterName
) &&
1318 !OperationContext
.Current
.OutgoingMessageProperties
.TryGetValue
<JavascriptCallbackResponseMessageProperty
>(JavascriptCallbackResponseMessageProperty
.Name
, out javascriptProperty
))
1320 UriTemplateMatch match
= WebOperationContext
.Current
.IncomingRequest
.UriTemplateMatch
;
1321 if (match
!= null &&
1322 match
.QueryParameters
.AllKeys
.Contains(callbackParameterName
))
1324 string callbackName
= match
.QueryParameters
[callbackParameterName
];
1326 if (!String
.IsNullOrEmpty(callbackName
))
1328 javascriptProperty
= new JavascriptCallbackResponseMessageProperty
1330 CallbackFunctionName
= callbackName
1332 OperationContext
.Current
.OutgoingMessageProperties
.Add(JavascriptCallbackResponseMessageProperty
.Name
, javascriptProperty
);
1336 return javascriptProperty
;