Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

View File

@ -0,0 +1,33 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
class CompositeClientFormatter : IClientMessageFormatter
{
IClientMessageFormatter reply;
IClientMessageFormatter request;
public CompositeClientFormatter(IClientMessageFormatter request, IClientMessageFormatter reply)
{
this.request = request;
this.reply = reply;
}
public object DeserializeReply(Message message, object[] parameters)
{
return this.reply.DeserializeReply(message, parameters);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
return this.request.SerializeRequest(messageVersion, parameters);
}
}
}

View File

@ -0,0 +1,33 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
class CompositeDispatchFormatter : IDispatchMessageFormatter
{
IDispatchMessageFormatter reply;
IDispatchMessageFormatter request;
public CompositeDispatchFormatter(IDispatchMessageFormatter request, IDispatchMessageFormatter reply)
{
this.request = request;
this.reply = reply;
}
public void DeserializeRequest(Message message, object[] parameters)
{
this.request.DeserializeRequest(message, parameters);
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
return this.reply.SerializeReply(messageVersion, parameters, result);
}
}
}

View File

@ -0,0 +1,92 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System.Collections;
using System.ServiceModel.Channels;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Xml;
using System.ServiceModel.Diagnostics;
using System.Net;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
class ContentTypeSettingClientMessageFormatter : IClientMessageFormatter
{
IClientMessageFormatter innerFormatter;
string outgoingContentType;
public ContentTypeSettingClientMessageFormatter(string outgoingContentType, IClientMessageFormatter innerFormatter)
{
if (outgoingContentType == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("outgoingContentType");
}
if (innerFormatter == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("innerFormatter");
}
this.outgoingContentType = outgoingContentType;
this.innerFormatter = innerFormatter;
}
public object DeserializeReply(Message message, object[] parameters)
{
return this.innerFormatter.DeserializeReply(message, parameters);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
Message message = this.innerFormatter.SerializeRequest(messageVersion, parameters);
if (message != null)
{
AddRequestContentTypeProperty(message, this.outgoingContentType);
}
return message;
}
static void AddRequestContentTypeProperty(Message message, string contentType)
{
if (message == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
}
if (contentType == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contentType");
}
if (OperationContext.Current != null && OperationContext.Current.HasOutgoingMessageProperties)
{
if (string.IsNullOrEmpty(WebOperationContext.Current.OutgoingRequest.ContentType))
{
WebOperationContext.Current.OutgoingRequest.ContentType = contentType;
}
}
else
{
object prop;
message.Properties.TryGetValue(HttpRequestMessageProperty.Name, out prop);
HttpRequestMessageProperty httpProperty;
if (prop != null)
{
httpProperty = (HttpRequestMessageProperty) prop;
}
else
{
httpProperty = new HttpRequestMessageProperty();
message.Properties.Add(HttpRequestMessageProperty.Name, httpProperty);
}
if (string.IsNullOrEmpty(httpProperty.Headers[HttpRequestHeader.ContentType]))
{
httpProperty.Headers[HttpRequestHeader.ContentType] = contentType;
}
}
}
}
}

View File

@ -0,0 +1,84 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
class ContentTypeSettingDispatchMessageFormatter : IDispatchMessageFormatter
{
IDispatchMessageFormatter innerFormatter;
string outgoingContentType;
public ContentTypeSettingDispatchMessageFormatter(string outgoingContentType, IDispatchMessageFormatter innerFormatter)
{
if (outgoingContentType == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("outgoingContentType");
}
if (innerFormatter == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("innerFormatter");
}
this.outgoingContentType = outgoingContentType;
this.innerFormatter = innerFormatter;
}
public void DeserializeRequest(Message message, object[] parameters)
{
this.innerFormatter.DeserializeRequest(message, parameters);
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
Message message = this.innerFormatter.SerializeReply(messageVersion, parameters, result);
if (message != null)
{
AddResponseContentTypeProperty(message, this.outgoingContentType);
}
return message;
}
static void AddResponseContentTypeProperty(Message message, string contentType)
{
if (message == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
}
if (contentType == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contentType");
}
if (OperationContext.Current != null && OperationContext.Current.HasOutgoingMessageProperties)
{
if (string.IsNullOrEmpty(WebOperationContext.Current.OutgoingResponse.ContentType))
{
WebOperationContext.Current.OutgoingResponse.ContentType = contentType;
}
}
else
{
object prop;
message.Properties.TryGetValue(HttpResponseMessageProperty.Name, out prop);
HttpResponseMessageProperty httpProperty;
if (prop != null)
{
httpProperty = (HttpResponseMessageProperty) prop;
}
else
{
httpProperty = new HttpResponseMessageProperty();
message.Properties.Add(HttpResponseMessageProperty.Name, httpProperty);
}
if (string.IsNullOrEmpty(httpProperty.Headers[HttpResponseHeader.ContentType]))
{
httpProperty.Headers[HttpResponseHeader.ContentType] = contentType;
}
}
}
}
}

View File

@ -0,0 +1,76 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Globalization;
class DemultiplexingClientMessageFormatter : IClientMessageFormatter
{
IClientMessageFormatter defaultFormatter;
Dictionary<WebContentFormat, IClientMessageFormatter> formatters;
string supportedFormats;
public DemultiplexingClientMessageFormatter(IDictionary<WebContentFormat, IClientMessageFormatter> formatters, IClientMessageFormatter defaultFormatter)
{
if (formatters == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("formatters");
}
this.formatters = new Dictionary<WebContentFormat, IClientMessageFormatter>();
foreach (WebContentFormat key in formatters.Keys)
{
this.formatters.Add(key, formatters[key]);
}
this.defaultFormatter = defaultFormatter;
}
public object DeserializeReply(Message message, object[] parameters)
{
if (message == null)
{
return null;
}
WebContentFormat format;
IClientMessageFormatter selectedFormatter;
if (DemultiplexingDispatchMessageFormatter.TryGetEncodingFormat(message, out format))
{
this.formatters.TryGetValue(format, out selectedFormatter);
if (selectedFormatter == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR2.GetString(SR2.UnrecognizedHttpMessageFormat, format, GetSupportedFormats())));
}
}
else
{
selectedFormatter = this.defaultFormatter;
if (selectedFormatter == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR2.GetString(SR2.MessageFormatPropertyNotFound3)));
}
}
return selectedFormatter.DeserializeReply(message, parameters);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR2.GetString(SR2.SerializingRequestNotSupportedByFormatter, this)));
}
string GetSupportedFormats()
{
if (this.supportedFormats == null)
{
this.supportedFormats = DemultiplexingDispatchMessageFormatter.GetSupportedFormats(this.formatters.Keys);
}
return this.supportedFormats;
}
}
}

View File

@ -0,0 +1,108 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Globalization;
using System.Text;
class DemultiplexingDispatchMessageFormatter : IDispatchMessageFormatter
{
IDispatchMessageFormatter defaultFormatter;
Dictionary<WebContentFormat, IDispatchMessageFormatter> formatters;
string supportedFormats;
public DemultiplexingDispatchMessageFormatter(IDictionary<WebContentFormat, IDispatchMessageFormatter> formatters, IDispatchMessageFormatter defaultFormatter)
{
if (formatters == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("formatters");
}
this.formatters = new Dictionary<WebContentFormat, IDispatchMessageFormatter>();
foreach (WebContentFormat key in formatters.Keys)
{
this.formatters.Add(key, formatters[key]);
}
this.defaultFormatter = defaultFormatter;
}
public void DeserializeRequest(Message message, object[] parameters)
{
if (message == null)
{
return;
}
WebContentFormat format;
IDispatchMessageFormatter selectedFormatter;
if (TryGetEncodingFormat(message, out format))
{
this.formatters.TryGetValue(format, out selectedFormatter);
if (selectedFormatter == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR2.GetString(SR2.UnrecognizedHttpMessageFormat, format, GetSupportedFormats())));
}
}
else
{
selectedFormatter = this.defaultFormatter;
if (selectedFormatter == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR2.GetString(SR2.MessageFormatPropertyNotFound3)));
}
}
selectedFormatter.DeserializeRequest(message, parameters);
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR2.GetString(SR2.SerializingReplyNotSupportedByFormatter, this)));
}
internal static string GetSupportedFormats(IEnumerable<WebContentFormat> formats)
{
StringBuilder sb = new StringBuilder();
int i = 0;
foreach (WebContentFormat format in formats)
{
if (i > 0)
{
sb.Append(CultureInfo.CurrentCulture.TextInfo.ListSeparator);
sb.Append(" ");
}
sb.Append("'" + format.ToString() + "'");
++i;
}
return sb.ToString();
}
internal static bool TryGetEncodingFormat(Message message, out WebContentFormat format)
{
object prop;
message.Properties.TryGetValue(WebBodyFormatMessageProperty.Name, out prop);
WebBodyFormatMessageProperty formatProperty = prop as WebBodyFormatMessageProperty;
if (formatProperty == null)
{
format = WebContentFormat.Default;
return false;
}
format = formatProperty.Format;
return true;
}
string GetSupportedFormats()
{
if (this.supportedFormats == null)
{
this.supportedFormats = GetSupportedFormats(this.formatters.Keys);
}
return this.supportedFormats;
}
}
}

View File

@ -0,0 +1,235 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634, 1691
namespace System.ServiceModel.Description
{
using System.Collections.Generic;
using System.Linq;
using System.Net.Mime;
using System.Runtime;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
using System.Diagnostics;
using System.ServiceModel.Diagnostics;
class FormatSelectingMessageInspector : IDispatchMessageInspector
{
static readonly IEnumerable<string> wildcardMediaTypes = new List<string>() { "application", "text" };
List<MultiplexingFormatMapping> mappings;
Dictionary<string, MultiplexingDispatchMessageFormatter> formatters;
Dictionary<string, NameValueCache<FormatContentTypePair>> caches;
bool automaticFormatSelectionEnabled;
// There are technically an infinite number of valid accept headers for just xml and json,
// but to prevent DOS attacks, we need to set an upper limit. It is assumed that there would
// never be more than two dozen valid accept headers actually used out in the wild.
static readonly int maxCachedAcceptHeaders = 25;
public FormatSelectingMessageInspector(WebHttpBehavior webHttpBehavior, List<MultiplexingFormatMapping> mappings)
{
if (webHttpBehavior == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("webHttpBehavior");
}
if (mappings == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("mappings");
}
this.automaticFormatSelectionEnabled = webHttpBehavior.AutomaticFormatSelectionEnabled;
this.formatters = new Dictionary<string, MultiplexingDispatchMessageFormatter>();
this.caches = new Dictionary<string, NameValueCache<FormatContentTypePair>>();
this.mappings = mappings;
}
public void RegisterOperation(string operationName, MultiplexingDispatchMessageFormatter formatter)
{
if (formatter == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("formatter");
}
Fx.Assert(!this.formatters.ContainsKey(operationName), "An operation should only be registered once.");
this.formatters.Add(operationName, formatter);
this.caches.Add(operationName, new NameValueCache<FormatContentTypePair>(maxCachedAcceptHeaders));
}
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
if (this.automaticFormatSelectionEnabled)
{
MessageProperties messageProperties = OperationContext.Current.IncomingMessageProperties;
if (messageProperties.ContainsKey(WebHttpDispatchOperationSelector.HttpOperationNamePropertyName))
{
string operationName = messageProperties[WebHttpDispatchOperationSelector.HttpOperationNamePropertyName] as string;
if (!string.IsNullOrEmpty(operationName) && this.formatters.ContainsKey(operationName))
{
string acceptHeader = WebOperationContext.Current.IncomingRequest.Accept;
if (!string.IsNullOrEmpty(acceptHeader))
{
if (TrySetFormatFromCache(operationName, acceptHeader) ||
TrySetFormatFromAcceptHeader(operationName, acceptHeader, true /* matchCharSet */) ||
TrySetFormatFromAcceptHeader(operationName, acceptHeader, false /* matchCharSet */))
{
return null;
}
}
if (TrySetFormatFromContentType(operationName))
{
return null;
}
SetFormatFromDefault(operationName);
}
}
}
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
// do nothing
}
bool TrySetFormatFromCache(string operationName, string acceptHeader)
{
Fx.Assert(this.caches.ContainsKey(operationName), "The calling method is responsible for ensuring that the 'operationName' key exists in the caches dictionary.");
Fx.Assert(acceptHeader != null, "The calling method is responsible for ensuring that 'acceptHeader' is not null");
FormatContentTypePair pair = caches[operationName].Lookup(acceptHeader.ToUpperInvariant());
if (pair != null)
{
SetFormatAndContentType(pair.Format, pair.ContentType);
return true;
}
return false;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Given that media types are generally in lowercase, it is awkward to normalize to uppercase.")]
bool TrySetFormatFromAcceptHeader(string operationName, string acceptHeader, bool matchCharSet)
{
Fx.Assert(this.formatters.ContainsKey(operationName), "The calling method is responsible for ensuring that the 'operationName' key exists in the formatters dictionary.");
IList<ContentType> acceptHeaderElements = WebOperationContext.Current.IncomingRequest.GetAcceptHeaderElements();
for (int i = 0; i < acceptHeaderElements.Count; i++)
{
string[] typeAndSubType = acceptHeaderElements[i].MediaType.Split('/');
string type = typeAndSubType[0].Trim().ToLowerInvariant();
string subType = typeAndSubType[1].Trim();
if ((subType[0] == '*' && subType.Length == 1) &&
((type[0] == '*' && type.Length == 1) ||
wildcardMediaTypes.Contains(type)))
{
SetFormatFromDefault(operationName, acceptHeader);
return true;
}
foreach (MultiplexingFormatMapping mapping in mappings)
{
ContentType contentType;
WebMessageFormat format = mapping.MessageFormat;
if (this.formatters[operationName].SupportsMessageFormat(format) &&
mapping.CanFormatResponse(acceptHeaderElements[i], matchCharSet, out contentType))
{
string contentTypeStr = contentType.ToString();
this.caches[operationName].AddOrUpdate(acceptHeader.ToUpperInvariant(), new FormatContentTypePair(format, contentTypeStr));
SetFormatAndContentType(format, contentTypeStr);
return true;
}
}
}
return false;
}
bool TrySetFormatFromContentType(string operationName)
{
Fx.Assert(this.formatters.ContainsKey(operationName), "The calling method is responsible for ensuring that the 'operationName' key exists in the formatters dictionary.");
string contentTypeStr = WebOperationContext.Current.IncomingRequest.ContentType;
if (contentTypeStr != null)
{
ContentType contentType = Web.Utility.GetContentType(contentTypeStr);
if (contentType != null)
{
foreach (MultiplexingFormatMapping mapping in mappings)
{
ContentType responseContentType;
if (this.formatters[operationName].SupportsMessageFormat(mapping.MessageFormat) &&
mapping.CanFormatResponse(contentType, false, out responseContentType))
{
SetFormatAndContentType(mapping.MessageFormat, responseContentType.ToString());
return true;
}
}
}
}
return false;
}
void SetFormatFromDefault(string operationName)
{
SetFormatFromDefault(operationName, null);
}
void SetFormatFromDefault(string operationName, string acceptHeader)
{
Fx.Assert(this.formatters.ContainsKey(operationName), "The calling method is responsible for ensuring that the 'operationName' key exists in the formatters dictionary.");
WebMessageFormat format = this.formatters[operationName].DefaultFormat;
if (!string.IsNullOrEmpty(acceptHeader))
{
this.caches[operationName].AddOrUpdate(acceptHeader.ToUpperInvariant(), new FormatContentTypePair(format, null));
}
WebOperationContext.Current.OutgoingResponse.Format = format;
if (DiagnosticUtility.ShouldTraceInformation)
{
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.AutomaticFormatSelectedOperationDefault, SR2.GetString(SR2.TraceCodeAutomaticFormatSelectedOperationDefault, format.ToString()));
}
}
void SetFormatAndContentType(WebMessageFormat format, string contentType)
{
OutgoingWebResponseContext outgoingResponse = WebOperationContext.Current.OutgoingResponse;
outgoingResponse.Format = format;
outgoingResponse.AutomatedFormatSelectionContentType = contentType;
if (DiagnosticUtility.ShouldTraceInformation)
{
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.AutomaticFormatSelectedRequestBased, SR2.GetString(SR2.TraceCodeAutomaticFormatSelectedRequestBased, format.ToString(), contentType));
}
}
class FormatContentTypePair
{
WebMessageFormat format;
string contentType;
public FormatContentTypePair(WebMessageFormat format, string contentType)
{
this.format = format;
this.contentType = contentType;
}
public WebMessageFormat Format
{
get { return this.format; }
}
public string ContentType
{
get { return this.contentType; }
}
}
}
}

View File

@ -0,0 +1,427 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Json;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
using System.ServiceModel.Web.Configuration;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Globalization;
using System.Web;
using System.Xml.Schema;
class HelpHtmlBuilder
{
const string HelpOperationPageUrl = "help/operations/{0}";
const string HtmlHtmlElementName = "{http://www.w3.org/1999/xhtml}html";
const string HtmlHeadElementName = "{http://www.w3.org/1999/xhtml}head";
const string HtmlTitleElementName = "{http://www.w3.org/1999/xhtml}title";
const string HtmlBodyElementName = "{http://www.w3.org/1999/xhtml}body";
const string HtmlBrElementName = "{http://www.w3.org/1999/xhtml}br";
const string HtmlPElementName = "{http://www.w3.org/1999/xhtml}p";
const string HtmlTableElementName = "{http://www.w3.org/1999/xhtml}table";
const string HtmlTrElementName = "{http://www.w3.org/1999/xhtml}tr";
const string HtmlThElementName = "{http://www.w3.org/1999/xhtml}th";
const string HtmlTdElementName = "{http://www.w3.org/1999/xhtml}td";
const string HtmlDivElementName = "{http://www.w3.org/1999/xhtml}div";
const string HtmlAElementName = "{http://www.w3.org/1999/xhtml}a";
const string HtmlPreElementName = "{http://www.w3.org/1999/xhtml}pre";
const string HtmlClassAttributeName = "class";
const string HtmlTitleAttributeName = "title";
const string HtmlHrefAttributeName = "href";
const string HtmlRelAttributeName = "rel";
const string HtmlIdAttributeName = "id";
const string HtmlNameAttributeName = "name";
const string HtmlRowspanAttributeName = "rowspan";
const string HtmlHeading1Class = "heading1";
const string HtmlContentClass = "content";
const string HtmlRequestXmlId = "request-xml";
const string HtmlRequestJsonId = "request-json";
const string HtmlRequestSchemaId = "request-schema";
const string HtmlResponseXmlId = "response-xml";
const string HtmlResponseJsonId = "response-json";
const string HtmlResponseSchemaId = "response-schema";
const string HtmlOperationClass = "operation";
public static XDocument CreateHelpPage(Uri baseUri, IEnumerable<OperationHelpInformation> operations)
{
XDocument document = CreateBaseDocument(SR2.GetString(SR2.HelpPageOperationsAt, baseUri));
XElement table = new XElement(HtmlTableElementName,
new XElement(HtmlTrElementName,
new XElement(HtmlThElementName, SR2.GetString(SR2.HelpPageUri)),
new XElement(HtmlThElementName, SR2.GetString(SR2.HelpPageMethod)),
new XElement(HtmlThElementName, SR2.GetString(SR2.HelpPageDescription))));
string lastOperation = null;
XElement firstTr = null;
int rowspan = 0;
foreach (OperationHelpInformation operationHelpInfo in operations.OrderBy(o => FilterQueryVariables(o.UriTemplate)))
{
string operationUri = FilterQueryVariables(operationHelpInfo.UriTemplate);
string description = operationHelpInfo.Description;
if (String.IsNullOrEmpty(description))
{
description = SR2.GetString(SR2.HelpPageDefaultDescription, BuildFullUriTemplate(baseUri, operationHelpInfo.UriTemplate));
}
XElement tr = new XElement(HtmlTrElementName,
new XElement(HtmlTdElementName, new XAttribute(HtmlTitleAttributeName, BuildFullUriTemplate(baseUri, operationHelpInfo.UriTemplate)),
new XElement(HtmlAElementName,
new XAttribute(HtmlRelAttributeName, HtmlOperationClass),
new XAttribute(HtmlHrefAttributeName, String.Format(CultureInfo.InvariantCulture, HelpOperationPageUrl, operationHelpInfo.Name)), operationHelpInfo.Method)),
new XElement(HtmlTdElementName, description));
table.Add(tr);
if (operationUri != lastOperation)
{
XElement td = new XElement(HtmlTdElementName, operationUri == lastOperation ? String.Empty : operationUri);
tr.AddFirst(td);
if (firstTr != null && rowspan > 1)
{
firstTr.Descendants(HtmlTdElementName).First().Add(new XAttribute(HtmlRowspanAttributeName, rowspan));
}
firstTr = tr;
rowspan = 0;
lastOperation = operationUri;
}
++rowspan;
}
if (firstTr != null && rowspan > 1)
{
firstTr.Descendants(HtmlTdElementName).First().Add(new XAttribute(HtmlRowspanAttributeName, rowspan));
}
document.Descendants(HtmlBodyElementName).First().Add(new XElement(HtmlDivElementName, new XAttribute(HtmlIdAttributeName, HtmlContentClass),
new XElement(HtmlPElementName, new XAttribute(HtmlClassAttributeName, HtmlHeading1Class), SR2.GetString(SR2.HelpPageOperationsAt, baseUri)),
new XElement(HtmlPElementName, SR2.GetString(SR2.HelpPageStaticText)),
table));
return document;
}
public static XDocument CreateOperationHelpPage(Uri baseUri, OperationHelpInformation operationInfo)
{
XDocument document = CreateBaseDocument(SR2.GetString(SR2.HelpPageReferenceFor, BuildFullUriTemplate(baseUri, operationInfo.UriTemplate)));
XElement table = new XElement(HtmlTableElementName,
new XElement(HtmlTrElementName,
new XElement(HtmlThElementName, SR2.GetString(SR2.HelpPageMessageDirection)),
new XElement(HtmlThElementName, SR2.GetString(SR2.HelpPageFormat)),
new XElement(HtmlThElementName, SR2.GetString(SR2.HelpPageBody))));
RenderMessageInformation(table, operationInfo, true);
RenderMessageInformation(table, operationInfo, false);
XElement div = new XElement(HtmlDivElementName, new XAttribute(HtmlIdAttributeName, HtmlContentClass),
new XElement(HtmlPElementName, new XAttribute(HtmlClassAttributeName, HtmlHeading1Class), SR2.GetString(SR2.HelpPageReferenceFor, BuildFullUriTemplate(baseUri, operationInfo.UriTemplate))),
new XElement(HtmlPElementName, operationInfo.Description),
XElement.Parse(SR2.GetString(SR2.HelpPageOperationUri, HttpUtility.HtmlEncode(BuildFullUriTemplate(baseUri, operationInfo.UriTemplate)))),
XElement.Parse(SR2.GetString(SR2.HelpPageOperationMethod, HttpUtility.HtmlEncode(operationInfo.Method))));
if (!String.IsNullOrEmpty(operationInfo.JavascriptCallbackParameterName))
{
div.Add(XElement.Parse(SR2.GetString(SR2.HelpPageCallbackText, HttpUtility.HtmlEncode(operationInfo.JavascriptCallbackParameterName))), table);
}
else
{
div.Add(table);
}
document.Descendants(HtmlBodyElementName).First().Add(div);
CreateOperationSamples(document.Descendants(HtmlDivElementName).First(), operationInfo);
return document;
}
public static XDocument CreateMethodNotAllowedPage(Uri helpUri)
{
XDocument document = CreateBaseDocument(SR2.GetString(SR2.HelpPageTitleText));
XElement div = new XElement(HtmlDivElementName, new XAttribute(HtmlIdAttributeName, HtmlContentClass),
new XElement(HtmlPElementName, new XAttribute(HtmlClassAttributeName, HtmlHeading1Class), SR2.GetString(SR2.HelpPageTitleText)));
if (helpUri == null)
{
div.Add(new XElement(HtmlPElementName, SR2.GetString(SR2.HelpPageMethodNotAllowed)));
}
else
{
div.Add(XElement.Parse(SR2.GetString(SR2.HelpPageMethodNotAllowedWithLink, HttpUtility.HtmlEncode(helpUri.AbsoluteUri))));
}
document.Descendants(HtmlBodyElementName).First().Add(div);
return document;
}
public static XDocument CreateServerErrorPage(Uri helpUri, Exception error)
{
XDocument document = CreateBaseDocument(SR2.GetString(SR2.HelpPageRequestErrorTitle));
XElement div = new XElement(HtmlDivElementName, new XAttribute(HtmlIdAttributeName, HtmlContentClass),
new XElement(HtmlPElementName, new XAttribute(HtmlClassAttributeName, HtmlHeading1Class), SR2.GetString(SR2.HelpPageRequestErrorTitle)));
if (helpUri == null)
{
if (error != null)
{
//TFS Bug 500275: it is not necessary to HtmlEncode the error.Message string here because XElement ctor will encode it.
div.Add(new XElement(HtmlPElementName, SR2.GetString(SR2.HelpServerErrorProcessingRequestWithDetails, error.Message)));
div.Add(new XElement(HtmlPElementName, error.StackTrace ?? String.Empty));
}
else
{
div.Add(new XElement(HtmlPElementName, SR2.GetString(SR2.HelpServerErrorProcessingRequest)));
}
}
else
{
string encodedHelpLink = HttpUtility.HtmlEncode(helpUri.AbsoluteUri);
if (error != null)
{
//TFS Bug 500275: XElement.Parse does not HtmlEncode the string passed to it, so we need to encode it before calling Parse.
string errorMessage = AppSettings.DisableHtmlErrorPageExceptionHtmlEncoding ? error.Message : HttpUtility.HtmlEncode(error.Message);
div.Add(XElement.Parse(SR2.GetString(SR2.HelpServerErrorProcessingRequestWithDetailsAndLink, encodedHelpLink, errorMessage)));
div.Add(new XElement(HtmlPElementName, error.StackTrace ?? String.Empty));
}
else
{
div.Add(XElement.Parse(SR2.GetString(SR2.HelpServerErrorProcessingRequestWithLink, encodedHelpLink)));
}
}
document.Descendants(HtmlBodyElementName).First().Add(div);
return document;
}
public static XDocument CreateEndpointNotFound(Uri helpUri)
{
XDocument document = CreateBaseDocument(SR2.GetString(SR2.HelpPageTitleText));
XElement div = new XElement(HtmlDivElementName, new XAttribute(HtmlIdAttributeName, HtmlContentClass),
new XElement(HtmlPElementName, new XAttribute(HtmlClassAttributeName, HtmlHeading1Class), SR2.GetString(SR2.HelpPageTitleText)));
if (helpUri == null)
{
div.Add(new XElement(HtmlPElementName, SR2.GetString(SR2.HelpPageEndpointNotFound)));
}
else
{
div.Add(XElement.Parse(SR2.GetString(SR2.HelpPageEndpointNotFoundWithLink, HttpUtility.HtmlEncode(helpUri.AbsoluteUri))));
}
document.Descendants(HtmlBodyElementName).First().Add(div);
return document;
}
public static XDocument CreateTransferRedirectPage(string originalTo, string newLocation)
{
XDocument document = CreateBaseDocument(SR2.GetString(SR2.HelpPageTitleText));
XElement div = new XElement(HtmlDivElementName, new XAttribute(HtmlIdAttributeName, HtmlContentClass),
new XElement(HtmlPElementName, new XAttribute(HtmlClassAttributeName, HtmlHeading1Class), SR2.GetString(SR2.HelpPageTitleText)),
XElement.Parse(SR2.GetString(SR2.HelpPageRedirect, HttpUtility.HtmlEncode(originalTo), HttpUtility.HtmlEncode(newLocation))));
document.Descendants(HtmlBodyElementName).First().Add(div);
return document;
}
static XDocument CreateBaseDocument(string title)
{
return new XDocument(
new XDocumentType("html", "-//W3C//DTD XHTML 1.0 Transitional//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", null),
new XElement(HtmlHtmlElementName,
new XElement(HtmlHeadElementName,
new XElement(HtmlTitleElementName, title),
new XElement("{http://www.w3.org/1999/xhtml}style", SR2.GetString(SR2.HelpPageHtml))),
new XElement(HtmlBodyElementName)));
}
static string FilterQueryVariables(string uriTemplate)
{
int variablesIndex = uriTemplate.IndexOf('?');
if (variablesIndex > 0)
{
return uriTemplate.Substring(0, variablesIndex);
}
return uriTemplate;
}
static void RenderMessageInformation(XElement table, OperationHelpInformation operationInfo, bool isRequest)
{
MessageHelpInformation info = isRequest ? operationInfo.Request : operationInfo.Response;
string direction = isRequest ? SR2.GetString(SR2.HelpPageRequest) : SR2.GetString(SR2.HelpPageResponse);
string nonLocalizedDirection = isRequest ? HtmlRequestXmlId : HtmlResponseXmlId;
if (info.BodyDescription != null)
{
table.Add(new XElement(HtmlTrElementName,
new XElement(HtmlTdElementName, direction),
new XElement(HtmlTdElementName, info.FormatString),
new XElement(HtmlTdElementName, info.BodyDescription)));
}
else
{
if (info.XmlExample != null || info.Schema != null)
{
XElement contentTd;
table.Add(new XElement(HtmlTrElementName,
new XElement(HtmlTdElementName, direction),
new XElement(HtmlTdElementName, "Xml"),
contentTd = new XElement(HtmlTdElementName)));
if (info.XmlExample != null)
{
contentTd.Add(new XElement(HtmlAElementName, new XAttribute(HtmlHrefAttributeName, "#" + (isRequest ? HtmlRequestXmlId : HtmlResponseXmlId)), SR2.GetString(SR2.HelpPageExample)));
if (info.Schema != null)
{
contentTd.Add(",");
}
}
if (info.Schema != null)
{
contentTd.Add(new XElement(HtmlAElementName, new XAttribute(HtmlHrefAttributeName, "#" + (isRequest ? HtmlRequestSchemaId : HtmlResponseSchemaId)), SR2.GetString(SR2.HelpPageSchema)));
}
}
if (info.JsonExample != null)
{
table.Add(new XElement(HtmlTrElementName,
new XElement(HtmlTdElementName, direction),
new XElement(HtmlTdElementName, "Json"),
new XElement(HtmlTdElementName,
new XElement(HtmlAElementName, new XAttribute(HtmlHrefAttributeName, "#" + (isRequest ? HtmlRequestJsonId : HtmlResponseJsonId)), SR2.GetString(SR2.HelpPageExample)))));
}
}
}
static void CreateOperationSamples(XElement element, OperationHelpInformation operationInfo)
{
if (operationInfo.Request.XmlExample != null)
{
element.Add(GenerateSampleXml(operationInfo.Request.XmlExample, SR2.GetString(SR2.HelpPageXmlRequest), HtmlRequestXmlId));
}
if (operationInfo.Request.JsonExample != null)
{
element.Add(AddSampleJson(operationInfo.Request.JsonExample, SR2.GetString(SR2.HelpPageJsonRequest), HtmlRequestJsonId));
}
if (operationInfo.Response.XmlExample != null)
{
element.Add(GenerateSampleXml(operationInfo.Response.XmlExample, SR2.GetString(SR2.HelpPageXmlResponse), HtmlResponseXmlId));
}
if (operationInfo.Response.JsonExample != null)
{
element.Add(AddSampleJson(operationInfo.Response.JsonExample, SR2.GetString(SR2.HelpPageJsonResponse), HtmlResponseJsonId));
}
if (operationInfo.Request.Schema != null)
{
element.Add(GenerateSampleXml(XmlSchemaToXElement(operationInfo.Request.Schema), SR2.GetString(SR2.HelpPageRequestSchema), HtmlRequestSchemaId));
int count = 0;
foreach (XmlSchema schema in operationInfo.Request.SchemaSet.Schemas())
{
if (schema.TargetNamespace != operationInfo.Request.Schema.TargetNamespace)
{
element.Add(GenerateSampleXml(XmlSchemaToXElement(schema), ++count == 1 ? SR2.GetString(SR2.HelpPageAdditionalRequestSchema) : null, HtmlRequestSchemaId));
}
}
}
if (operationInfo.Response.Schema != null)
{
element.Add(GenerateSampleXml(XmlSchemaToXElement(operationInfo.Response.Schema), SR2.GetString(SR2.HelpPageResponseSchema), HtmlResponseSchemaId));
int count = 0;
foreach (XmlSchema schema in operationInfo.Response.SchemaSet.Schemas())
{
if (schema.TargetNamespace != operationInfo.Response.Schema.TargetNamespace)
{
element.Add(GenerateSampleXml(XmlSchemaToXElement(schema), ++count == 1 ? SR2.GetString(SR2.HelpPageAdditionalResponseSchema) : null, HtmlResponseSchemaId));
}
}
}
}
private static XElement XmlSchemaToXElement(XmlSchema schema)
{
XmlWriterSettings settings = new XmlWriterSettings
{
CloseOutput = false,
Indent = true,
};
XDocument schemaDocument = new XDocument();
using (XmlWriter writer = XmlWriter.Create(schemaDocument.CreateWriter(), settings))
{
schema.Write(writer);
}
return schemaDocument.Root;
}
static XElement AddSample(object content, string title, string label)
{
if (String.IsNullOrEmpty(title))
{
return new XElement(HtmlPElementName,
new XElement(HtmlPreElementName, new XAttribute(HtmlClassAttributeName, label), content));
}
else
{
return new XElement(HtmlPElementName,
new XElement(HtmlAElementName, new XAttribute(HtmlNameAttributeName, "#" + label), title),
new XElement(HtmlPreElementName, new XAttribute(HtmlClassAttributeName, label), content));
}
}
static XElement GenerateSampleXml(XElement content, string title, string label)
{
StringBuilder sample = new StringBuilder();
using (XmlWriter writer = XmlTextWriter.Create(sample, new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }))
{
content.WriteTo(writer);
}
return AddSample(sample.ToString(), title, label);
}
static XElement AddSampleJson(XElement content, string title, string label)
{
StringBuilder sample = new StringBuilder();
using (MemoryStream stream = new MemoryStream())
{
using (XmlJsonWriter writer = new XmlJsonWriter())
{
writer.SetOutput(stream, Encoding.Unicode, false);
content.WriteTo(writer);
}
stream.Position = 0;
sample.Append(new StreamReader(stream, Encoding.Unicode).ReadToEnd());
}
int depth = 0;
bool inString = false;
for (int i = 0; i < sample.Length; ++i)
{
if (sample[i] == '"')
{
inString = !inString;
}
else if (sample[i] == '{')
{
sample.Insert(i + 1, "\n" + new String('\t', ++depth));
i += depth + 1;
}
else if (sample[i] == ',' && !inString)
{
sample.Insert(i + 1, "\n" + new String('\t', depth));
}
else if (sample[i] == '}' && depth > 0)
{
sample.Insert(i, "\n" + new String('\t', --depth));
i += depth + 1;
}
}
return AddSample(sample.ToString(), title, label);
}
static string BuildFullUriTemplate(Uri baseUri, string uriTemplate)
{
UriTemplate template = new UriTemplate(uriTemplate);
Uri result = template.BindByPosition(baseUri, template.PathSegmentVariableNames.Concat(template.QueryValueVariableNames).Select(name => "{" + name + "}").ToArray());
return result.ToString();
}
}
}

View File

@ -0,0 +1,56 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
using System;
using System.Globalization;
using System.Net;
using System.Runtime;
using System.Web;
using System.ServiceModel.Syndication;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
namespace System.ServiceModel.Web
{
class HelpOperationInvoker : IOperationInvoker
{
HelpPage helpPage;
IOperationInvoker unhandledDispatchOperation;
public const string OperationName = "HelpPageInvoke";
public HelpOperationInvoker(HelpPage helpPage, IOperationInvoker unhandledDispatchOperation)
{
this.helpPage = helpPage;
this.unhandledDispatchOperation = unhandledDispatchOperation;
}
public object[] AllocateInputs()
{
return new object[] { null };
}
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
outputs = null;
UriTemplateMatch match = (UriTemplateMatch)OperationContext.Current.IncomingMessageProperties[IncomingWebRequestContext.UriTemplateMatchResultsPropertyName];
return this.helpPage.Invoke(match);
}
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
}
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
}
public bool IsSynchronous
{
get { return true; }
}
}
}

View File

@ -0,0 +1,461 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime;
using System.Runtime.Serialization;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Syndication;
using System.ServiceModel.Web;
using System.Web;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
using System.Xml.Serialization;
class HelpPage
{
public const string OperationListHelpPageUriTemplate = "help";
public const string OperationHelpPageUriTemplate = "help/operations/{operation}";
const string HelpMethodName = "GetHelpPage";
const string HelpOperationMethodName = "GetOperationHelpPage";
DateTime startupTime = DateTime.UtcNow;
Dictionary<string, OperationHelpInformation> operationInfoDictionary;
NameValueCache<string> operationPageCache;
NameValueCache<string> helpPageCache;
public HelpPage(WebHttpBehavior behavior, ContractDescription description)
{
this.operationInfoDictionary = new Dictionary<string, OperationHelpInformation>();
this.operationPageCache = new NameValueCache<string>();
this.helpPageCache = new NameValueCache<string>();
foreach (OperationDescription od in description.Operations)
{
operationInfoDictionary.Add(od.Name, new OperationHelpInformation(behavior, od));
}
}
Message GetHelpPage()
{
Uri baseUri = UriTemplate.RewriteUri(OperationContext.Current.Channel.LocalAddress.Uri, WebOperationContext.Current.IncomingRequest.Headers[HttpRequestHeader.Host]);
string helpPage = this.helpPageCache.Lookup(baseUri.Authority);
if (String.IsNullOrEmpty(helpPage))
{
helpPage = HelpHtmlBuilder.CreateHelpPage(baseUri, operationInfoDictionary.Values).ToString();
if (HttpContext.Current == null)
{
this.helpPageCache.AddOrUpdate(baseUri.Authority, helpPage);
}
}
return WebOperationContext.Current.CreateTextResponse(helpPage, "text/html");
}
Message GetOperationHelpPage(string operation)
{
Uri requestUri = UriTemplate.RewriteUri(WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RequestUri, WebOperationContext.Current.IncomingRequest.Headers[HttpRequestHeader.Host]);
string helpPage = this.operationPageCache.Lookup(requestUri.AbsoluteUri);
if (String.IsNullOrEmpty(helpPage))
{
OperationHelpInformation operationInfo;
if (this.operationInfoDictionary.TryGetValue(operation, out operationInfo))
{
Uri baseUri = UriTemplate.RewriteUri(OperationContext.Current.Channel.LocalAddress.Uri, WebOperationContext.Current.IncomingRequest.Headers[HttpRequestHeader.Host]);
helpPage = HelpHtmlBuilder.CreateOperationHelpPage(baseUri, operationInfo).ToString();
if (HttpContext.Current == null)
{
this.operationPageCache.AddOrUpdate(requestUri.AbsoluteUri, helpPage);
}
}
else
{
throw System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new WebFaultException(HttpStatusCode.NotFound));
}
}
return WebOperationContext.Current.CreateTextResponse(helpPage, "text/html");
}
public static IEnumerable<KeyValuePair<UriTemplate, object>> GetOperationTemplatePairs()
{
return new KeyValuePair<UriTemplate, object>[]
{
new KeyValuePair<UriTemplate, object>(new UriTemplate(OperationListHelpPageUriTemplate), HelpMethodName),
new KeyValuePair<UriTemplate, object>(new UriTemplate(OperationHelpPageUriTemplate), HelpOperationMethodName)
};
}
public object Invoke(UriTemplateMatch match)
{
if (HttpContext.Current != null)
{
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.Public);
HttpContext.Current.Response.Cache.SetMaxAge(TimeSpan.MaxValue);
HttpContext.Current.Response.Cache.AddValidationCallback(new HttpCacheValidateHandler(this.CacheValidationCallback), this.startupTime);
HttpContext.Current.Response.Cache.SetValidUntilExpires(true);
}
switch ((string)match.Data)
{
case HelpMethodName:
return GetHelpPage();
case HelpOperationMethodName:
return GetOperationHelpPage(match.BoundVariables["operation"]);
default:
return null;
}
}
void CacheValidationCallback(HttpContext context, object state, ref HttpValidationStatus result)
{
if (((DateTime)state) == this.startupTime)
{
result = HttpValidationStatus.Valid;
}
else
{
result = HttpValidationStatus.Invalid;
}
}
}
class OperationHelpInformation
{
OperationDescription od;
WebHttpBehavior behavior;
MessageHelpInformation request;
MessageHelpInformation response;
internal OperationHelpInformation(WebHttpBehavior behavior, OperationDescription od)
{
this.od = od;
this.behavior = behavior;
}
public string Name
{
get
{
return od.Name;
}
}
public string UriTemplate
{
get
{
return UriTemplateClientFormatter.GetUTStringOrDefault(od);
}
}
public string Method
{
get
{
return WebHttpBehavior.GetWebMethod(od);
}
}
public string Description
{
get
{
return WebHttpBehavior.GetDescription(od);
}
}
public string JavascriptCallbackParameterName
{
get
{
if (this.Response.SupportsJson && this.Method == WebHttpBehavior.GET)
{
return behavior.JavascriptCallbackParameterName;
}
return null;
}
}
public WebMessageBodyStyle BodyStyle
{
get
{
return behavior.GetBodyStyle(od);
}
}
public MessageHelpInformation Request
{
get
{
if (this.request == null)
{
this.request = new MessageHelpInformation(od, true, GetRequestBodyType(od, this.UriTemplate),
this.BodyStyle == WebMessageBodyStyle.WrappedRequest || this.BodyStyle == WebMessageBodyStyle.Wrapped);
}
return this.request;
}
}
public MessageHelpInformation Response
{
get
{
if (this.response == null)
{
this.response = new MessageHelpInformation(od, false, GetResponseBodyType(od),
this.BodyStyle == WebMessageBodyStyle.WrappedResponse || this.BodyStyle == WebMessageBodyStyle.Wrapped);
}
return this.response;
}
}
static Type GetResponseBodyType(OperationDescription od)
{
if (WebHttpBehavior.IsUntypedMessage(od.Messages[1]))
{
return typeof(Message);
}
else if (WebHttpBehavior.IsTypedMessage(od.Messages[1]))
{
return od.Messages[1].MessageType;
}
else if (od.Messages[1].Body.Parts.Count > 0)
{
// If it is more than 0 the response is wrapped and not supported
return null;
}
else
{
return (od.Messages[1].Body.ReturnValue.Type);
}
}
static Type GetRequestBodyType(OperationDescription od, string uriTemplate)
{
if (od.Behaviors.Contains(typeof(WebGetAttribute)))
{
return typeof(void);
}
else if (WebHttpBehavior.IsUntypedMessage(od.Messages[0]))
{
return typeof(Message);
}
else if (WebHttpBehavior.IsTypedMessage(od.Messages[0]))
{
return od.Messages[0].MessageType;
}
else
{
UriTemplate template = new UriTemplate(uriTemplate);
IEnumerable<MessagePartDescription> parts =
from part in od.Messages[0].Body.Parts
where !template.PathSegmentVariableNames.Contains(part.Name.ToUpperInvariant()) && !template.QueryValueVariableNames.Contains(part.Name.ToUpperInvariant())
select part;
if (parts.Count() == 1)
{
return parts.First().Type;
}
else if (parts.Count() == 0)
{
return typeof(void);
}
else
{
// The request is wrapped and not supported
return null;
}
}
}
}
class MessageHelpInformation
{
public string BodyDescription { get; private set; }
public string FormatString { get; private set; }
public Type Type { get; private set; }
public bool SupportsJson { get; private set; }
public XmlSchemaSet SchemaSet { get; private set; }
public XmlSchema Schema { get; private set; }
public XElement XmlExample { get; private set; }
public XElement JsonExample { get; private set; }
internal MessageHelpInformation(OperationDescription od, bool isRequest, Type type, bool wrapped)
{
this.Type = type;
this.SupportsJson = WebHttpBehavior.SupportsJsonFormat(od);
string direction = isRequest ? SR2.GetString(SR2.HelpPageRequest) : SR2.GetString(SR2.HelpPageResponse);
if (wrapped && !typeof(void).Equals(type))
{
this.BodyDescription = SR2.GetString(SR2.HelpPageBodyIsWrapped, direction);
this.FormatString = SR2.GetString(SR2.HelpPageUnknown);
}
else if (typeof(void).Equals(type))
{
this.BodyDescription = SR2.GetString(SR2.HelpPageBodyIsEmpty, direction);
this.FormatString = SR2.GetString(SR2.HelpPageNA);
}
else if (typeof(Message).IsAssignableFrom(type))
{
this.BodyDescription = SR2.GetString(SR2.HelpPageIsMessage, direction);
this.FormatString = SR2.GetString(SR2.HelpPageUnknown);
}
else if (typeof(Stream).IsAssignableFrom(type))
{
this.BodyDescription = SR2.GetString(SR2.HelpPageIsStream, direction);
this.FormatString = SR2.GetString(SR2.HelpPageUnknown);
}
else if (typeof(Atom10FeedFormatter).IsAssignableFrom(type))
{
this.BodyDescription = SR2.GetString(SR2.HelpPageIsAtom10Feed, direction);
this.FormatString = WebMessageFormat.Xml.ToString();
}
else if (typeof(Atom10ItemFormatter).IsAssignableFrom(type))
{
this.BodyDescription = SR2.GetString(SR2.HelpPageIsAtom10Entry, direction);
this.FormatString = WebMessageFormat.Xml.ToString();
}
else if (typeof(AtomPub10ServiceDocumentFormatter).IsAssignableFrom(type))
{
this.BodyDescription = SR2.GetString(SR2.HelpPageIsAtomPubServiceDocument, direction);
this.FormatString = WebMessageFormat.Xml.ToString();
}
else if (typeof(AtomPub10CategoriesDocumentFormatter).IsAssignableFrom(type))
{
this.BodyDescription = SR2.GetString(SR2.HelpPageIsAtomPubCategoriesDocument, direction);
this.FormatString = WebMessageFormat.Xml.ToString();
}
else if (typeof(Rss20FeedFormatter).IsAssignableFrom(type))
{
this.BodyDescription = SR2.GetString(SR2.HelpPageIsRSS20Feed, direction);
this.FormatString = WebMessageFormat.Xml.ToString();
}
else if (typeof(SyndicationFeedFormatter).IsAssignableFrom(type))
{
this.BodyDescription = SR2.GetString(SR2.HelpPageIsSyndication, direction);
this.FormatString = WebMessageFormat.Xml.ToString();
}
else if (typeof(XElement).IsAssignableFrom(type) || typeof(XmlElement).IsAssignableFrom(type))
{
this.BodyDescription = SR2.GetString(SR2.HelpPageIsXML, direction);
this.FormatString = WebMessageFormat.Xml.ToString();
}
else
{
try
{
bool usesXmlSerializer = od.Behaviors.Contains(typeof(XmlSerializerOperationBehavior));
XmlQualifiedName name;
this.SchemaSet = new XmlSchemaSet();
IDictionary<XmlQualifiedName, Type> knownTypes = new Dictionary<XmlQualifiedName, Type>();
if (usesXmlSerializer)
{
XmlReflectionImporter importer = new XmlReflectionImporter();
XmlTypeMapping typeMapping = importer.ImportTypeMapping(this.Type);
name = new XmlQualifiedName(typeMapping.ElementName, typeMapping.Namespace);
XmlSchemas schemas = new XmlSchemas();
XmlSchemaExporter exporter = new XmlSchemaExporter(schemas);
exporter.ExportTypeMapping(typeMapping);
foreach (XmlSchema schema in schemas)
{
this.SchemaSet.Add(schema);
}
}
else
{
XsdDataContractExporter exporter = new XsdDataContractExporter();
List<Type> listTypes = new List<Type>(od.KnownTypes);
bool isQueryable;
Type dataContractType = DataContractSerializerOperationFormatter.GetSubstituteDataContractType(this.Type, out isQueryable);
listTypes.Add(dataContractType);
exporter.Export(listTypes);
if (!exporter.CanExport(dataContractType))
{
this.BodyDescription = SR2.GetString(SR2.HelpPageCouldNotGenerateSchema);
this.FormatString = SR2.GetString(SR2.HelpPageUnknown);
return;
}
name = exporter.GetRootElementName(dataContractType);
DataContract typeDataContract = DataContract.GetDataContract(dataContractType);
if (typeDataContract.KnownDataContracts != null)
{
foreach (XmlQualifiedName dataContractName in typeDataContract.KnownDataContracts.Keys)
{
knownTypes.Add(dataContractName, typeDataContract.KnownDataContracts[dataContractName].UnderlyingType);
}
}
foreach (Type knownType in od.KnownTypes)
{
XmlQualifiedName knownTypeName = exporter.GetSchemaTypeName(knownType);
if (!knownTypes.ContainsKey(knownTypeName))
{
knownTypes.Add(knownTypeName, knownType);
}
}
foreach (XmlSchema schema in exporter.Schemas.Schemas())
{
this.SchemaSet.Add(schema);
}
}
this.SchemaSet.Compile();
XmlWriterSettings settings = new XmlWriterSettings
{
CloseOutput = false,
Indent = true,
};
if (this.SupportsJson)
{
XDocument exampleDocument = new XDocument();
using (XmlWriter writer = XmlWriter.Create(exampleDocument.CreateWriter(), settings))
{
HelpExampleGenerator.GenerateJsonSample(this.SchemaSet, name, writer, knownTypes);
}
this.JsonExample = exampleDocument.Root;
}
if (name.Namespace != "http://schemas.microsoft.com/2003/10/Serialization/")
{
foreach (XmlSchema schema in this.SchemaSet.Schemas(name.Namespace))
{
this.Schema = schema;
}
}
XDocument XmlExampleDocument = new XDocument();
using (XmlWriter writer = XmlWriter.Create(XmlExampleDocument.CreateWriter(), settings))
{
HelpExampleGenerator.GenerateXmlSample(this.SchemaSet, name, writer);
}
this.XmlExample = XmlExampleDocument.Root;
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
this.BodyDescription = SR2.GetString(SR2.HelpPageCouldNotGenerateSchema);
this.FormatString = SR2.GetString(SR2.HelpPageUnknown);
this.Schema = null;
this.JsonExample = null;
this.XmlExample = null;
}
}
}
}
}

View File

@ -0,0 +1,118 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634 // Stops compiler from warning about unknown warnings (for Presharp)
namespace System.ServiceModel.Dispatcher
{
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Collections.Generic;
using System.Xml;
using System.Runtime.Serialization;
using DiagnosticUtility = System.ServiceModel.DiagnosticUtility;
using System.IO;
using System.Collections.Specialized;
using System.Net;
class HttpStreamFormatter : IDispatchMessageFormatter, IClientMessageFormatter
{
string contractName;
string contractNs;
string operationName;
public HttpStreamFormatter(OperationDescription operation)
{
if (operation == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operation");
}
this.operationName = operation.Name;
this.contractName = operation.DeclaringContract.Name;
this.contractNs = operation.DeclaringContract.Namespace;
}
public object DeserializeReply(Message message, object[] parameters)
{
return GetStreamFromMessage(message, false);
}
public void DeserializeRequest(Message message, object[] parameters)
{
parameters[0] = GetStreamFromMessage(message, true);
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
Message message = CreateMessageFromStream(result);
if (result == null)
{
SingleBodyParameterMessageFormatter.SuppressReplyEntityBody(message);
}
return message;
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
Message message = CreateMessageFromStream(parameters[0]);
if (parameters[0] == null)
{
SingleBodyParameterMessageFormatter.SuppressRequestEntityBody(message);
}
return message;
}
internal static bool IsEmptyMessage(Message message)
{
return message.IsEmpty;
}
Message CreateMessageFromStream(object data)
{
Message result;
if (data == null)
{
result = Message.CreateMessage(MessageVersion.None, (string) null);
}
else
{
Stream streamData = data as Stream;
if (streamData == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR2.GetString(SR2.ParameterIsNotStreamType, data.GetType(), this.operationName, this.contractName, this.contractNs)));
}
result = ByteStreamMessage.CreateMessage(streamData);
result.Properties[WebBodyFormatMessageProperty.Name] = WebBodyFormatMessageProperty.RawProperty;
}
return result;
}
Stream GetStreamFromMessage(Message message, bool isRequest)
{
object prop;
message.Properties.TryGetValue(WebBodyFormatMessageProperty.Name, out prop);
WebBodyFormatMessageProperty formatProperty = (prop as WebBodyFormatMessageProperty);
if (formatProperty == null)
{
// GET and DELETE do not go through the encoder
if (IsEmptyMessage(message))
{
return new MemoryStream();
}
else
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR2.GetString(SR2.MessageFormatPropertyNotFound, this.operationName, this.contractName, this.contractNs)));
}
}
if (formatProperty.Format != WebContentFormat.Raw)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR2.GetString(SR2.InvalidHttpMessageFormat, this.operationName, this.contractName, this.contractNs, formatProperty.Format, WebContentFormat.Raw)));
}
return new StreamFormatter.MessageBodyStream(message, null, null, HttpStreamMessage.StreamElementName, string.Empty, isRequest);
}
}
}

View File

@ -0,0 +1,141 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634, 1691
namespace System.ServiceModel.Dispatcher
{
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Diagnostics;
using System.ServiceModel.Web;
using System.ServiceModel.Syndication;
using System.Xml.Linq;
using System.ServiceModel.Description;
internal class HttpUnhandledOperationInvoker : IOperationInvoker
{
const string HtmlContentType = "text/html; charset=UTF-8";
public bool IsSynchronous
{
get { return true; }
}
public object[] AllocateInputs()
{
return new object[1];
}
public Uri HelpUri { get; set; }
[SuppressMessage("Reliability", "Reliability104:CaughtAndHandledExceptionsRule", Justification = "The exception is thrown for tracing purposes")]
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
Message message = inputs[0] as Message;
outputs = null;
#pragma warning disable 56506 // [....], message.Properties is never null
if (message == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
SR2.GetString(SR2.HttpUnhandledOperationInvokerCalledWithoutMessage)));
}
// We might be here because we desire a redirect...
Uri newLocation = null;
Uri to = message.Headers.To;
if (message.Properties.ContainsKey(WebHttpDispatchOperationSelector.RedirectPropertyName))
{
newLocation = message.Properties[WebHttpDispatchOperationSelector.RedirectPropertyName] as Uri;
}
if (newLocation != null && to != null)
{
// ...redirect
Message redirectResult = WebOperationContext.Current.CreateStreamResponse(s => HelpHtmlBuilder.CreateTransferRedirectPage(to.AbsoluteUri, newLocation.AbsoluteUri).Save(s, SaveOptions.OmitDuplicateNamespaces), Atom10Constants.HtmlMediaType);
WebOperationContext.Current.OutgoingResponse.Location = newLocation.AbsoluteUri;
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.TemporaryRedirect;
WebOperationContext.Current.OutgoingResponse.ContentType = HtmlContentType;
// Note that no exception is thrown along this path, even if the debugger is attached
if (DiagnosticUtility.ShouldTraceInformation)
{
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.WebRequestRedirect,
SR2.GetString(SR2.TraceCodeWebRequestRedirect, to, newLocation));
}
return redirectResult;
}
// otherwise we are here to issue either a 404 or a 405
bool uriMatched = false;
if (message.Properties.ContainsKey(WebHttpDispatchOperationSelector.HttpOperationSelectorUriMatchedPropertyName))
{
uriMatched = (bool) message.Properties[WebHttpDispatchOperationSelector.HttpOperationSelectorUriMatchedPropertyName];
}
#pragma warning enable 56506
Message result = null;
Uri helpUri = this.HelpUri != null ? UriTemplate.RewriteUri(this.HelpUri, WebOperationContext.Current.IncomingRequest.Headers[HttpRequestHeader.Host]) : null;
if (uriMatched)
{
WebHttpDispatchOperationSelectorData allowedMethodsData = null;
if (message.Properties.TryGetValue(WebHttpDispatchOperationSelector.HttpOperationSelectorDataPropertyName, out allowedMethodsData))
{
WebOperationContext.Current.OutgoingResponse.Headers[HttpResponseHeader.Allow] = allowedMethodsData.AllowHeader;
}
result = WebOperationContext.Current.CreateStreamResponse(s => HelpHtmlBuilder.CreateMethodNotAllowedPage(helpUri).Save(s, SaveOptions.OmitDuplicateNamespaces), Atom10Constants.HtmlMediaType);
}
else
{
result = WebOperationContext.Current.CreateStreamResponse(s => HelpHtmlBuilder.CreateEndpointNotFound(helpUri).Save(s, SaveOptions.OmitDuplicateNamespaces), Atom10Constants.HtmlMediaType);
}
WebOperationContext.Current.OutgoingResponse.StatusCode = uriMatched ? HttpStatusCode.MethodNotAllowed : HttpStatusCode.NotFound;
WebOperationContext.Current.OutgoingResponse.ContentType = HtmlContentType;
try
{
if (!uriMatched)
{
if (Debugger.IsAttached)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR2.GetString(SR2.WebRequestDidNotMatchOperation,
OperationContext.Current.IncomingMessageHeaders.To)));
}
else
{
DiagnosticUtility.TraceHandledException(new InvalidOperationException(SR2.GetString(SR2.WebRequestDidNotMatchOperation,
OperationContext.Current.IncomingMessageHeaders.To)), TraceEventType.Warning);
}
}
else
{
if (Debugger.IsAttached)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR2.GetString(SR2.WebRequestDidNotMatchMethod,
WebOperationContext.Current.IncomingRequest.Method, OperationContext.Current.IncomingMessageHeaders.To)));
}
else
{
DiagnosticUtility.TraceHandledException(new InvalidOperationException(SR2.GetString(SR2.WebRequestDidNotMatchMethod,
WebOperationContext.Current.IncomingRequest.Method, OperationContext.Current.IncomingMessageHeaders.To)), TraceEventType.Warning);
}
}
}
catch (InvalidOperationException)
{
// catch the exception - its only used for tracing
}
return result;
}
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
}
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
}
}
}

View File

@ -0,0 +1,86 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634, 1691
namespace System.ServiceModel.Dispatcher
{
using System.Net;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.Web;
using System.ServiceModel.Description;
using System.Diagnostics;
using System.ServiceModel.Diagnostics;
class JavascriptCallbackMessageInspector : IDispatchMessageInspector
{
internal static readonly string applicationJavaScriptMediaType = "application/x-javascript";
public JavascriptCallbackMessageInspector(string callbackParameterName)
{
this.CallbackParameterName = callbackParameterName;
if (DiagnosticUtility.ShouldTraceInformation)
{
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.JsonpCallbackNameSet, SR2.GetString(SR2.TraceCodeJsonpCallbackNameSet, callbackParameterName));
}
}
string CallbackParameterName { get; set; }
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
if (HttpContext.Current != null &&
HttpContext.Current.User != null &&
HttpContext.Current.User.Identity != null &&
HttpContext.Current.User.Identity.IsAuthenticated)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR2.CrossDomainJavascriptAuthNotSupported));
}
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
WebBodyFormatMessageProperty formatProperty;
JavascriptCallbackResponseMessageProperty javascriptCallbackResponseMessageProperty = null;
if (reply.Properties.TryGetValue<WebBodyFormatMessageProperty>(WebBodyFormatMessageProperty.Name, out formatProperty) &&
formatProperty != null &&
formatProperty.Format == WebContentFormat.Json)
{
if (!reply.Properties.TryGetValue<JavascriptCallbackResponseMessageProperty>(JavascriptCallbackResponseMessageProperty.Name, out javascriptCallbackResponseMessageProperty)
|| javascriptCallbackResponseMessageProperty == null)
{
javascriptCallbackResponseMessageProperty = WebHttpBehavior.TrySetupJavascriptCallback(this.CallbackParameterName);
if (javascriptCallbackResponseMessageProperty != null)
{
reply.Properties.Add(JavascriptCallbackResponseMessageProperty.Name, javascriptCallbackResponseMessageProperty);
}
}
if (javascriptCallbackResponseMessageProperty != null)
{
HttpResponseMessageProperty property;
if (reply.Properties.TryGetValue<HttpResponseMessageProperty>(HttpResponseMessageProperty.Name, out property) &&
property != null)
{
property.Headers[HttpResponseHeader.ContentType] = applicationJavaScriptMediaType;
if (javascriptCallbackResponseMessageProperty.StatusCode == null)
{
javascriptCallbackResponseMessageProperty.StatusCode = property.StatusCode;
}
property.StatusCode = HttpStatusCode.OK;
if (property.SuppressEntityBody)
{
property.SuppressEntityBody = false;
Message nullJsonMessage = WebOperationContext.Current.CreateJsonResponse<object>(null);
nullJsonMessage.Properties.CopyProperties(reply.Properties);
reply = nullJsonMessage;
}
}
}
}
}
}
}

View File

@ -0,0 +1,55 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System.Collections.Generic;
using System.Runtime.Serialization.Json;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.Text;
using System.Xml;
class JsonFormatMapping : MultiplexingFormatMapping
{
public static readonly WebContentFormat WebContentFormat = WebContentFormat.Json;
static readonly string defaultMediaType = JsonGlobals.applicationJsonMediaType;
static Dictionary<Encoding, MessageEncoder> encoders = new Dictionary<Encoding, MessageEncoder>();
static object thisLock = new object();
public JsonFormatMapping(Encoding writeEncoding, WebContentTypeMapper contentTypeMapper)
: base(writeEncoding, contentTypeMapper)
{ }
public override WebContentFormat ContentFormat
{
get { return JsonFormatMapping.WebContentFormat; }
}
public override WebMessageFormat MessageFormat
{
get { return WebMessageFormat.Json; }
}
public override string DefaultMediaType
{
get { return JsonFormatMapping.defaultMediaType; }
}
protected override MessageEncoder Encoder
{
get
{
lock (thisLock)
{
if (!JsonFormatMapping.encoders.ContainsKey(this.writeEncoding))
{
JsonFormatMapping.encoders[this.writeEncoding] = new JsonMessageEncoderFactory(this.writeEncoding, 0, 0, new XmlDictionaryReaderQuotas(), false).Encoder;
}
}
return JsonFormatMapping.encoders[this.writeEncoding];
}
}
}
}

View File

@ -0,0 +1,221 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634, 1691
namespace System.ServiceModel.Dispatcher
{
using System;
using System.IO;
using System.Collections.Specialized;
using System.Globalization;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Web;
using System.Xml;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
public class JsonQueryStringConverter : QueryStringConverter
{
DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior = null;
OperationDescription operationDescription = null;
public JsonQueryStringConverter() : base()
{
}
internal JsonQueryStringConverter(OperationDescription operationDescription)
: base()
{
if (operationDescription == null)
{
throw System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operationDescription");
}
this.operationDescription = operationDescription;
this.dataContractSerializerOperationBehavior = this.operationDescription.Behaviors.Find<DataContractSerializerOperationBehavior>();
}
public override bool CanConvert(Type type)
{
XsdDataContractExporter exporter = new XsdDataContractExporter();
return exporter.CanExport(type);
}
public override object ConvertStringToValue(string parameter, Type parameterType)
{
if (parameterType == null)
{
throw System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parameterType");
}
switch (Type.GetTypeCode(parameterType))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
case TypeCode.Boolean:
// base.ConvertStringToValue handles parameter == null case.
return base.ConvertStringToValue(parameter, parameterType);
case TypeCode.Char:
case TypeCode.String:
case TypeCode.DateTime:
// base.ConvertStringToValue handles parameter == null case.
// IsFirstCharacterReservedCharacter returns false for null strings.
if (IsFirstCharacterReservedCharacter(parameter, '"'))
{
return CreateJsonDeserializedObject(parameter.Trim(), parameterType);
}
return base.ConvertStringToValue(parameter, parameterType);
default:
{
if (parameterType == typeof(Guid))
{
if (parameter == null)
{
return default(Guid);
}
if (IsFirstCharacterReservedCharacter(parameter, '"'))
{
return CreateJsonDeserializedObject(parameter.Trim(), parameterType);
}
return base.ConvertStringToValue(parameter, parameterType);
}
else if (parameterType == typeof(Uri))
{
if (parameter == null)
{
return default(Uri);
}
if (IsFirstCharacterReservedCharacter(parameter, '"'))
{
return CreateJsonDeserializedObject(parameter.Trim(), parameterType);
}
return base.ConvertStringToValue(parameter, parameterType);
}
else if (parameterType == typeof(TimeSpan))
{
if (parameter == null)
{
return default(TimeSpan);
}
if (IsFirstCharacterReservedCharacter(parameter, '"'))
{
return CreateJsonDeserializedObject(parameter.Trim(), parameterType);
}
return base.ConvertStringToValue(parameter, parameterType);
}
else if (parameterType == typeof(byte[]))
{
if (parameter == null)
{
return default(byte[]);
}
if (IsFirstCharacterReservedCharacter(parameter, '['))
{
return CreateJsonDeserializedObject(parameter.Trim(), parameterType);
}
return base.ConvertStringToValue(parameter, parameterType);
}
else if (parameterType == typeof(DateTimeOffset))
{
if (parameter == null)
{
return default(DateTimeOffset);
}
if (IsFirstCharacterReservedCharacter(parameter, '{'))
{
return CreateJsonDeserializedObject(parameter.Trim(), parameterType);
}
return base.ConvertStringToValue(parameter, parameterType);
}
else if (parameterType == typeof(object))
{
if (parameter == null)
{
return default(object);
}
if (IsFirstCharacterReservedCharacter(parameter, '{'))
{
return CreateJsonDeserializedObject(parameter.Trim(), parameterType);
}
return base.ConvertStringToValue(parameter, parameterType);
}
if (parameter == null)
{
return null;
}
return CreateJsonDeserializedObject(parameter.Trim(), parameterType);
}
}
}
public override string ConvertValueToString(object parameter, Type parameterType)
{
if (parameter == null)
{
return null;
}
MemoryStream memoryStream = new MemoryStream();
XmlDictionaryWriter jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(memoryStream, Encoding.UTF8);
GetDataContractJsonSerializer(parameterType).WriteObject(jsonWriter, parameter);
jsonWriter.Flush();
memoryStream.Seek(0, SeekOrigin.Begin);
return Encoding.UTF8.GetString(memoryStream.GetBuffer(), (int) memoryStream.Position, (int) memoryStream.Length);
}
object CreateJsonDeserializedObject(string parameter, Type parameterType)
{
byte[] byteArray = Encoding.UTF8.GetBytes(parameter);
XmlDictionaryReader jsonReader = JsonReaderWriterFactory.CreateJsonReader
(byteArray, 0, byteArray.Length, Encoding.UTF8, XmlDictionaryReaderQuotas.Max, null);
return GetDataContractJsonSerializer(parameterType).ReadObject(jsonReader);
}
DataContractJsonSerializer GetDataContractJsonSerializer(Type parameterType)
{
if (this.operationDescription == null)
{
return new DataContractJsonSerializer(parameterType);
}
else if (this.dataContractSerializerOperationBehavior == null)
{
return new DataContractJsonSerializer(parameterType, operationDescription.KnownTypes);
}
else
{
return new DataContractJsonSerializer(parameterType, this.operationDescription.KnownTypes, this.dataContractSerializerOperationBehavior.maxItemsInObjectGraph,
this.dataContractSerializerOperationBehavior.IgnoreExtensionDataObject, this.dataContractSerializerOperationBehavior.DataContractSurrogate, false); //alwaysEmitTypeInformation
}
}
bool IsFirstCharacterReservedCharacter(string parameter, char reservedCharacter)
{
if (parameter == null)
{
return false;
}
string localParameter = parameter.Trim();
if (localParameter == string.Empty)
{
return false;
}
if (localParameter[0] == reservedCharacter)
{
return true;
}
return false;
}
}
}

View File

@ -0,0 +1,119 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System;
using System.Collections.Generic;
using System.Net.Mime;
using System.Runtime;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
class MultiplexingDispatchMessageFormatter : IDispatchMessageFormatter
{
Dictionary<WebMessageFormat, IDispatchMessageFormatter> formatters;
WebMessageFormat defaultFormat;
Dictionary<WebMessageFormat, string> defaultContentTypes;
public WebMessageFormat DefaultFormat
{
get { return this.defaultFormat; }
}
public Dictionary<WebMessageFormat, string> DefaultContentTypes
{
get
{
return this.defaultContentTypes;
}
}
public MultiplexingDispatchMessageFormatter(Dictionary<WebMessageFormat, IDispatchMessageFormatter> formatters, WebMessageFormat defaultFormat)
{
if (formatters == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("formatters");
}
this.formatters = formatters;
this.defaultFormat = defaultFormat;
this.defaultContentTypes = new Dictionary<WebMessageFormat, string>();
Fx.Assert(this.formatters.ContainsKey(this.defaultFormat), "The default format should always be included in the dictionary of formatters.");
}
public void DeserializeRequest(Message message, object[] parameters)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR2.GetString(SR2.SerializingRequestNotSupportedByFormatter, this)));
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
WebOperationContext currentContext = WebOperationContext.Current;
OutgoingWebResponseContext outgoingResponse = null;
if (currentContext != null)
{
outgoingResponse = currentContext.OutgoingResponse;
}
WebMessageFormat format = this.defaultFormat;
if (outgoingResponse != null)
{
WebMessageFormat? nullableFormat = outgoingResponse.Format;
if (nullableFormat.HasValue)
{
format = nullableFormat.Value;
}
}
if (!this.formatters.ContainsKey(format))
{
string operationName = "<null>";
if (OperationContext.Current != null)
{
MessageProperties messageProperties = OperationContext.Current.IncomingMessageProperties;
if (messageProperties.ContainsKey(WebHttpDispatchOperationSelector.HttpOperationNamePropertyName))
{
operationName = messageProperties[WebHttpDispatchOperationSelector.HttpOperationNamePropertyName] as string;
}
}
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR2.GetString(SR2.OperationDoesNotSupportFormat, operationName, format.ToString())));
}
if (outgoingResponse != null && string.IsNullOrEmpty(outgoingResponse.ContentType))
{
string automatedSelectionContentType = outgoingResponse.AutomatedFormatSelectionContentType;
if (!string.IsNullOrEmpty(automatedSelectionContentType))
{
// Don't set the content-type if it is default xml for backwards compatiabilty
if (!string.Equals(automatedSelectionContentType, defaultContentTypes[WebMessageFormat.Xml], StringComparison.OrdinalIgnoreCase))
{
outgoingResponse.ContentType = automatedSelectionContentType;
}
}
else
{
// Don't set the content-type if it is default xml for backwards compatiabilty
if (format != WebMessageFormat.Xml)
{
outgoingResponse.ContentType = defaultContentTypes[format];
}
}
}
Message message = this.formatters[format].SerializeReply(messageVersion, parameters, result);
return message;
}
public bool SupportsMessageFormat(WebMessageFormat format)
{
return this.formatters.ContainsKey(format);
}
}
}

View File

@ -0,0 +1,83 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System.Net.Mime;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.Text;
abstract class MultiplexingFormatMapping
{
protected Encoding writeEncoding;
protected string writeCharset;
protected WebContentTypeMapper contentTypeMapper;
abstract public WebMessageFormat MessageFormat { get; }
abstract public WebContentFormat ContentFormat { get; }
abstract public string DefaultMediaType { get; }
abstract protected MessageEncoder Encoder { get; }
ContentType defaultContentType;
public ContentType DefaultContentType
{
get
{
if (defaultContentType == null)
{
defaultContentType = new ContentType(this.DefaultMediaType) { CharSet = this.writeCharset };
}
return defaultContentType;
}
}
public MultiplexingFormatMapping(Encoding writeEncoding, WebContentTypeMapper contentTypeMapper)
{
if (writeEncoding == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writeEncoding");
}
this.writeEncoding = writeEncoding;
this.writeCharset = TextEncoderDefaults.EncodingToCharSet(writeEncoding);
this.contentTypeMapper = contentTypeMapper;
}
public bool CanFormatResponse(ContentType acceptHeaderElement, bool matchCharset, out ContentType contentType)
{
if (acceptHeaderElement == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("acceptHeaderElement");
}
// Scrub the content type so that it is only mediaType and the charset
string charset = acceptHeaderElement.CharSet;
contentType = new ContentType(acceptHeaderElement.MediaType);
contentType.CharSet = this.DefaultContentType.CharSet;
string contentTypeStr = contentType.ToString();
if (matchCharset &&
!string.IsNullOrEmpty(charset) &&
!string.Equals(charset, this.DefaultContentType.CharSet, StringComparison.OrdinalIgnoreCase))
{
return false;
}
if (this.contentTypeMapper != null &&
this.contentTypeMapper.GetMessageFormatForContentType(contentType.MediaType) == this.ContentFormat)
{
return true;
}
if (this.Encoder.IsContentTypeSupported(contentTypeStr) &&
(charset == null || contentType.CharSet == this.DefaultContentType.CharSet))
{
return true;
}
contentType = null;
return false;
}
}
}

View File

@ -0,0 +1,61 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading;
namespace System.ServiceModel.Dispatcher
{
class NameValueCache<T>
{
// The NameValueCache implements a structure that uses a dictionary to map objects to
// indices of an array of cache entries. This allows us to store the cache entries in
// the order in which they were added to the cache, and yet still lookup any cache entry.
// The eviction policy of the cache is to evict the least-recently-added cache entry.
// Using a pointer to the next available cache entry in the array, we can always be sure
// that the given entry is the oldest entry.
Hashtable cache;
string[] currentKeys;
int nextAvailableCacheIndex;
object cachelock;
internal const int maxNumberofEntriesInCache = 16;
public NameValueCache()
: this(maxNumberofEntriesInCache)
{
}
public NameValueCache(int maxCacheEntries)
{
cache = new Hashtable();
currentKeys = new string[maxCacheEntries];
cachelock = new object();
}
public T Lookup(string key)
{
return (T)cache[key];
}
public void AddOrUpdate(string key, T value)
{
lock (cache)
{
if (!cache.ContainsKey(key))
{
if (!String.IsNullOrEmpty(currentKeys[nextAvailableCacheIndex]))
{
cache.Remove(currentKeys[nextAvailableCacheIndex]);
}
currentKeys[nextAvailableCacheIndex] = key;
nextAvailableCacheIndex = ++nextAvailableCacheIndex % currentKeys.Length;
}
cache[key] = value;
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More