2016-08-03 10:59:49 +00:00
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634 , 1691
namespace System.ServiceModel.Description
{
using System ;
using System.Collections.Generic ;
using System.Collections.ObjectModel ;
using System.ComponentModel ;
using System.IO ;
using System.Linq ;
using System.ServiceModel ;
using System.ServiceModel.Administration ;
using System.ServiceModel.Channels ;
using System.ServiceModel.Dispatcher ;
using System.ServiceModel.Web ;
public class WebHttpBehavior : IEndpointBehavior , IWmiInstanceProvider
{
internal const string GET = "GET" ;
internal const string POST = "POST" ;
internal const string WildcardAction = "*" ;
internal const string WildcardMethod = "*" ;
internal static readonly string defaultStreamContentType = "application/octet-stream" ;
internal static readonly string defaultCallbackParameterName = "callback" ;
const string AddressPropertyName = "Address" ;
WebMessageBodyStyle defaultBodyStyle ;
WebMessageFormat defaultOutgoingReplyFormat ;
WebMessageFormat defaultOutgoingRequestFormat ;
XmlSerializerOperationBehavior . Reflector reflector ;
UnwrappedTypesXmlSerializerManager xmlSerializerManager ;
public WebHttpBehavior ( )
{
defaultOutgoingRequestFormat = WebMessageFormat . Xml ;
defaultOutgoingReplyFormat = WebMessageFormat . Xml ;
this . defaultBodyStyle = WebMessageBodyStyle . Bare ;
xmlSerializerManager = new UnwrappedTypesXmlSerializerManager ( ) ;
}
internal delegate void Effect ( ) ;
public virtual WebMessageBodyStyle DefaultBodyStyle
{
get { return this . defaultBodyStyle ; }
set
{
if ( ! WebMessageBodyStyleHelper . IsDefined ( value ) )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentOutOfRangeException ( "value" ) ) ;
}
this . defaultBodyStyle = value ;
}
}
public virtual WebMessageFormat DefaultOutgoingRequestFormat
{
get
{
return this . defaultOutgoingRequestFormat ;
}
set
{
if ( ! WebMessageFormatHelper . IsDefined ( value ) )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentOutOfRangeException ( "value" ) ) ;
}
this . defaultOutgoingRequestFormat = value ;
}
}
public virtual WebMessageFormat DefaultOutgoingResponseFormat
{
get
{
return this . defaultOutgoingReplyFormat ;
}
set
{
if ( ! WebMessageFormatHelper . IsDefined ( value ) )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentOutOfRangeException ( "value" ) ) ;
}
this . defaultOutgoingReplyFormat = value ;
}
}
public virtual bool HelpEnabled { get ; set ; }
public virtual bool AutomaticFormatSelectionEnabled { get ; set ; }
public virtual bool FaultExceptionEnabled { get ; set ; }
internal Uri HelpUri { get ; set ; }
protected internal string JavascriptCallbackParameterName { get ; set ; }
public virtual void AddBindingParameters ( ServiceEndpoint endpoint , BindingParameterCollection bindingParameters )
{
// do nothing
}
public virtual void ApplyClientBehavior ( ServiceEndpoint endpoint , ClientRuntime clientRuntime )
{
if ( endpoint = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgumentNull ( "endpoint" ) ;
}
if ( clientRuntime = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgumentNull ( "clientRuntime" ) ;
}
WebMessageEncodingBindingElement webEncodingBindingElement = endpoint . Binding . CreateBindingElements ( ) . Find < WebMessageEncodingBindingElement > ( ) ;
if ( webEncodingBindingElement ! = null & & webEncodingBindingElement . CrossDomainScriptAccessEnabled )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new NotSupportedException ( SR2 . CrossDomainJavascriptNotsupported ) ) ;
}
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft, endpoint.Contract is never null
2016-08-03 10:59:49 +00:00
this . reflector = new XmlSerializerOperationBehavior . Reflector ( endpoint . Contract . Namespace , null ) ;
foreach ( OperationDescription od in endpoint . Contract . Operations )
#pragma warning restore 56506
{
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft, clientRuntime.Operations is never null
2016-08-03 10:59:49 +00:00
if ( clientRuntime . Operations . Contains ( od . Name ) )
#pragma warning restore 56506
{
ClientOperation cop = clientRuntime . Operations [ od . Name ] ;
IClientMessageFormatter requestClient = GetRequestClientFormatter ( od , endpoint ) ;
IClientMessageFormatter replyClient = GetReplyClientFormatter ( od , endpoint ) ;
cop . Formatter = new CompositeClientFormatter ( requestClient , replyClient ) ;
cop . SerializeRequest = true ;
cop . DeserializeReply = od . Messages . Count > 1 & & ! IsUntypedMessage ( od . Messages [ 1 ] ) ;
}
}
AddClientErrorInspector ( endpoint , clientRuntime ) ;
}
public virtual void ApplyDispatchBehavior ( ServiceEndpoint endpoint , EndpointDispatcher endpointDispatcher )
{
if ( endpoint = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgumentNull ( "endpoint" ) ;
}
if ( endpointDispatcher = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgumentNull ( "endpointDispatcher" ) ;
}
WebMessageEncodingBindingElement webEncodingBindingElement = endpoint . Binding . CreateBindingElements ( ) . Find < WebMessageEncodingBindingElement > ( ) ;
if ( webEncodingBindingElement ! = null & & webEncodingBindingElement . CrossDomainScriptAccessEnabled )
{
ISecurityCapabilities securityCapabilities = endpoint . Binding . GetProperty < ISecurityCapabilities > ( new BindingParameterCollection ( ) ) ;
if ( securityCapabilities . SupportsClientAuthentication )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new NotSupportedException ( SR2 . CrossDomainJavascriptAuthNotSupported ) ) ;
}
if ( endpoint . Contract . Behaviors . Contains ( typeof ( JavascriptCallbackBehaviorAttribute ) ) )
{
JavascriptCallbackBehaviorAttribute behavior = endpoint . Contract . Behaviors [ typeof ( JavascriptCallbackBehaviorAttribute ) ] as JavascriptCallbackBehaviorAttribute ;
this . JavascriptCallbackParameterName = behavior . UrlParameterName ;
}
else
{
this . JavascriptCallbackParameterName = defaultCallbackParameterName ;
}
endpointDispatcher . DispatchRuntime . MessageInspectors . Add ( new JavascriptCallbackMessageInspector ( this . JavascriptCallbackParameterName ) ) ;
}
if ( this . HelpEnabled )
{
this . HelpUri = new UriTemplate ( HelpPage . OperationListHelpPageUriTemplate ) . BindByPosition ( endpoint . ListenUri ) ;
}
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft, endpoint.Contract is never null
2016-08-03 10:59:49 +00:00
this . reflector = new XmlSerializerOperationBehavior . Reflector ( endpoint . Contract . Namespace , null ) ;
#pragma warning restore 56506
// endpoint filter
endpointDispatcher . AddressFilter = new PrefixEndpointAddressMessageFilter ( endpoint . Address ) ;
endpointDispatcher . ContractFilter = new MatchAllMessageFilter ( ) ;
// operation selector
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime is never null
2016-08-03 10:59:49 +00:00
endpointDispatcher . DispatchRuntime . OperationSelector = this . GetOperationSelector ( endpoint ) ;
#pragma warning restore 56506
// unhandled operation
string actionStarOperationName = null ;
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft, endpoint.Contract is never null
2016-08-03 10:59:49 +00:00
foreach ( OperationDescription od in endpoint . Contract . Operations )
#pragma warning restore 56506
{
if ( od . Messages [ 0 ] . Direction = = MessageDirection . Input
& & od . Messages [ 0 ] . Action = = WildcardAction )
{
actionStarOperationName = od . Name ;
break ;
}
}
if ( actionStarOperationName ! = null )
{
// WCF v1 installs any Action="*" op into UnhandledDispatchOperation, but WebHttpBehavior
// doesn't want this, so we 'move' that operation back into normal set of operations
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime.{Operations,UnhandledDispatchOperation} is never null
2016-08-03 10:59:49 +00:00
endpointDispatcher . DispatchRuntime . Operations . Add (
endpointDispatcher . DispatchRuntime . UnhandledDispatchOperation ) ;
#pragma warning restore 56506
}
FormatSelectingMessageInspector formatSelectingMessageInspector = null ;
string xmlContentType = null ;
string jsonContentType = null ;
if ( webEncodingBindingElement ! = null )
{
XmlFormatMapping xmlFormatMapping = new XmlFormatMapping ( webEncodingBindingElement . WriteEncoding , webEncodingBindingElement . ContentTypeMapper ) ;
JsonFormatMapping jsonFormatMapping = new JsonFormatMapping ( webEncodingBindingElement . WriteEncoding , webEncodingBindingElement . ContentTypeMapper ) ;
xmlContentType = xmlFormatMapping . DefaultContentType . ToString ( ) ;
jsonContentType = jsonFormatMapping . DefaultContentType . ToString ( ) ;
if ( AutomaticFormatSelectionEnabled )
{
formatSelectingMessageInspector = new FormatSelectingMessageInspector ( this , new List < MultiplexingFormatMapping > { xmlFormatMapping , jsonFormatMapping } ) ;
endpointDispatcher . DispatchRuntime . MessageInspectors . Add ( formatSelectingMessageInspector ) ;
}
}
else
{
xmlContentType = TextMessageEncoderFactory . GetContentType ( XmlFormatMapping . defaultMediaType , TextEncoderDefaults . Encoding ) ;
jsonContentType = JsonMessageEncoderFactory . GetContentType ( null ) ;
}
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation is never null
2016-08-03 10:59:49 +00:00
// always install UnhandledDispatchOperation (WebHttpDispatchOperationSelector may choose not to use it)
endpointDispatcher . DispatchRuntime . UnhandledDispatchOperation = new DispatchOperation ( endpointDispatcher . DispatchRuntime , "*" , WildcardAction , WildcardAction ) ;
endpointDispatcher . DispatchRuntime . UnhandledDispatchOperation . DeserializeRequest = false ;
endpointDispatcher . DispatchRuntime . UnhandledDispatchOperation . SerializeReply = false ;
endpointDispatcher . DispatchRuntime . UnhandledDispatchOperation . Invoker = new HttpUnhandledOperationInvoker { HelpUri = this . HelpUri } ;
#pragma warning restore 56506
// install formatters and parameter inspectors
foreach ( OperationDescription od in endpoint . Contract . Operations )
{
DispatchOperation dop = null ;
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime, DispatchRuntime.Operations are never null
2016-08-03 10:59:49 +00:00
if ( endpointDispatcher . DispatchRuntime . Operations . Contains ( od . Name ) )
#pragma warning restore 56506
{
dop = endpointDispatcher . DispatchRuntime . Operations [ od . Name ] ;
}
2017-08-21 15:34:15 +00:00
#pragma warning disable 56506 // Microsoft, endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation is never null
2016-08-03 10:59:49 +00:00
else if ( endpointDispatcher . DispatchRuntime . UnhandledDispatchOperation . Name = = od . Name )
{
dop = endpointDispatcher . DispatchRuntime . UnhandledDispatchOperation ;
}
#pragma warning restore 56506
if ( dop ! = null )
{
IDispatchMessageFormatter requestDispatch = GetRequestDispatchFormatter ( od , endpoint ) ;
IDispatchMessageFormatter replyDispatch = GetReplyDispatchFormatter ( od , endpoint ) ;
MultiplexingDispatchMessageFormatter replyDispatchAsMultiplexing = replyDispatch as MultiplexingDispatchMessageFormatter ;
if ( replyDispatchAsMultiplexing ! = null )
{
// here we are adding all default content types, despite the fact that
// some of the formatters in MultiplexingDispatchMessageFormatter might not be present
// i.e. the JSON formatter
replyDispatchAsMultiplexing . DefaultContentTypes . Add ( WebMessageFormat . Xml , xmlContentType ) ;
replyDispatchAsMultiplexing . DefaultContentTypes . Add ( WebMessageFormat . Json , jsonContentType ) ;
if ( formatSelectingMessageInspector ! = null )
{
formatSelectingMessageInspector . RegisterOperation ( od . Name , replyDispatchAsMultiplexing ) ;
}
}
dop . Formatter = new CompositeDispatchFormatter ( requestDispatch , replyDispatch ) ;
dop . FaultFormatter = new WebFaultFormatter ( dop . FaultFormatter ) ;
dop . DeserializeRequest = ( requestDispatch ! = null ) ;
dop . SerializeReply = od . Messages . Count > 1 & & ( replyDispatch ! = null ) ;
}
}
if ( this . HelpEnabled )
{
HelpPage helpPage = new HelpPage ( this , endpoint . Contract ) ;
DispatchOperation dispatchOperation = new DispatchOperation ( endpointDispatcher . DispatchRuntime , HelpOperationInvoker . OperationName , null , null )
{
DeserializeRequest = false ,
SerializeReply = false ,
Invoker = new HelpOperationInvoker ( helpPage , endpointDispatcher . DispatchRuntime . UnhandledDispatchOperation . Invoker ) ,
} ;
endpointDispatcher . DispatchRuntime . Operations . Add ( dispatchOperation ) ;
}
AddServerErrorHandlers ( endpoint , endpointDispatcher ) ;
}
internal virtual Dictionary < string , string > GetWmiProperties ( )
{
Dictionary < string , string > result = new Dictionary < string , string > ( ) ;
result . Add ( "DefaultBodyStyle" , this . DefaultBodyStyle . ToString ( ) ) ;
result . Add ( "DefaultOutgoingRequestFormat" , this . DefaultOutgoingRequestFormat . ToString ( ) ) ;
result . Add ( "DefaultOutgoingResponseFormat" , this . DefaultOutgoingResponseFormat . ToString ( ) ) ;
return result ;
}
internal virtual string GetWmiTypeName ( )
{
return "WebHttpBehavior" ;
}
void IWmiInstanceProvider . FillInstance ( IWmiInstance wmiInstance )
{
if ( wmiInstance = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgument ( "wmiInstance" ) ;
}
Dictionary < string , string > properties = this . GetWmiProperties ( ) ;
foreach ( string key in properties . Keys )
{
wmiInstance . SetProperty ( key , properties [ key ] ) ;
}
}
string IWmiInstanceProvider . GetInstanceType ( )
{
return GetWmiTypeName ( ) ;
}
public virtual void Validate ( ServiceEndpoint endpoint )
{
if ( endpoint = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgumentNull ( "endpoint" ) ;
}
ValidateNoMessageHeadersPresent ( endpoint ) ;
ValidateBinding ( endpoint ) ;
ValidateContract ( endpoint ) ;
}
void ValidateNoMessageHeadersPresent ( ServiceEndpoint endpoint )
{
if ( endpoint = = null | | endpoint . Address = = null )
{
return ;
}
EndpointAddress address = endpoint . Address ;
if ( address . Headers . Count > 0 )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR2 . GetString ( SR2 . WebHttpServiceEndpointCannotHaveMessageHeaders , address ) ) ) ;
}
}
protected virtual void ValidateBinding ( ServiceEndpoint endpoint )
{
ValidateIsWebHttpBinding ( endpoint , this . GetType ( ) . ToString ( ) ) ;
}
internal static string GetWebMethod ( OperationDescription od )
{
WebGetAttribute wga = od . Behaviors . Find < WebGetAttribute > ( ) ;
WebInvokeAttribute wia = od . Behaviors . Find < WebInvokeAttribute > ( ) ;
EnsureOk ( wga , wia , od ) ;
if ( wga ! = null )
{
return GET ;
}
else if ( wia ! = null )
{
return wia . Method ? ? POST ;
}
else
{
return POST ;
}
}
internal static string GetWebUriTemplate ( OperationDescription od )
{
// return exactly what is on the attribute
WebGetAttribute wga = od . Behaviors . Find < WebGetAttribute > ( ) ;
WebInvokeAttribute wia = od . Behaviors . Find < WebInvokeAttribute > ( ) ;
EnsureOk ( wga , wia , od ) ;
if ( wga ! = null )
{
return wga . UriTemplate ;
}
else if ( wia ! = null )
{
return wia . UriTemplate ;
}
else
{
return null ;
}
}
internal static string GetDescription ( OperationDescription od )
{
object [ ] attributes = null ;
if ( od . SyncMethod ! = null )
{
attributes = od . SyncMethod . GetCustomAttributes ( typeof ( DescriptionAttribute ) , true ) ;
}
else if ( od . BeginMethod ! = null )
{
attributes = od . BeginMethod . GetCustomAttributes ( typeof ( DescriptionAttribute ) , true ) ;
}
2018-01-24 17:04:36 +00:00
else if ( od . TaskMethod ! = null )
{
attributes = od . TaskMethod . GetCustomAttributes ( typeof ( DescriptionAttribute ) , true ) ;
}
2016-08-03 10:59:49 +00:00
if ( attributes ! = null & & attributes . Length > 0 )
{
return ( ( DescriptionAttribute ) attributes [ 0 ] ) . Description ;
}
else
{
return String . Empty ;
}
}
internal static bool IsTypedMessage ( MessageDescription message )
{
return ( message ! = null & & message . MessageType ! = null ) ;
}
internal static bool IsUntypedMessage ( MessageDescription message )
{
if ( message = = null )
{
return false ;
}
return ( message . Body . ReturnValue ! = null & & message . Body . Parts . Count = = 0 & & message . Body . ReturnValue . Type = = typeof ( Message ) ) | |
( message . Body . ReturnValue = = null & & message . Body . Parts . Count = = 1 & & message . Body . Parts [ 0 ] . Type = = typeof ( Message ) ) ;
}
internal static MessageDescription MakeDummyMessageDescription ( MessageDirection direction )
{
MessageDescription messageDescription = new MessageDescription ( "urn:dummyAction" , direction ) ;
return messageDescription ;
}
internal static bool SupportsJsonFormat ( OperationDescription od )
{
// if the type is XmlSerializable, then we cannot create a json serializer for it
DataContractSerializerOperationBehavior dcsob = od . Behaviors . Find < DataContractSerializerOperationBehavior > ( ) ;
return ( dcsob ! = null ) ;
}
internal static void ValidateIsWebHttpBinding ( ServiceEndpoint serviceEndpoint , string behaviorName )
{
Binding binding = serviceEndpoint . Binding ;
if ( binding . Scheme ! = "http" & & binding . Scheme ! = "https" )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException (
SR2 . GetString ( SR2 . WCFBindingCannotBeUsedWithUriOperationSelectorBehaviorBadScheme ,
serviceEndpoint . Contract . Name , behaviorName ) ) ) ;
}
if ( binding . MessageVersion ! = MessageVersion . None )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException (
SR2 . GetString ( SR2 . WCFBindingCannotBeUsedWithUriOperationSelectorBehaviorBadMessageVersion ,
serviceEndpoint . Address . Uri . AbsoluteUri , behaviorName ) ) ) ;
}
TransportBindingElement transportBindingElement = binding . CreateBindingElements ( ) . Find < TransportBindingElement > ( ) ;
if ( transportBindingElement ! = null & & ! transportBindingElement . ManualAddressing )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException (
SR2 . GetString ( SR2 . ManualAddressingCannotBeFalseWithTransportBindingElement ,
serviceEndpoint . Address . Uri . AbsoluteUri , behaviorName , transportBindingElement . GetType ( ) . Name ) ) ) ;
}
}
internal WebMessageBodyStyle GetBodyStyle ( OperationDescription od )
{
WebGetAttribute wga = od . Behaviors . Find < WebGetAttribute > ( ) ;
WebInvokeAttribute wia = od . Behaviors . Find < WebInvokeAttribute > ( ) ;
EnsureOk ( wga , wia , od ) ;
if ( wga ! = null )
{
return wga . GetBodyStyleOrDefault ( this . DefaultBodyStyle ) ;
}
else if ( wia ! = null )
{
return wia . GetBodyStyleOrDefault ( this . DefaultBodyStyle ) ;
}
else
{
return this . DefaultBodyStyle ;
}
}
internal IClientMessageFormatter GetDefaultClientFormatter ( OperationDescription od , bool useJson , bool isWrapped )
{
DataContractSerializerOperationBehavior dcsob = od . Behaviors . Find < DataContractSerializerOperationBehavior > ( ) ;
if ( useJson )
{
if ( dcsob = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR2 . GetString ( SR2 . JsonFormatRequiresDataContract , od . Name , od . DeclaringContract . Name , od . DeclaringContract . Namespace ) ) ) ;
}
return CreateDataContractJsonSerializerOperationFormatter ( od , dcsob , isWrapped ) ;
}
else
{
ClientRuntime clientRuntime = new ClientRuntime ( "name" , "" ) ;
ClientOperation cop = new ClientOperation ( clientRuntime , "dummyClient" , "urn:dummy" ) ;
cop . Formatter = null ;
if ( dcsob ! = null )
{
( dcsob as IOperationBehavior ) . ApplyClientBehavior ( od , cop ) ;
return cop . Formatter ;
}
XmlSerializerOperationBehavior xsob = od . Behaviors . Find < XmlSerializerOperationBehavior > ( ) ;
if ( xsob ! = null )
{
xsob = new XmlSerializerOperationBehavior ( od , xsob . XmlSerializerFormatAttribute , this . reflector ) ;
( xsob as IOperationBehavior ) . ApplyClientBehavior ( od , cop ) ;
return cop . Formatter ;
}
}
return null ;
}
protected virtual void AddClientErrorInspector ( ServiceEndpoint endpoint , ClientRuntime clientRuntime )
{
if ( ! this . FaultExceptionEnabled )
{
clientRuntime . MessageInspectors . Add ( new WebFaultClientMessageInspector ( ) ) ;
}
else
{
clientRuntime . MessageVersionNoneFaultsEnabled = true ;
}
}
protected virtual void AddServerErrorHandlers ( ServiceEndpoint endpoint , EndpointDispatcher endpointDispatcher )
{
if ( ! this . FaultExceptionEnabled )
{
WebErrorHandler errorHandler = new WebErrorHandler ( this , endpoint . Contract , endpointDispatcher . DispatchRuntime . ChannelDispatcher . IncludeExceptionDetailInFaults ) ;
endpointDispatcher . DispatchRuntime . ChannelDispatcher . ErrorHandlers . Add ( errorHandler ) ;
}
}
protected virtual WebHttpDispatchOperationSelector GetOperationSelector ( ServiceEndpoint endpoint )
{
return new WebHttpDispatchOperationSelector ( endpoint ) ;
}
protected virtual QueryStringConverter GetQueryStringConverter ( OperationDescription operationDescription )
{
return new QueryStringConverter ( ) ;
}
protected virtual IClientMessageFormatter GetReplyClientFormatter ( OperationDescription operationDescription , ServiceEndpoint endpoint )
{
if ( operationDescription . Messages . Count < 2 )
{
return null ;
}
ValidateBodyParameters ( operationDescription , false ) ;
Type type ;
if ( TryGetStreamParameterType ( operationDescription . Messages [ 1 ] , operationDescription , false , out type ) )
{
return new HttpStreamFormatter ( operationDescription ) ;
}
if ( IsUntypedMessage ( operationDescription . Messages [ 1 ] ) )
{
return new MessagePassthroughFormatter ( ) ;
}
WebMessageBodyStyle style = GetBodyStyle ( operationDescription ) ;
Type parameterType ;
if ( UseBareReplyFormatter ( style , operationDescription , GetResponseFormat ( operationDescription ) , out parameterType ) )
{
return SingleBodyParameterMessageFormatter . CreateXmlAndJsonClientFormatter ( operationDescription , parameterType , false , this . xmlSerializerManager ) ;
}
else
{
MessageDescription temp = operationDescription . Messages [ 0 ] ;
operationDescription . Messages [ 0 ] = MakeDummyMessageDescription ( MessageDirection . Input ) ;
IClientMessageFormatter result ;
result = GetDefaultXmlAndJsonClientFormatter ( operationDescription , ! IsBareResponse ( style ) ) ;
operationDescription . Messages [ 0 ] = temp ;
return result ;
}
}
internal virtual bool UseBareReplyFormatter ( WebMessageBodyStyle style , OperationDescription operationDescription , WebMessageFormat responseFormat , out Type parameterType )
{
parameterType = null ;
return IsBareResponse ( style ) & & TryGetNonMessageParameterType ( operationDescription . Messages [ 1 ] , operationDescription , false , out parameterType ) ;
}
protected virtual IDispatchMessageFormatter GetReplyDispatchFormatter ( OperationDescription operationDescription , ServiceEndpoint endpoint )
{
if ( operationDescription . Messages . Count < 2 )
{
return null ;
}
ValidateBodyParameters ( operationDescription , false ) ;
WebMessageFormat responseFormat = GetResponseFormat ( operationDescription ) ;
// Determine if we should add a json formatter; If the ResponseFormat is json, we always add the json formatter even if the
2017-08-21 15:34:15 +00:00
// operation is XmlSerializerFormat because the formatter constructor throws the exception: "json not valid with XmlSerializerFormat" [Microsoft]
2016-08-03 10:59:49 +00:00
bool useJson = ( responseFormat = = WebMessageFormat . Json | | SupportsJsonFormat ( operationDescription ) ) ;
IDispatchMessageFormatter innerFormatter ;
Type type ;
if ( TryGetStreamParameterType ( operationDescription . Messages [ 1 ] , operationDescription , false , out type ) )
{
innerFormatter = new ContentTypeSettingDispatchMessageFormatter ( defaultStreamContentType , new HttpStreamFormatter ( operationDescription ) ) ;
}
else if ( IsUntypedMessage ( operationDescription . Messages [ 1 ] ) )
{
innerFormatter = new MessagePassthroughFormatter ( ) ;
}
else
{
Type parameterType ;
WebMessageBodyStyle style = GetBodyStyle ( operationDescription ) ;
Dictionary < WebMessageFormat , IDispatchMessageFormatter > formatters = new Dictionary < WebMessageFormat , IDispatchMessageFormatter > ( ) ;
if ( UseBareReplyFormatter ( style , operationDescription , responseFormat , out parameterType ) )
{
formatters . Add ( WebMessageFormat . Xml , SingleBodyParameterMessageFormatter . CreateDispatchFormatter ( operationDescription , parameterType , false , false , this . xmlSerializerManager , null ) ) ;
if ( useJson )
{
formatters . Add ( WebMessageFormat . Json , SingleBodyParameterMessageFormatter . CreateDispatchFormatter ( operationDescription , parameterType , false , true , this . xmlSerializerManager , this . JavascriptCallbackParameterName ) ) ;
}
}
else
{
MessageDescription temp = operationDescription . Messages [ 0 ] ;
operationDescription . Messages [ 0 ] = MakeDummyMessageDescription ( MessageDirection . Input ) ;
formatters . Add ( WebMessageFormat . Xml , GetDefaultDispatchFormatter ( operationDescription , false , ! IsBareResponse ( style ) ) ) ;
if ( useJson )
{
formatters . Add ( WebMessageFormat . Json , GetDefaultDispatchFormatter ( operationDescription , true , ! IsBareResponse ( style ) ) ) ;
}
operationDescription . Messages [ 0 ] = temp ;
}
innerFormatter = new MultiplexingDispatchMessageFormatter ( formatters , responseFormat ) ;
}
return innerFormatter ;
}
protected virtual IClientMessageFormatter GetRequestClientFormatter ( OperationDescription operationDescription , ServiceEndpoint endpoint )
{
WebMessageFormat requestFormat = GetRequestFormat ( operationDescription ) ;
bool useJson = ( requestFormat = = WebMessageFormat . Json ) ;
WebMessageEncodingBindingElement webEncoding = ( useJson ) ? endpoint . Binding . CreateBindingElements ( ) . Find < WebMessageEncodingBindingElement > ( ) : null ;
IClientMessageFormatter innerFormatter = null ;
// get some validation errors by creating "throwAway" formatter
// validate that endpoint.Address is not null before accessing the endpoint.Address.Uri. This is to avoid throwing a NullRefException while constructing a UriTemplateClientFormatter
if ( endpoint . Address = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException (
SR2 . GetString ( SR2 . ServiceEndpointMustHaveNonNullAddress , typeof ( ServiceEndpoint ) , typeof ( ChannelFactory ) , typeof ( WebHttpEndpoint ) , AddressPropertyName , typeof ( ServiceEndpoint ) ) ) ) ;
}
UriTemplateClientFormatter throwAway = new UriTemplateClientFormatter ( operationDescription , null , GetQueryStringConverter ( operationDescription ) , endpoint . Address . Uri , false , endpoint . Contract . Name ) ;
int numUriVariables = throwAway . pathMapping . Count + throwAway . queryMapping . Count ;
bool isStream = false ;
HideReplyMessage ( operationDescription , delegate ( )
{
WebMessageBodyStyle style = GetBodyStyle ( operationDescription ) ;
bool isUntypedWhenUriParamsNotConsidered = false ;
Effect doBodyFormatter = delegate ( )
{
if ( numUriVariables ! = 0 )
{
EnsureNotUntypedMessageNorMessageContract ( operationDescription ) ;
}
// get body formatter
ValidateBodyParameters ( operationDescription , true ) ;
IClientMessageFormatter baseFormatter ;
Type parameterType ;
if ( TryGetStreamParameterType ( operationDescription . Messages [ 0 ] , operationDescription , true , out parameterType ) )
{
isStream = true ;
baseFormatter = new HttpStreamFormatter ( operationDescription ) ;
}
else if ( UseBareRequestFormatter ( style , operationDescription , out parameterType ) )
{
baseFormatter = SingleBodyParameterMessageFormatter . CreateClientFormatter ( operationDescription , parameterType , true , useJson , this . xmlSerializerManager ) ;
}
else
{
baseFormatter = GetDefaultClientFormatter ( operationDescription , useJson , ! IsBareRequest ( style ) ) ;
}
innerFormatter = baseFormatter ;
isUntypedWhenUriParamsNotConsidered = IsUntypedMessage ( operationDescription . Messages [ 0 ] ) ;
} ;
if ( numUriVariables = = 0 )
{
if ( IsUntypedMessage ( operationDescription . Messages [ 0 ] ) )
{
ValidateBodyParameters ( operationDescription , true ) ;
innerFormatter = new MessagePassthroughFormatter ( ) ;
isUntypedWhenUriParamsNotConsidered = true ;
}
else if ( IsTypedMessage ( operationDescription . Messages [ 0 ] ) )
{
ValidateBodyParameters ( operationDescription , true ) ;
innerFormatter = GetDefaultClientFormatter ( operationDescription , useJson , ! IsBareRequest ( style ) ) ;
}
else
{
doBodyFormatter ( ) ;
}
}
else
{
HideRequestUriTemplateParameters ( operationDescription , throwAway , delegate ( )
{
CloneMessageDescriptionsBeforeActing ( operationDescription , delegate ( )
{
doBodyFormatter ( ) ;
} ) ;
} ) ;
}
innerFormatter = new UriTemplateClientFormatter ( operationDescription , innerFormatter , GetQueryStringConverter ( operationDescription ) , endpoint . Address . Uri , isUntypedWhenUriParamsNotConsidered , endpoint . Contract . Name ) ;
} ) ;
string defaultContentType = GetDefaultContentType ( isStream , useJson , webEncoding ) ;
if ( ! string . IsNullOrEmpty ( defaultContentType ) )
{
innerFormatter = new ContentTypeSettingClientMessageFormatter ( defaultContentType , innerFormatter ) ;
}
return innerFormatter ;
}
protected virtual IDispatchMessageFormatter GetRequestDispatchFormatter ( OperationDescription operationDescription , ServiceEndpoint endpoint )
{
IDispatchMessageFormatter result = null ;
// get some validation errors by creating "throwAway" formatter
UriTemplateDispatchFormatter throwAway = new UriTemplateDispatchFormatter ( operationDescription , null , GetQueryStringConverter ( operationDescription ) , endpoint . Contract . Name , endpoint . Address . Uri ) ;
int numUriVariables = throwAway . pathMapping . Count + throwAway . queryMapping . Count ;
HideReplyMessage ( operationDescription , delegate ( )
{
WebMessageBodyStyle style = GetBodyStyle ( operationDescription ) ;
Effect doBodyFormatter = delegate ( )
{
if ( numUriVariables ! = 0 )
{
EnsureNotUntypedMessageNorMessageContract ( operationDescription ) ;
}
// get body formatter
ValidateBodyParameters ( operationDescription , true ) ;
Type type ;
if ( TryGetStreamParameterType ( operationDescription . Messages [ 0 ] , operationDescription , true , out type ) )
{
result = new HttpStreamFormatter ( operationDescription ) ;
}
else
{
Type parameterType ;
if ( UseBareRequestFormatter ( style , operationDescription , out parameterType ) )
{
result = SingleBodyParameterMessageFormatter . CreateXmlAndJsonDispatchFormatter ( operationDescription , parameterType , true , this . xmlSerializerManager , this . JavascriptCallbackParameterName ) ;
}
else
{
result = GetDefaultXmlAndJsonDispatchFormatter ( operationDescription , ! IsBareRequest ( style ) ) ;
}
}
} ;
if ( numUriVariables = = 0 )
{
if ( IsUntypedMessage ( operationDescription . Messages [ 0 ] ) )
{
ValidateBodyParameters ( operationDescription , true ) ;
result = new MessagePassthroughFormatter ( ) ;
}
else if ( IsTypedMessage ( operationDescription . Messages [ 0 ] ) )
{
ValidateBodyParameters ( operationDescription , true ) ;
result = GetDefaultXmlAndJsonDispatchFormatter ( operationDescription , ! IsBareRequest ( style ) ) ;
}
else
{
doBodyFormatter ( ) ;
}
}
else
{
HideRequestUriTemplateParameters ( operationDescription , throwAway , delegate ( )
{
CloneMessageDescriptionsBeforeActing ( operationDescription , delegate ( )
{
doBodyFormatter ( ) ;
} ) ;
} ) ;
}
result = new UriTemplateDispatchFormatter ( operationDescription , result , GetQueryStringConverter ( operationDescription ) , endpoint . Contract . Name , endpoint . Address . Uri ) ;
} ) ;
return result ;
}
static void CloneMessageDescriptionsBeforeActing ( OperationDescription operationDescription , Effect effect )
{
MessageDescription originalRequest = operationDescription . Messages [ 0 ] ;
bool thereIsAReply = operationDescription . Messages . Count > 1 ;
MessageDescription originalReply = thereIsAReply ? operationDescription . Messages [ 1 ] : null ;
operationDescription . Messages [ 0 ] = originalRequest . Clone ( ) ;
if ( thereIsAReply )
{
operationDescription . Messages [ 1 ] = originalReply . Clone ( ) ;
}
effect ( ) ;
operationDescription . Messages [ 0 ] = originalRequest ;
if ( thereIsAReply )
{
operationDescription . Messages [ 1 ] = originalReply ;
}
}
internal virtual bool UseBareRequestFormatter ( WebMessageBodyStyle style , OperationDescription operationDescription , out Type parameterType )
{
parameterType = null ;
return IsBareRequest ( style ) & & TryGetNonMessageParameterType ( operationDescription . Messages [ 0 ] , operationDescription , true , out parameterType ) ;
}
static Collection < MessagePartDescription > CloneParts ( MessageDescription md )
{
MessagePartDescriptionCollection bodyParameters = md . Body . Parts ;
Collection < MessagePartDescription > bodyParametersClone = new Collection < MessagePartDescription > ( ) ;
for ( int i = 0 ; i < bodyParameters . Count ; + + i )
{
MessagePartDescription copy = bodyParameters [ i ] . Clone ( ) ;
bodyParametersClone . Add ( copy ) ;
}
return bodyParametersClone ;
}
static void EnsureNotUntypedMessageNorMessageContract ( OperationDescription operationDescription )
{
// Called when there are UriTemplate parameters. UT does not compose with Message
// or MessageContract because the SOAP and REST programming models must be uniform here.
bool isUnadornedWebGet = false ;
if ( GetWebMethod ( operationDescription ) = = GET & & GetWebUriTemplate ( operationDescription ) = = null )
{
isUnadornedWebGet = true ;
}
if ( IsTypedMessage ( operationDescription . Messages [ 0 ] ) )
{
if ( isUnadornedWebGet )
{
// WebGet will give you UriTemplate parameters by default.
// We need a special error message for this case to prevent confusion.
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException (
SR2 . GetString ( SR2 . GETCannotHaveMCParameter , operationDescription . Name , operationDescription . DeclaringContract . Name , operationDescription . Messages [ 0 ] . MessageType . Name ) ) ) ;
}
else
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR2 . GetString (
SR2 . UTParamsDoNotComposeWithMessageContract , operationDescription . Name , operationDescription . DeclaringContract . Name ) ) ) ;
}
}
if ( IsUntypedMessage ( operationDescription . Messages [ 0 ] ) )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR2 . GetString (
SR2 . UTParamsDoNotComposeWithMessage , operationDescription . Name , operationDescription . DeclaringContract . Name ) ) ) ;
}
}
static void EnsureOk ( WebGetAttribute wga , WebInvokeAttribute wia , OperationDescription od )
{
if ( wga ! = null & & wia ! = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException (
SR2 . GetString ( SR2 . MultipleWebAttributes , od . Name , od . DeclaringContract . Name ) ) ) ;
}
}
static void HideReplyMessage ( OperationDescription operationDescription , Effect effect )
{
MessageDescription temp = null ;
if ( operationDescription . Messages . Count > 1 )
{
temp = operationDescription . Messages [ 1 ] ;
operationDescription . Messages [ 1 ] = MakeDummyMessageDescription ( MessageDirection . Output ) ;
}
effect ( ) ;
if ( operationDescription . Messages . Count > 1 )
{
operationDescription . Messages [ 1 ] = temp ;
}
}
static void HideRequestUriTemplateParameters ( OperationDescription operationDescription , UriTemplateClientFormatter throwAway , Effect effect )
{
HideRequestUriTemplateParameters ( operationDescription , throwAway . pathMapping , throwAway . queryMapping , effect ) ;
}
internal static void HideRequestUriTemplateParameters ( OperationDescription operationDescription , UriTemplateDispatchFormatter throwAway , Effect effect )
{
HideRequestUriTemplateParameters ( operationDescription , throwAway . pathMapping , throwAway . queryMapping , effect ) ;
}
static void HideRequestUriTemplateParameters ( OperationDescription operationDescription , Dictionary < int , string > pathMapping , Dictionary < int , KeyValuePair < string , Type > > queryMapping , Effect effect )
{
// mutate description to hide UriTemplate parameters
Collection < MessagePartDescription > originalParts = CloneParts ( operationDescription . Messages [ 0 ] ) ;
Collection < MessagePartDescription > parts = CloneParts ( operationDescription . Messages [ 0 ] ) ;
operationDescription . Messages [ 0 ] . Body . Parts . Clear ( ) ;
int newIndex = 0 ;
for ( int i = 0 ; i < parts . Count ; + + i )
{
if ( ! pathMapping . ContainsKey ( i ) & & ! queryMapping . ContainsKey ( i ) )
{
operationDescription . Messages [ 0 ] . Body . Parts . Add ( parts [ i ] ) ;
parts [ i ] . Index = newIndex + + ;
}
}
effect ( ) ;
// unmutate description
operationDescription . Messages [ 0 ] . Body . Parts . Clear ( ) ;
for ( int i = 0 ; i < originalParts . Count ; + + i )
{
operationDescription . Messages [ 0 ] . Body . Parts . Add ( originalParts [ i ] ) ;
}
}
static bool IsBareRequest ( WebMessageBodyStyle style )
{
return ( style = = WebMessageBodyStyle . Bare | | style = = WebMessageBodyStyle . WrappedResponse ) ;
}
static bool IsBareResponse ( WebMessageBodyStyle style )
{
return ( style = = WebMessageBodyStyle . Bare | | style = = WebMessageBodyStyle . WrappedRequest ) ;
}
internal static bool TryGetNonMessageParameterType ( MessageDescription message , OperationDescription declaringOperation , bool isRequest , out Type type )
{
type = null ;
if ( message = = null )
{
return true ;
}
if ( IsTypedMessage ( message ) | | IsUntypedMessage ( message ) )
{
return false ;
}
if ( isRequest )
{
if ( message . Body . Parts . Count > 1 )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR2 . GetString ( SR2 . AtMostOneRequestBodyParameterAllowedForUnwrappedMessages , declaringOperation . Name , declaringOperation . DeclaringContract . Name ) ) ) ;
}
if ( message . Body . Parts . Count = = 1 & & message . Body . Parts [ 0 ] . Type ! = typeof ( void ) )
{
type = message . Body . Parts [ 0 ] . Type ;
}
return true ;
}
else
{
if ( message . Body . Parts . Count > 0 )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR2 . GetString ( SR2 . OnlyReturnValueBodyParameterAllowedForUnwrappedMessages , declaringOperation . Name , declaringOperation . DeclaringContract . Name ) ) ) ;
}
if ( message . Body . ReturnValue ! = null & & message . Body . ReturnValue . Type ! = typeof ( void ) )
{
type = message . Body . ReturnValue . Type ;
}
return true ;
}
}
static bool TryGetStreamParameterType ( MessageDescription message , OperationDescription declaringOperation , bool isRequest , out Type type )
{
type = null ;
if ( message = = null | | IsTypedMessage ( message ) | | IsUntypedMessage ( message ) )
{
return false ;
}
if ( isRequest )
{
bool hasStream = false ;
for ( int i = 0 ; i < message . Body . Parts . Count ; + + i )
{
if ( typeof ( Stream ) = = message . Body . Parts [ i ] . Type )
{
type = message . Body . Parts [ i ] . Type ;
hasStream = true ;
break ;
}
}
if ( hasStream & & message . Body . Parts . Count > 1 )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentException ( SR2 . GetString ( SR2 . AtMostOneRequestBodyParameterAllowedForStream , declaringOperation . Name , declaringOperation . DeclaringContract . Name ) ) ) ;
}
return hasStream ;
}
else
{
// validate that the stream is not an out or ref param
for ( int i = 0 ; i < message . Body . Parts . Count ; + + i )
{
if ( typeof ( Stream ) = = message . Body . Parts [ i ] . Type )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentException ( SR2 . GetString ( SR2 . NoOutOrRefStreamParametersAllowed , message . Body . Parts [ i ] . Name , declaringOperation . Name , declaringOperation . DeclaringContract . Name ) ) ) ;
}
}
if ( message . Body . ReturnValue ! = null & & typeof ( Stream ) = = message . Body . ReturnValue . Type )
{
// validate that there are no out or ref params
if ( message . Body . Parts . Count > 0 )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentException ( SR2 . GetString ( SR2 . NoOutOrRefParametersAllowedWithStreamResult , declaringOperation . Name , declaringOperation . DeclaringContract . Name ) ) ) ;
}
type = message . Body . ReturnValue . Type ;
return true ;
}
else
{
return false ;
}
}
}
static void ValidateAtMostOneStreamParameter ( OperationDescription operation , bool request )
{
Type dummy ;
if ( request )
{
TryGetStreamParameterType ( operation . Messages [ 0 ] , operation , true , out dummy ) ;
}
else
{
if ( operation . Messages . Count > 1 )
{
TryGetStreamParameterType ( operation . Messages [ 1 ] , operation , false , out dummy ) ;
}
}
}
string GetDefaultContentType ( bool isStream , bool useJson , WebMessageEncodingBindingElement webEncoding )
{
if ( isStream )
{
return defaultStreamContentType ;
}
else if ( useJson )
{
return JsonMessageEncoderFactory . GetContentType ( webEncoding ) ;
}
else
{
return null ;
}
}
IDispatchMessageFormatter GetDefaultDispatchFormatter ( OperationDescription od , bool useJson , bool isWrapped )
{
DataContractSerializerOperationBehavior dcsob = od . Behaviors . Find < DataContractSerializerOperationBehavior > ( ) ;
if ( useJson )
{
if ( dcsob = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR2 . GetString ( SR2 . JsonFormatRequiresDataContract , od . Name , od . DeclaringContract . Name , od . DeclaringContract . Namespace ) ) ) ;
}
return CreateDataContractJsonSerializerOperationFormatter ( od , dcsob , isWrapped ) ;
}
else
{
EndpointDispatcher dummyED = new EndpointDispatcher ( new EndpointAddress ( "http://localhost/" ) , "name" , "" ) ;
DispatchRuntime dispatchRuntime = dummyED . DispatchRuntime ;
DispatchOperation dop = new DispatchOperation ( dispatchRuntime , "dummyDispatch" , "urn:dummy" ) ;
dop . Formatter = null ;
if ( dcsob ! = null )
{
( dcsob as IOperationBehavior ) . ApplyDispatchBehavior ( od , dop ) ;
return dop . Formatter ;
}
XmlSerializerOperationBehavior xsob = od . Behaviors . Find < XmlSerializerOperationBehavior > ( ) ;
if ( xsob ! = null )
{
xsob = new XmlSerializerOperationBehavior ( od , xsob . XmlSerializerFormatAttribute , this . reflector ) ;
( xsob as IOperationBehavior ) . ApplyDispatchBehavior ( od , dop ) ;
return dop . Formatter ;
}
}
return null ;
}
internal virtual DataContractJsonSerializerOperationFormatter CreateDataContractJsonSerializerOperationFormatter ( OperationDescription od , DataContractSerializerOperationBehavior dcsob , bool isWrapped )
{
return new DataContractJsonSerializerOperationFormatter ( od , dcsob . MaxItemsInObjectGraph , dcsob . IgnoreExtensionDataObject , dcsob . DataContractSurrogate , isWrapped , false , JavascriptCallbackParameterName ) ;
}
IClientMessageFormatter GetDefaultXmlAndJsonClientFormatter ( OperationDescription od , bool isWrapped )
{
IClientMessageFormatter xmlFormatter = GetDefaultClientFormatter ( od , false , isWrapped ) ;
if ( ! SupportsJsonFormat ( od ) )
{
return xmlFormatter ;
}
IClientMessageFormatter jsonFormatter = GetDefaultClientFormatter ( od , true , isWrapped ) ;
Dictionary < WebContentFormat , IClientMessageFormatter > map = new Dictionary < WebContentFormat , IClientMessageFormatter > ( ) ;
map . Add ( WebContentFormat . Xml , xmlFormatter ) ;
map . Add ( WebContentFormat . Json , jsonFormatter ) ;
// In case there is no format property, the default formatter to use is XML
return new DemultiplexingClientMessageFormatter ( map , xmlFormatter ) ;
}
IDispatchMessageFormatter GetDefaultXmlAndJsonDispatchFormatter ( OperationDescription od , bool isWrapped )
{
IDispatchMessageFormatter xmlFormatter = GetDefaultDispatchFormatter ( od , false , isWrapped ) ;
if ( ! SupportsJsonFormat ( od ) )
{
return xmlFormatter ;
}
IDispatchMessageFormatter jsonFormatter = GetDefaultDispatchFormatter ( od , true , isWrapped ) ;
Dictionary < WebContentFormat , IDispatchMessageFormatter > map = new Dictionary < WebContentFormat , IDispatchMessageFormatter > ( ) ;
map . Add ( WebContentFormat . Xml , xmlFormatter ) ;
map . Add ( WebContentFormat . Json , jsonFormatter ) ;
return new DemultiplexingDispatchMessageFormatter ( map , xmlFormatter ) ;
}
internal WebMessageFormat GetRequestFormat ( OperationDescription od )
{
WebGetAttribute wga = od . Behaviors . Find < WebGetAttribute > ( ) ;
WebInvokeAttribute wia = od . Behaviors . Find < WebInvokeAttribute > ( ) ;
EnsureOk ( wga , wia , od ) ;
if ( wga ! = null )
{
return wga . IsRequestFormatSetExplicitly ? wga . RequestFormat : this . DefaultOutgoingRequestFormat ;
}
else if ( wia ! = null )
{
return wia . IsRequestFormatSetExplicitly ? wia . RequestFormat : this . DefaultOutgoingRequestFormat ;
}
else
{
return this . DefaultOutgoingRequestFormat ;
}
}
internal WebMessageFormat GetResponseFormat ( OperationDescription od )
{
WebGetAttribute wga = od . Behaviors . Find < WebGetAttribute > ( ) ;
WebInvokeAttribute wia = od . Behaviors . Find < WebInvokeAttribute > ( ) ;
EnsureOk ( wga , wia , od ) ;
if ( wga ! = null )
{
return wga . IsResponseFormatSetExplicitly ? wga . ResponseFormat : this . DefaultOutgoingResponseFormat ;
}
else if ( wia ! = null )
{
return wia . IsResponseFormatSetExplicitly ? wia . ResponseFormat : this . DefaultOutgoingResponseFormat ;
}
else
{
return this . DefaultOutgoingResponseFormat ;
}
}
void ValidateBodyParameters ( OperationDescription operation , bool request )
{
string method = GetWebMethod ( operation ) ;
if ( request )
{
ValidateGETHasNoBody ( operation , method ) ;
}
// validate that if bare is chosen for request/response, then at most 1 parameter is possible
ValidateBodyStyle ( operation , request ) ;
// validate if the request or response body is a stream, no other body parameters
// can be specified
ValidateAtMostOneStreamParameter ( operation , request ) ;
}
void ValidateBodyStyle ( OperationDescription operation , bool request )
{
WebMessageBodyStyle style = GetBodyStyle ( operation ) ;
Type dummy ;
if ( request & & IsBareRequest ( style ) )
{
TryGetNonMessageParameterType ( operation . Messages [ 0 ] , operation , true , out dummy ) ;
}
if ( ! request & & operation . Messages . Count > 1 & & IsBareResponse ( style ) )
{
TryGetNonMessageParameterType ( operation . Messages [ 1 ] , operation , false , out dummy ) ;
}
}
void ValidateGETHasNoBody ( OperationDescription operation , string method )
{
if ( method = = GET )
{
if ( ! IsUntypedMessage ( operation . Messages [ 0 ] ) & & operation . Messages [ 0 ] . Body . Parts . Count ! = 0 )
{
if ( ! IsTypedMessage ( operation . Messages [ 0 ] ) )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException (
SR2 . GetString ( SR2 . GETCannotHaveBody , operation . Name , operation . DeclaringContract . Name , operation . Messages [ 0 ] . Body . Parts [ 0 ] . Name ) ) ) ;
}
else
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException (
SR2 . GetString ( SR2 . GETCannotHaveMCParameter , operation . Name , operation . DeclaringContract . Name , operation . Messages [ 0 ] . MessageType . Name ) ) ) ;
}
}
}
}
void ValidateContract ( ServiceEndpoint endpoint )
{
foreach ( OperationDescription od in endpoint . Contract . Operations )
{
ValidateNoOperationHasEncodedXmlSerializer ( od ) ;
ValidateNoMessageContractHeaders ( od . Messages [ 0 ] , od . Name , endpoint . Contract . Name ) ;
ValidateNoBareMessageContractWithMultipleParts ( od . Messages [ 0 ] , od . Name , endpoint . Contract . Name ) ;
ValidateNoMessageContractWithStream ( od . Messages [ 0 ] , od . Name , endpoint . Contract . Name ) ;
if ( od . Messages . Count > 1 )
{
ValidateNoMessageContractHeaders ( od . Messages [ 1 ] , od . Name , endpoint . Contract . Name ) ;
ValidateNoBareMessageContractWithMultipleParts ( od . Messages [ 1 ] , od . Name , endpoint . Contract . Name ) ;
ValidateNoMessageContractWithStream ( od . Messages [ 1 ] , od . Name , endpoint . Contract . Name ) ;
}
}
}
internal static bool IsXmlSerializerFaultFormat ( OperationDescription operationDescription )
{
XmlSerializerOperationBehavior xsob = operationDescription . Behaviors . Find < XmlSerializerOperationBehavior > ( ) ;
return ( xsob ! = null & & xsob . XmlSerializerFormatAttribute . SupportFaults ) ;
}
void ValidateNoMessageContractWithStream ( MessageDescription md , string opName , string contractName )
{
if ( IsTypedMessage ( md ) )
{
foreach ( MessagePartDescription description in md . Body . Parts )
{
if ( description . Type = = typeof ( Stream ) )
{
throw System . ServiceModel . DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new InvalidOperationException ( System . ServiceModel . SR2 . GetString ( System . ServiceModel . SR2 . StreamBodyMemberNotSupported , this . GetType ( ) . ToString ( ) , contractName , opName , md . MessageType . ToString ( ) , description . Name ) ) ) ;
}
}
}
}
void ValidateNoOperationHasEncodedXmlSerializer ( OperationDescription od )
{
XmlSerializerOperationBehavior xsob = od . Behaviors . Find < XmlSerializerOperationBehavior > ( ) ;
if ( xsob ! = null & & ( xsob . XmlSerializerFormatAttribute . Style = = OperationFormatStyle . Rpc | | xsob . XmlSerializerFormatAttribute . IsEncoded ) )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR2 . GetString ( SR2 . RpcEncodedNotSupportedForNoneMessageVersion , od . Name , od . DeclaringContract . Name , od . DeclaringContract . Namespace ) ) ) ;
}
}
void ValidateNoBareMessageContractWithMultipleParts ( MessageDescription md , string opName , string contractName )
{
if ( IsTypedMessage ( md ) & & md . Body . WrapperName = = null )
{
if ( md . Body . Parts . Count > 1 )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException (
SR2 . GetString ( SR2 . InvalidMessageContractWithoutWrapperName , opName , contractName , md . MessageType ) ) ) ;
}
if ( md . Body . Parts . Count = = 1 & & md . Body . Parts [ 0 ] . Multiple )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR2 . GetString ( SR2 . MCAtMostOneRequestBodyParameterAllowedForUnwrappedMessages , opName , contractName , md . MessageType ) ) ) ;
}
}
}
void ValidateNoMessageContractHeaders ( MessageDescription md , string opName , string contractName )
{
if ( md . Headers . Count ! = 0 )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException (
SR2 . GetString ( SR2 . InvalidMethodWithSOAPHeaders , opName , contractName ) ) ) ;
}
}
internal class MessagePassthroughFormatter : IClientMessageFormatter , IDispatchMessageFormatter
{
public object DeserializeReply ( Message message , object [ ] parameters )
{
return message ;
}
public void DeserializeRequest ( Message message , object [ ] parameters )
{
parameters [ 0 ] = message ;
}
public Message SerializeReply ( MessageVersion messageVersion , object [ ] parameters , object result )
{
return result as Message ;
}
public Message SerializeRequest ( MessageVersion messageVersion , object [ ] parameters )
{
return parameters [ 0 ] as Message ;
}
}
static internal JavascriptCallbackResponseMessageProperty TrySetupJavascriptCallback ( string callbackParameterName )
{
JavascriptCallbackResponseMessageProperty javascriptProperty = null ;
if ( ! String . IsNullOrEmpty ( callbackParameterName ) & &
! OperationContext . Current . OutgoingMessageProperties . TryGetValue < JavascriptCallbackResponseMessageProperty > ( JavascriptCallbackResponseMessageProperty . Name , out javascriptProperty ) )
{
UriTemplateMatch match = WebOperationContext . Current . IncomingRequest . UriTemplateMatch ;
if ( match ! = null & &
match . QueryParameters . AllKeys . Contains ( callbackParameterName ) )
{
string callbackName = match . QueryParameters [ callbackParameterName ] ;
if ( ! String . IsNullOrEmpty ( callbackName ) )
{
javascriptProperty = new JavascriptCallbackResponseMessageProperty
{
CallbackFunctionName = callbackName
} ;
OperationContext . Current . OutgoingMessageProperties . Add ( JavascriptCallbackResponseMessageProperty . Name , javascriptProperty ) ;
}
}
}
return javascriptProperty ;
}
}
}