Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx35 / System.ServiceModel.Web / System / ServiceModel / Dispatcher / FormatSelectingMessageInspector.cs / 1305376 / FormatSelectingMessageInspector.cs
//------------------------------------------------------------
// 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 wildcardMediaTypes = new List() { "application", "text" };
List mappings;
Dictionary formatters;
Dictionary> 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 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();
this.caches = new Dictionary>();
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(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 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 = IncomingWebRequestContext.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; }
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- TaskHelper.cs
- IChannel.cs
- ResXBuildProvider.cs
- UndoUnit.cs
- GeometryCombineModeValidation.cs
- SafeEventLogWriteHandle.cs
- Column.cs
- QilGeneratorEnv.cs
- CodeDirectiveCollection.cs
- StreamUpgradeInitiator.cs
- sqlinternaltransaction.cs
- ObjectDataSourceView.cs
- XmlParserContext.cs
- XPathItem.cs
- XmlTypeAttribute.cs
- VirtualPathExtension.cs
- StylusDevice.cs
- Schema.cs
- BindingCompleteEventArgs.cs
- TripleDESCryptoServiceProvider.cs
- SqlFactory.cs
- XmlObjectSerializerReadContextComplexJson.cs
- ParserExtension.cs
- TextParagraphCache.cs
- OracleDataAdapter.cs
- DesignerProperties.cs
- Utils.cs
- WebPartDeleteVerb.cs
- WindowsListViewItemStartMenu.cs
- Speller.cs
- SimpleFileLog.cs
- SafeRegistryHandle.cs
- QuaternionAnimationBase.cs
- PreviewPageInfo.cs
- LocationFactory.cs
- MailMessageEventArgs.cs
- GridViewColumnCollection.cs
- AttributeEmitter.cs
- Tile.cs
- Rss20FeedFormatter.cs
- BinaryWriter.cs
- PropertyValueChangedEvent.cs
- ETagAttribute.cs
- CircleHotSpot.cs
- ToolStripLocationCancelEventArgs.cs
- ConnectionStringsExpressionBuilder.cs
- httpstaticobjectscollection.cs
- XPathCompileException.cs
- SqlFacetAttribute.cs
- AxWrapperGen.cs
- ReaderOutput.cs
- Viewport3DAutomationPeer.cs
- EncryptedData.cs
- CqlLexerHelpers.cs
- DataPointer.cs
- DispatcherProcessingDisabled.cs
- ConnectionManagementElement.cs
- PassportAuthenticationEventArgs.cs
- HtmlEmptyTagControlBuilder.cs
- MouseGestureValueSerializer.cs
- NotifyIcon.cs
- PanelDesigner.cs
- IisTraceListener.cs
- ImageList.cs
- GridErrorDlg.cs
- odbcmetadatafactory.cs
- DataBinder.cs
- base64Transforms.cs
- IndicCharClassifier.cs
- RootProfilePropertySettingsCollection.cs
- SplashScreen.cs
- DataPager.cs
- CqlQuery.cs
- Logging.cs
- GetRecipientListRequest.cs
- RequestNavigateEventArgs.cs
- Item.cs
- FixedNode.cs
- XPathEmptyIterator.cs
- RC2.cs
- SchemaCollectionPreprocessor.cs
- FtpWebResponse.cs
- CodeDomDecompiler.cs
- Stack.cs
- DESCryptoServiceProvider.cs
- DtdParser.cs
- Base64Decoder.cs
- DataMisalignedException.cs
- RequestCachePolicy.cs
- SqlCacheDependencyDatabaseCollection.cs
- DataServiceCollectionOfT.cs
- RijndaelCryptoServiceProvider.cs
- ToolStripManager.cs
- InputBindingCollection.cs
- RelationalExpressions.cs
- DataFormat.cs
- ExtenderProvidedPropertyAttribute.cs
- XmlAttributeProperties.cs
- Size3D.cs
- BStrWrapper.cs