1 //------------------------------------------------------------ 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //------------------------------------------------------------ 4 5 namespace System.ServiceModel.Dispatcher 6 { 7 using System; 8 using System.ServiceModel; 9 using System.ServiceModel.Channels; 10 using System.ServiceModel.Description; 11 using System.Collections.Generic; 12 using System.Xml; 13 using System.Runtime.Serialization; 14 using DiagnosticUtility = System.ServiceModel.DiagnosticUtility; 15 using System.ServiceModel.Web; 16 17 abstract class SingleBodyParameterMessageFormatter : IDispatchMessageFormatter, IClientMessageFormatter 18 { 19 string contractName; 20 string contractNs; 21 bool isRequestFormatter; 22 string operationName; 23 string serializerType; 24 SingleBodyParameterMessageFormatter(OperationDescription operation, bool isRequestFormatter, string serializerType)25 protected SingleBodyParameterMessageFormatter(OperationDescription operation, bool isRequestFormatter, string serializerType) 26 { 27 if (operation == null) 28 { 29 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operation"); 30 } 31 this.contractName = operation.DeclaringContract.Name; 32 this.contractNs = operation.DeclaringContract.Namespace; 33 this.operationName = operation.Name; 34 this.isRequestFormatter = isRequestFormatter; 35 this.serializerType = serializerType; 36 } 37 38 protected string ContractName 39 { 40 get { return this.contractName; } 41 } 42 43 protected string ContractNs 44 { 45 get { return this.contractNs; } 46 } 47 48 protected string OperationName 49 { 50 get { return this.operationName; } 51 } 52 CreateXmlAndJsonClientFormatter(OperationDescription operation, Type type, bool isRequestFormatter, UnwrappedTypesXmlSerializerManager xmlSerializerManager)53 public static IClientMessageFormatter CreateXmlAndJsonClientFormatter(OperationDescription operation, Type type, bool isRequestFormatter, UnwrappedTypesXmlSerializerManager xmlSerializerManager) 54 { 55 IClientMessageFormatter xmlFormatter = CreateClientFormatter(operation, type, isRequestFormatter, false, xmlSerializerManager); 56 if (!WebHttpBehavior.SupportsJsonFormat(operation)) 57 { 58 return xmlFormatter; 59 } 60 IClientMessageFormatter jsonFormatter = CreateClientFormatter(operation, type, isRequestFormatter, true, xmlSerializerManager); 61 Dictionary<WebContentFormat, IClientMessageFormatter> map = new Dictionary<WebContentFormat, IClientMessageFormatter>(); 62 map.Add(WebContentFormat.Xml, xmlFormatter); 63 map.Add(WebContentFormat.Json, jsonFormatter); 64 return new DemultiplexingClientMessageFormatter(map, xmlFormatter); 65 } 66 CreateXmlAndJsonDispatchFormatter(OperationDescription operation, Type type, bool isRequestFormatter, UnwrappedTypesXmlSerializerManager xmlSerializerManager, string callbackParameterName)67 public static IDispatchMessageFormatter CreateXmlAndJsonDispatchFormatter(OperationDescription operation, Type type, bool isRequestFormatter, UnwrappedTypesXmlSerializerManager xmlSerializerManager, string callbackParameterName) 68 { 69 IDispatchMessageFormatter xmlFormatter = CreateDispatchFormatter(operation, type, isRequestFormatter, false, xmlSerializerManager, null); 70 if (!WebHttpBehavior.SupportsJsonFormat(operation)) 71 { 72 return xmlFormatter; 73 } 74 IDispatchMessageFormatter jsonFormatter = CreateDispatchFormatter(operation, type, isRequestFormatter, true, xmlSerializerManager, callbackParameterName); 75 Dictionary<WebContentFormat, IDispatchMessageFormatter> map = new Dictionary<WebContentFormat, IDispatchMessageFormatter>(); 76 map.Add(WebContentFormat.Xml, xmlFormatter); 77 map.Add(WebContentFormat.Json, jsonFormatter); 78 return new DemultiplexingDispatchMessageFormatter(map, xmlFormatter); 79 } 80 DeserializeReply(Message message, object[] parameters)81 public object DeserializeReply(Message message, object[] parameters) 82 { 83 if (isRequestFormatter) 84 { 85 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.FormatterCannotBeUsedForReplyMessages))); 86 } 87 return ReadObject(message); 88 } 89 DeserializeRequest(Message message, object[] parameters)90 public void DeserializeRequest(Message message, object[] parameters) 91 { 92 if (!isRequestFormatter) 93 { 94 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.FormatterCannotBeUsedForRequestMessages))); 95 } 96 97 parameters[0] = ReadObject(message); 98 } 99 SerializeReply(MessageVersion messageVersion, object[] parameters, object result)100 public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result) 101 { 102 if (isRequestFormatter) 103 { 104 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.FormatterCannotBeUsedForReplyMessages))); 105 } 106 Message message = Message.CreateMessage(messageVersion, (string)null, CreateBodyWriter(result)); 107 if (result == null) 108 { 109 SuppressReplyEntityBody(message); 110 } 111 AttachMessageProperties(message, false); 112 return message; 113 } 114 SerializeRequest(MessageVersion messageVersion, object[] parameters)115 public Message SerializeRequest(MessageVersion messageVersion, object[] parameters) 116 { 117 if (!isRequestFormatter) 118 { 119 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.FormatterCannotBeUsedForRequestMessages))); 120 } 121 Message message = Message.CreateMessage(messageVersion, (string)null, CreateBodyWriter(parameters[0])); 122 if (parameters[0] == null) 123 { 124 SuppressRequestEntityBody(message); 125 } 126 AttachMessageProperties(message, true); 127 return message; 128 } 129 CreateClientFormatter(OperationDescription operation, Type type, bool isRequestFormatter, bool useJson, UnwrappedTypesXmlSerializerManager xmlSerializerManager)130 internal static IClientMessageFormatter CreateClientFormatter(OperationDescription operation, Type type, bool isRequestFormatter, bool useJson, UnwrappedTypesXmlSerializerManager xmlSerializerManager) 131 { 132 if (type == null) 133 { 134 return new NullMessageFormatter(false, null); 135 } 136 else if (useJson) 137 { 138 return CreateJsonFormatter(operation, type, isRequestFormatter); 139 } 140 else 141 { 142 return CreateXmlFormatter(operation, type, isRequestFormatter, xmlSerializerManager); 143 } 144 } 145 CreateDispatchFormatter(OperationDescription operation, Type type, bool isRequestFormatter, bool useJson, UnwrappedTypesXmlSerializerManager xmlSerializerManager, string callbackParameterName)146 internal static IDispatchMessageFormatter CreateDispatchFormatter(OperationDescription operation, Type type, bool isRequestFormatter, bool useJson, UnwrappedTypesXmlSerializerManager xmlSerializerManager, string callbackParameterName) 147 { 148 if (type == null) 149 { 150 return new NullMessageFormatter(useJson, callbackParameterName); 151 } 152 else if (useJson) 153 { 154 return CreateJsonFormatter(operation, type, isRequestFormatter); 155 } 156 else 157 { 158 return CreateXmlFormatter(operation, type, isRequestFormatter, xmlSerializerManager); 159 } 160 } 161 SuppressReplyEntityBody(Message message)162 internal static void SuppressReplyEntityBody(Message message) 163 { 164 WebOperationContext currentContext = WebOperationContext.Current; 165 if (currentContext != null) 166 { 167 OutgoingWebResponseContext responseContext = currentContext.OutgoingResponse; 168 if (responseContext != null) 169 { 170 responseContext.SuppressEntityBody = true; 171 } 172 } 173 else 174 { 175 object untypedProp; 176 message.Properties.TryGetValue(HttpResponseMessageProperty.Name, out untypedProp); 177 HttpResponseMessageProperty prop = untypedProp as HttpResponseMessageProperty; 178 if (prop == null) 179 { 180 prop = new HttpResponseMessageProperty(); 181 message.Properties[HttpResponseMessageProperty.Name] = prop; 182 } 183 prop.SuppressEntityBody = true; 184 } 185 } 186 SuppressRequestEntityBody(Message message)187 internal static void SuppressRequestEntityBody(Message message) 188 { 189 WebOperationContext currentContext = WebOperationContext.Current; 190 if (currentContext != null) 191 { 192 OutgoingWebRequestContext requestContext = currentContext.OutgoingRequest; 193 if (requestContext != null) 194 { 195 requestContext.SuppressEntityBody = true; 196 } 197 } 198 else 199 { 200 object untypedProp; 201 message.Properties.TryGetValue(HttpRequestMessageProperty.Name, out untypedProp); 202 HttpRequestMessageProperty prop = untypedProp as HttpRequestMessageProperty; 203 if (prop == null) 204 { 205 prop = new HttpRequestMessageProperty(); 206 message.Properties[HttpRequestMessageProperty.Name] = prop; 207 } 208 prop.SuppressEntityBody = true; 209 } 210 } 211 AttachMessageProperties(Message message, bool isRequest)212 protected virtual void AttachMessageProperties(Message message, bool isRequest) 213 { 214 } 215 GetInputSerializers()216 protected abstract XmlObjectSerializer[] GetInputSerializers(); 217 GetOutputSerializer(Type type)218 protected abstract XmlObjectSerializer GetOutputSerializer(Type type); 219 ValidateMessageFormatProperty(Message message)220 protected virtual void ValidateMessageFormatProperty(Message message) 221 { 222 } 223 GetTypeForSerializer(Type type, Type parameterType, IList<Type> knownTypes)224 protected Type GetTypeForSerializer(Type type, Type parameterType, IList<Type> knownTypes) 225 { 226 if (type == parameterType) 227 { 228 return type; 229 } 230 else if (knownTypes != null) 231 { 232 for (int i = 0; i < knownTypes.Count; ++i) 233 { 234 if (type == knownTypes[i]) 235 { 236 return type; 237 } 238 } 239 } 240 return parameterType; 241 } 242 CreateXmlFormatter(OperationDescription operation, Type type, bool isRequestFormatter, UnwrappedTypesXmlSerializerManager xmlSerializerManager)243 public static SingleBodyParameterMessageFormatter CreateXmlFormatter(OperationDescription operation, Type type, bool isRequestFormatter, UnwrappedTypesXmlSerializerManager xmlSerializerManager) 244 { 245 DataContractSerializerOperationBehavior dcsob = operation.Behaviors.Find<DataContractSerializerOperationBehavior>(); 246 if (dcsob != null) 247 { 248 return new SingleBodyParameterDataContractMessageFormatter(operation, type, isRequestFormatter, false, dcsob); 249 } 250 XmlSerializerOperationBehavior xsob = operation.Behaviors.Find<XmlSerializerOperationBehavior>(); 251 if (xsob != null) 252 { 253 return new SingleBodyParameterXmlSerializerMessageFormatter(operation, type, isRequestFormatter, xsob, xmlSerializerManager); 254 } 255 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR2.GetString(SR2.OnlyDataContractAndXmlSerializerTypesInUnWrappedMode, operation.Name))); 256 } 257 CreateJsonFormatter(OperationDescription operation, Type type, bool isRequestFormatter)258 public static SingleBodyParameterMessageFormatter CreateJsonFormatter(OperationDescription operation, Type type, bool isRequestFormatter) 259 { 260 DataContractSerializerOperationBehavior dcsob = operation.Behaviors.Find<DataContractSerializerOperationBehavior>(); 261 if (dcsob == null) 262 { 263 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.JsonFormatRequiresDataContract, operation.Name, operation.DeclaringContract.Name, operation.DeclaringContract.Namespace))); 264 } 265 return new SingleBodyParameterDataContractMessageFormatter(operation, type, isRequestFormatter, true, dcsob); 266 } 267 CreateBodyWriter(object body)268 BodyWriter CreateBodyWriter(object body) 269 { 270 XmlObjectSerializer serializer; 271 if (body != null) 272 { 273 serializer = GetOutputSerializer(body.GetType()); 274 if (serializer == null) 275 { 276 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR2.GetString(SR2.CannotSerializeType, body.GetType(), this.operationName, this.contractName, this.contractNs, this.serializerType))); 277 } 278 } 279 else 280 { 281 serializer = null; 282 } 283 return new SingleParameterBodyWriter(body, serializer); 284 } 285 ReadObject(Message message)286 protected virtual object ReadObject(Message message) 287 { 288 if (HttpStreamFormatter.IsEmptyMessage(message)) 289 { 290 return null; 291 } 292 XmlObjectSerializer[] inputSerializers = GetInputSerializers(); 293 XmlDictionaryReader reader = message.GetReaderAtBodyContents(); 294 if (inputSerializers != null) 295 { 296 for (int i = 0; i < inputSerializers.Length; ++i) 297 { 298 if (inputSerializers[i].IsStartObject(reader)) 299 { 300 return inputSerializers[i].ReadObject(reader, false); 301 } 302 } 303 } 304 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR2.GetString(SR2.CannotDeserializeBody, reader.LocalName, reader.NamespaceURI, operationName, contractName, contractNs, this.serializerType))); 305 } 306 307 class NullMessageFormatter : IDispatchMessageFormatter, IClientMessageFormatter 308 { 309 bool useJson; 310 string callbackParameterName; 311 NullMessageFormatter(bool useJson, string callbackParameterName)312 public NullMessageFormatter(bool useJson, string callbackParameterName) 313 { 314 this.useJson = useJson; 315 this.callbackParameterName = callbackParameterName; 316 } 317 DeserializeReply(Message message, object[] parameters)318 public object DeserializeReply(Message message, object[] parameters) 319 { 320 return null; 321 } 322 DeserializeRequest(Message message, object[] parameters)323 public void DeserializeRequest(Message message, object[] parameters) 324 { 325 } 326 SerializeReply(MessageVersion messageVersion, object[] parameters, object result)327 public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result) 328 { 329 Message reply = Message.CreateMessage(messageVersion, (string)null); 330 SuppressReplyEntityBody(reply); 331 if (useJson && WebHttpBehavior.TrySetupJavascriptCallback(callbackParameterName) != null) 332 { 333 reply.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.JsonProperty); 334 } 335 return reply; 336 } 337 SerializeRequest(MessageVersion messageVersion, object[] parameters)338 public Message SerializeRequest(MessageVersion messageVersion, object[] parameters) 339 { 340 Message request = Message.CreateMessage(messageVersion, (string)null); 341 SuppressRequestEntityBody(request); 342 return request; 343 } 344 } 345 346 class SingleParameterBodyWriter : BodyWriter 347 { 348 object body; 349 XmlObjectSerializer serializer; 350 SingleParameterBodyWriter(object body, XmlObjectSerializer serializer)351 public SingleParameterBodyWriter(object body, XmlObjectSerializer serializer) 352 : base(false) 353 { 354 if (body != null && serializer == null) 355 { 356 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer"); 357 } 358 this.body = body; 359 this.serializer = serializer; 360 } 361 OnWriteBodyContents(XmlDictionaryWriter writer)362 protected override void OnWriteBodyContents(XmlDictionaryWriter writer) 363 { 364 if (body != null) 365 { 366 this.serializer.WriteObject(writer, body); 367 } 368 } 369 } 370 } 371 } 372 373