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,54 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Web
{
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
[AttributeUsage(AttributeTargets.Method)]
public sealed class AspNetCacheProfileAttribute : Attribute, IOperationBehavior
{
string cacheProfileName;
public AspNetCacheProfileAttribute(string cacheProfileName)
{
this.cacheProfileName = cacheProfileName;
}
public string CacheProfileName
{
get { return this.cacheProfileName; }
}
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
} // do nothing
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
} // do nothing
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
if (!AspNetEnvironment.Current.AspNetCompatibilityEnabled)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR2.CacheProfileOnlySupportedInAspNetCompatibilityMode));
}
if (operationDescription.Behaviors.Find<WebGetAttribute>() == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.CacheProfileAttributeOnlyWithGet));
}
dispatchOperation.ParameterInspectors.Add(new CachingParameterInspector(this.cacheProfileName));
}
public void Validate(OperationDescription operationDescription)
{
// validation happens in ApplyDispatchBehavior because it is dispatcher specific
}
}
}

View File

@ -0,0 +1,130 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.ServiceModel.Web
{
using System;
using System.Collections.Generic;
using System.Net;
using System.Runtime;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
internal abstract class AutomaticEndpointGenerator
{
private IDictionary<string, ContractDescription> implementedContracts;
private string multipleContractsErrorMessage;
private string noContractErrorMessage;
private string standardEndpointKind;
private Type singleImplementedContract;
protected AutomaticEndpointGenerator(IDictionary<string, ContractDescription> implementedContracts, string multipleContractsErrorMessage, string noContractErrorMessage, string standardEndpointKind)
{
Fx.Assert(implementedContracts != null, "The 'implementedContracts' parameter should not be null.");
Fx.Assert(multipleContractsErrorMessage != null, "The 'multipleContractsErrorMessage' parameter should not be null.");
Fx.Assert(noContractErrorMessage != null, "The 'noContractErrorMessage' parameter should not be null.");
Fx.Assert(standardEndpointKind != null, "The 'standardEndpointKind' parameter should not be null.");
this.implementedContracts = implementedContracts;
this.multipleContractsErrorMessage = multipleContractsErrorMessage;
this.noContractErrorMessage = noContractErrorMessage;
this.standardEndpointKind = standardEndpointKind;
}
protected abstract string BindingCollectionElementName { get; }
public ServiceEndpoint GenerateServiceEndpoint(ServiceHostBase serviceHost, Uri baseAddress)
{
Fx.Assert(serviceHost != null, "The 'serviceHost' parameter should not be null.");
Fx.Assert(baseAddress != null, "The 'baseAddress' parameter should not be null.");
AuthenticationSchemes supportedSchemes = GetAuthenticationSchemes(baseAddress);
Type contractType = this.GetSingleImplementedContract();
ConfigLoader configLoader = new ConfigLoader(serviceHost.GetContractResolver(this.implementedContracts));
ServiceEndpointElement serviceEndpointElement = new ServiceEndpointElement();
serviceEndpointElement.Contract = contractType.FullName;
this.SetBindingConfiguration(baseAddress.Scheme, serviceEndpointElement);
serviceEndpointElement.Kind = this.standardEndpointKind;
ServiceEndpoint serviceEndpoint = configLoader.LookupEndpoint(serviceEndpointElement, null, serviceHost, serviceHost.Description, true);
this.ConfigureBinding(serviceEndpoint.Binding, baseAddress.Scheme, supportedSchemes, AspNetEnvironment.Enabled);
// Setting the Endpoint address and listenUri now that we've set the binding security
ConfigLoader.ConfigureEndpointAddress(serviceEndpointElement, serviceHost, serviceEndpoint);
ConfigLoader.ConfigureEndpointListenUri(serviceEndpointElement, serviceHost, serviceEndpoint);
return serviceEndpoint;
}
protected abstract void ConfigureBinding(Binding binding, string uriScheme, AuthenticationSchemes supportedAuthenticationSchemes, bool hostedEnvironment);
private static AuthenticationSchemes GetAuthenticationSchemes(Uri baseAddress)
{
AuthenticationSchemes supportedSchemes = AspNetEnvironment.Current.GetAuthenticationSchemes(baseAddress);
if (AspNetEnvironment.Current.IsSimpleApplicationHost)
{
// Cassini always reports the auth scheme as anonymous or Ntlm. Map this to Ntlm, except when forms auth
// is requested
if (supportedSchemes == (AuthenticationSchemes.Anonymous | AuthenticationSchemes.Ntlm))
{
if (AspNetEnvironment.Current.IsWindowsAuthenticationConfigured())
{
supportedSchemes = AuthenticationSchemes.Ntlm;
}
else
{
supportedSchemes = AuthenticationSchemes.Anonymous;
}
}
}
return supportedSchemes;
}
private Type GetSingleImplementedContract()
{
if (this.singleImplementedContract == null)
{
Fx.Assert(this.implementedContracts != null, "The 'implementedContracts' field should not be null.");
Fx.Assert(this.multipleContractsErrorMessage != null, "The 'multipleContractsErrorMessage' field should not be null.");
Fx.Assert(this.noContractErrorMessage != null, "The 'noContractErrorMessage' field should not be null.");
if (this.implementedContracts.Count > 1)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(this.multipleContractsErrorMessage));
}
else if (this.implementedContracts.Count == 0)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(this.noContractErrorMessage));
}
foreach (ContractDescription contract in this.implementedContracts.Values)
{
this.singleImplementedContract = contract.ContractType;
break;
}
}
return this.singleImplementedContract;
}
private void SetBindingConfiguration(string uriScheme, ServiceEndpointElement serviceEndpointElement)
{
Fx.Assert(uriScheme != null, "The 'uriScheme' parameter should not be null.");
Fx.Assert(serviceEndpointElement != null, "The 'serviceEndpointElement' parameter should not be null.");
Fx.Assert(this.BindingCollectionElementName != null, "The 'this.BindingCollectionElementName' property should not be null.");
ProtocolMappingItem protocolMappingItem = ConfigLoader.LookupProtocolMapping(uriScheme);
if (protocolMappingItem != null &&
string.Equals(protocolMappingItem.Binding, this.BindingCollectionElementName, StringComparison.Ordinal))
{
serviceEndpointElement.BindingConfiguration = protocolMappingItem.BindingConfiguration;
}
}
}
}

View File

@ -0,0 +1,366 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime;
using System.Runtime.Serialization;
using System.Security;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Diagnostics;
using System.ServiceModel.Dispatcher;
using System.Web;
using System.Web.Caching;
using System.Web.Configuration;
using System.Web.UI;
using System.ServiceModel.Activation;
namespace System.ServiceModel.Web
{
class CachingParameterInspector : IParameterInspector
{
const char seperatorChar = ';';
const char escapeChar = '\\';
const char tableDbSeperatorChar = ':';
const string invalidSqlDependencyString = "Invalid Sql dependency string.";
[Fx.Tag.SecurityNote(Critical = "A config object, which should not be leaked.")]
[SecurityCritical]
OutputCacheProfile cacheProfile;
SqlDependencyInfo[] cacheDependencyInfoArray;
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "The config object never leaves the CachingParameterInspector.")]
[SecuritySafeCritical]
public CachingParameterInspector(string cacheProfileName)
{
if (string.IsNullOrEmpty(cacheProfileName))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.CacheProfileNameNullOrEmpty));
}
OutputCacheSettingsSection cacheSettings = AspNetEnvironment.Current.UnsafeGetConfigurationSection("system.web/caching/outputCacheSettings") as OutputCacheSettingsSection;
if (cacheSettings == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.CacheProfileNotConfigured, cacheProfileName)));
}
this.cacheProfile = cacheSettings.OutputCacheProfiles[cacheProfileName];
if (this.cacheProfile == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.CacheProfileNotConfigured, cacheProfileName)));
}
// Validate the cacheProfile
if (this.cacheProfile.Location != OutputCacheLocation.None)
{
// Duration must be set; Duration default value is -1
if (this.cacheProfile.Duration == -1)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.CacheProfileValueMissing, this.cacheProfile.Name, "Duration")));
}
if (this.cacheProfile.VaryByParam == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.CacheProfileValueMissing, this.cacheProfile.Name, "VaryByParam")));
}
}
if (string.Equals(this.cacheProfile.SqlDependency, "CommandNotification", StringComparison.OrdinalIgnoreCase))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR2.CommandNotificationSqlDependencyNotSupported));
}
if (!string.IsNullOrEmpty(this.cacheProfile.SqlDependency))
{
ParseSqlDependencyString(cacheProfile.SqlDependency);
}
}
[Fx.Tag.SecurityNote(Critical = "Handles config objects, which should not be leaked.",
Safe = "The config object never leaves the CachingParameterInspector.")]
[SecuritySafeCritical]
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
if (this.cacheProfile != null &&
this.cacheProfile.Enabled &&
OperationContext.Current.IncomingMessage.Version == MessageVersion.None)
{
if (DiagnosticUtility.ShouldTraceWarning && !IsAnonymous())
{
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.AddingAuthenticatedResponseToOutputCache, SR2.GetString(SR2.TraceCodeAddingAuthenticatedResponseToOutputCache, operationName));
}
else if (DiagnosticUtility.ShouldTraceInformation)
{
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.AddingResponseToOutputCache, SR2.GetString(SR2.TraceCodeAddingResponseToOutputCache, operationName));
}
SetCacheFromCacheProfile();
}
}
public object BeforeCall(string operationName, object[] inputs)
{
return null;
}
bool IsAnonymous()
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
return false;
}
else
{
if (OperationContext.Current.ServiceSecurityContext == null)
{
return true;
}
else
{
return OperationContext.Current.ServiceSecurityContext.IsAnonymous;
}
}
}
static SqlDependencyInfo[] ParseSqlDependencyString(string sqlDependencyString)
{
// The code for this method was taken from private code in
// System.Web.SqlCacheDependency.ParseSql7OutputCacheDependency.
// Alter if only absolutely necessary since we want to reproduce the same ASP.NET caching behavior.
List<SqlDependencyInfo> dependencyList = new List<SqlDependencyInfo>();
bool escapeSequenceFlag = false;
int startIndexForDatabaseName = 0;
int startIndexForTableName = -1;
string databaseName = null;
try
{
for (int currentIndex = 0; currentIndex < (sqlDependencyString.Length + 1); currentIndex++)
{
if (escapeSequenceFlag)
{
escapeSequenceFlag = false;
}
else if ((currentIndex != sqlDependencyString.Length) &&
(sqlDependencyString[currentIndex] == escapeChar))
{
escapeSequenceFlag = true;
}
else
{
int subStringLength;
if ((currentIndex == sqlDependencyString.Length) ||
(sqlDependencyString[currentIndex] == seperatorChar))
{
if (databaseName == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(invalidSqlDependencyString);
}
subStringLength = currentIndex - startIndexForTableName;
if (subStringLength == 0)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(invalidSqlDependencyString);
}
string tableName = sqlDependencyString.Substring(startIndexForTableName, subStringLength);
SqlDependencyInfo info = new SqlDependencyInfo();
info.Database = VerifyAndRemoveEscapeCharacters(databaseName);
info.Table = VerifyAndRemoveEscapeCharacters(tableName);
dependencyList.Add(info);
startIndexForDatabaseName = currentIndex + 1;
databaseName = null;
}
if (currentIndex == sqlDependencyString.Length)
{
break;
}
if (sqlDependencyString[currentIndex] == tableDbSeperatorChar)
{
if (databaseName != null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(invalidSqlDependencyString);
}
subStringLength = currentIndex - startIndexForDatabaseName;
if (subStringLength == 0)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(invalidSqlDependencyString);
}
databaseName = sqlDependencyString.Substring(startIndexForDatabaseName, subStringLength);
startIndexForTableName = currentIndex + 1;
}
}
}
}
catch (ArgumentException)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.CacheProfileSqlDependencyIsInvalid, sqlDependencyString)));
}
if (dependencyList.Count == 0)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString(SR2.CacheProfileSqlDependencyIsInvalid, sqlDependencyString)));
}
return dependencyList.ToArray();
}
static string VerifyAndRemoveEscapeCharacters(string str)
{
// The code for this method was taken from private code in
// System.Web.SqlCacheDependency.VerifyAndRemoveEscapeCharacters.
// Alter if only absolutely necessary since we want to reproduce the same ASP.NET caching behavior.
bool escapeSequenceFlag = false;
for (int currentIndex = 0; currentIndex < str.Length; currentIndex++)
{
if (escapeSequenceFlag)
{
if (((str[currentIndex] != escapeChar) &&
(str[currentIndex] != tableDbSeperatorChar)) &&
(str[currentIndex] != seperatorChar))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(str);
}
escapeSequenceFlag = false;
}
else if (str[currentIndex] == escapeChar)
{
if ((currentIndex + 1) == str.Length)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(str);
}
escapeSequenceFlag = true;
str = str.Remove(currentIndex, 1);
currentIndex--;
}
}
return str;
}
CacheDependency CreateSingleCacheDependency(string sqlDependency)
{
if (this.cacheDependencyInfoArray == null)
{
this.cacheDependencyInfoArray = CachingParameterInspector.ParseSqlDependencyString(sqlDependency);
}
// cacheDependencyInfoArray will never have length = 0
if (this.cacheDependencyInfoArray.Length == 1)
{
return new SqlCacheDependency(this.cacheDependencyInfoArray[0].Database, this.cacheDependencyInfoArray[0].Table);
}
AggregateCacheDependency cacheDependency = new AggregateCacheDependency();
foreach (SqlDependencyInfo dependencyInfo in this.cacheDependencyInfoArray)
{
cacheDependency.Add(new CacheDependency[] { new SqlCacheDependency(dependencyInfo.Database, dependencyInfo.Table) });
}
return cacheDependency;
}
[Fx.Tag.SecurityNote(Critical = "Uses config object to set properties of the HttpCachePolicy.",
Safe = "The config object itself doesn't leak.")]
[SecuritySafeCritical]
void SetCacheFromCacheProfile()
{
HttpCachePolicy cache = HttpContext.Current.Response.Cache;
if (this.cacheProfile.NoStore)
{
cache.SetNoStore();
}
// Location is not required to be set in the config. The default is Any,
// but if it is not set in the config the value will be -1. So must correct for this.
if ((int)(this.cacheProfile.Location) == -1)
{
cache.SetCacheability(HttpCacheability.Public);
}
else
{
switch (this.cacheProfile.Location)
{
case OutputCacheLocation.Any:
cache.SetCacheability(HttpCacheability.Public);
break;
case OutputCacheLocation.Client:
cache.SetCacheability(HttpCacheability.Private);
break;
case OutputCacheLocation.Downstream:
cache.SetCacheability(HttpCacheability.Public);
cache.SetNoServerCaching();
break;
case OutputCacheLocation.None:
cache.SetCacheability(HttpCacheability.NoCache);
break;
case OutputCacheLocation.Server:
cache.SetCacheability(HttpCacheability.ServerAndNoCache);
break;
case OutputCacheLocation.ServerAndClient:
cache.SetCacheability(HttpCacheability.ServerAndPrivate);
break;
default:
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR2.GetString(SR2.CacheProfileLocationNotSupported, this.cacheProfile.Location)));
}
}
if (this.cacheProfile.Location != OutputCacheLocation.None)
{
cache.SetExpires(HttpContext.Current.Timestamp.AddSeconds((double)this.cacheProfile.Duration));
cache.SetMaxAge(new TimeSpan(0, 0, this.cacheProfile.Duration));
cache.SetValidUntilExpires(true);
cache.SetLastModified(HttpContext.Current.Timestamp);
if (this.cacheProfile.Location != OutputCacheLocation.Client)
{
if (!string.IsNullOrEmpty(this.cacheProfile.VaryByContentEncoding))
{
foreach (string contentEncoding in this.cacheProfile.VaryByContentEncoding.Split(seperatorChar))
{
cache.VaryByContentEncodings[contentEncoding.Trim()] = true;
}
}
if (!string.IsNullOrEmpty(this.cacheProfile.VaryByHeader))
{
foreach (string header in this.cacheProfile.VaryByHeader.Split(seperatorChar))
{
cache.VaryByHeaders[header.Trim()] = true;
}
}
if (this.cacheProfile.Location != OutputCacheLocation.Downstream)
{
if (!string.IsNullOrEmpty(this.cacheProfile.VaryByCustom))
{
cache.SetVaryByCustom(this.cacheProfile.VaryByCustom);
}
if (!string.IsNullOrEmpty(this.cacheProfile.VaryByParam))
{
foreach (string parameter in cacheProfile.VaryByParam.Split(seperatorChar))
{
cache.VaryByParams[parameter.Trim()] = true;
}
}
if (!string.IsNullOrEmpty(this.cacheProfile.SqlDependency))
{
CacheDependency cacheDependency = this.CreateSingleCacheDependency(cacheProfile.SqlDependency);
HttpContext.Current.Response.AddCacheDependency(new CacheDependency[] { cacheDependency });
}
}
}
}
}
private struct SqlDependencyInfo
{
public string Database;
public string Table;
}
}
}

View File

@ -0,0 +1,472 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Web
{
using System;
using System.Globalization;
// DO NOT EDIT THIS CODE.
//
// All of the code from this class was taken from build 20717.00
// of System.Net.HttpDateParse. If there is a bug with this code
// it should be fixed in the original System.Net.HttpDateParse
// and then ported here. [[....]]
internal static class HttpDateParse
{
private const int BASE_DEC = 10; // base 10
//
// Date indicies used to figure out what each entry is.
//
private const int DATE_INDEX_DAY_OF_WEEK = 0;
private const int DATE_1123_INDEX_DAY = 1;
private const int DATE_1123_INDEX_MONTH = 2;
private const int DATE_1123_INDEX_YEAR = 3;
private const int DATE_1123_INDEX_HRS = 4;
private const int DATE_1123_INDEX_MINS = 5;
private const int DATE_1123_INDEX_SECS = 6;
private const int DATE_ANSI_INDEX_MONTH = 1;
private const int DATE_ANSI_INDEX_DAY = 2;
private const int DATE_ANSI_INDEX_HRS = 3;
private const int DATE_ANSI_INDEX_MINS = 4;
private const int DATE_ANSI_INDEX_SECS = 5;
private const int DATE_ANSI_INDEX_YEAR = 6;
private const int DATE_INDEX_TZ = 7;
private const int DATE_INDEX_LAST = DATE_INDEX_TZ;
private const int MAX_FIELD_DATE_ENTRIES = (DATE_INDEX_LAST + 1);
//
// DATE_TOKEN's DWORD values used to determine what day/month we're on
//
private const int DATE_TOKEN_JANUARY = 1;
private const int DATE_TOKEN_FEBRUARY = 2;
private const int DATE_TOKEN_MARCH = 3;
private const int DATE_TOKEN_APRIL = 4;
private const int DATE_TOKEN_MAY = 5;
private const int DATE_TOKEN_JUNE = 6;
private const int DATE_TOKEN_JULY = 7;
private const int DATE_TOKEN_AUGUST = 8;
private const int DATE_TOKEN_SEPTEMBER = 9;
private const int DATE_TOKEN_OCTOBER = 10;
private const int DATE_TOKEN_NOVEMBER = 11;
private const int DATE_TOKEN_DECEMBER = 12;
private const int DATE_TOKEN_LAST_MONTH = (DATE_TOKEN_DECEMBER + 1);
private const int DATE_TOKEN_SUNDAY = 0;
private const int DATE_TOKEN_MONDAY = 1;
private const int DATE_TOKEN_TUESDAY = 2;
private const int DATE_TOKEN_WEDNESDAY = 3;
private const int DATE_TOKEN_THURSDAY = 4;
private const int DATE_TOKEN_FRIDAY = 5;
private const int DATE_TOKEN_SATURDAY = 6;
private const int DATE_TOKEN_LAST_DAY = (DATE_TOKEN_SATURDAY + 1);
private const int DATE_TOKEN_GMT = -1000;
private const int DATE_TOKEN_LAST = DATE_TOKEN_GMT;
private const int DATE_TOKEN_ERROR = (DATE_TOKEN_LAST + 1);
//
// MakeUpper - takes an assumed lower character and bit manipulates into a upper.
// (make sure the character is Lower case alpha char to begin,
// otherwise it corrupts)
//
static char MakeUpper(char c)
{
return (Char.ToUpper(c, CultureInfo.InvariantCulture));
}
// Routine Description:
//
// Looks at the first three bytes of string to determine if we're looking
// at a Day of the Week, or Month, or "GMT" string. Is inlined so that
// the compiler can optimize this code into the caller FInternalParseHttpDate.
//
// Arguments:
//
// lpszDay - a string ptr to the first byte of the string in question.
//
// Return Value:
//
// DWORD
// Success - The Correct date token, 0-6 for day of the week, 1-14 for month, etc
//
// Failure - DATE_TOKEN_ERROR
static int MapDayMonthToDword(char[] lpszDay, int index)
{
switch (MakeUpper(lpszDay[index]))
{ // make uppercase
case 'A':
switch (MakeUpper(lpszDay[index + 1]))
{
case 'P':
return DATE_TOKEN_APRIL;
case 'U':
return DATE_TOKEN_AUGUST;
}
return DATE_TOKEN_ERROR;
case 'D':
return DATE_TOKEN_DECEMBER;
case 'F':
switch (MakeUpper(lpszDay[index + 1]))
{
case 'R':
return DATE_TOKEN_FRIDAY;
case 'E':
return DATE_TOKEN_FEBRUARY;
}
return DATE_TOKEN_ERROR;
case 'G':
return DATE_TOKEN_GMT;
case 'M':
switch (MakeUpper(lpszDay[index + 1]))
{
case 'O':
return DATE_TOKEN_MONDAY;
case 'A':
switch (MakeUpper(lpszDay[index + 2]))
{
case 'R':
return DATE_TOKEN_MARCH;
case 'Y':
return DATE_TOKEN_MAY;
}
// fall through to error
break;
}
return DATE_TOKEN_ERROR;
case 'N':
return DATE_TOKEN_NOVEMBER;
case 'J':
switch (MakeUpper(lpszDay[index + 1]))
{
case 'A':
return DATE_TOKEN_JANUARY;
case 'U':
switch (MakeUpper(lpszDay[index + 2]))
{
case 'N':
return DATE_TOKEN_JUNE;
case 'L':
return DATE_TOKEN_JULY;
}
// fall through to error
break;
}
return DATE_TOKEN_ERROR;
case 'O':
return DATE_TOKEN_OCTOBER;
case 'S':
switch (MakeUpper(lpszDay[index + 1]))
{
case 'A':
return DATE_TOKEN_SATURDAY;
case 'U':
return DATE_TOKEN_SUNDAY;
case 'E':
return DATE_TOKEN_SEPTEMBER;
}
return DATE_TOKEN_ERROR;
case 'T':
switch (MakeUpper(lpszDay[index + 1]))
{
case 'U':
return DATE_TOKEN_TUESDAY;
case 'H':
return DATE_TOKEN_THURSDAY;
}
return DATE_TOKEN_ERROR;
case 'U':
return DATE_TOKEN_GMT;
case 'W':
return DATE_TOKEN_WEDNESDAY;
}
return DATE_TOKEN_ERROR;
}
// Routine Description:
//
// Parses through a ANSI, RFC850, or RFC1123 date format and covents it into
// a FILETIME/SYSTEMTIME time format.
//
// Important this a time-critical function and should only be changed
// with the intention of optimizing or a critical need work item.
//
// Arguments:
//
// lpft - Ptr to FILETIME structure. Used to store converted result.
// Must be NULL if not intended to be used !!!
//
// lpSysTime - Ptr to SYSTEMTIME struture. Used to return Systime if needed.
//
// lpcszDateStr - Const Date string to parse.
//
// Return Value:
//
// BOOL
// Success - TRUE
// Failure - FALSE
internal static bool ParseHttpDate(String DateString, out DateTime dtOut)
{
int index = 0;
int i = 0, iLastLettered = -1;
bool fIsANSIDateFormat = false;
int[] rgdwDateParseResults = new int[MAX_FIELD_DATE_ENTRIES];
bool fRet = true;
char[] lpInputBuffer = DateString.ToCharArray();
dtOut = new DateTime();
//
// Date Parsing v2 (1 more to go), and here is how it works...
// We take a date string and churn through it once, converting
// integers to integers, Month,Day, and GMT strings into integers,
// and all is then placed IN order in a temp array.
//
// At the completetion of the parse stage, we simple look at
// the data, and then map the results into the correct
// places in the SYSTIME structure. Simple, No allocations, and
// No dirting the data.
//
// The end of the function does something munging and pretting
// up of the results to handle the year 2000, and TZ offsets
// Note: do we need to fully handle TZs anymore?
//
while (index < DateString.Length && i < MAX_FIELD_DATE_ENTRIES)
{
if (lpInputBuffer[index] >= '0' && lpInputBuffer[index] <= '9')
{
//
// we have a numerical entry, scan through it and convent to DWORD
//
rgdwDateParseResults[i] = 0;
do
{
rgdwDateParseResults[i] *= BASE_DEC;
rgdwDateParseResults[i] += (lpInputBuffer[index] - '0');
index++;
} while (index < DateString.Length &&
lpInputBuffer[index] >= '0' &&
lpInputBuffer[index] <= '9');
i++; // next token
}
else if ((lpInputBuffer[index] >= 'A' && lpInputBuffer[index] <= 'Z') ||
(lpInputBuffer[index] >= 'a' && lpInputBuffer[index] <= 'z'))
{
//
// we have a string, should be a day, month, or GMT
// lets skim to the end of the string
//
rgdwDateParseResults[i] =
MapDayMonthToDword(lpInputBuffer, index);
iLastLettered = i;
// We want to ignore the possibility of a time zone such as PST or EST in a non-standard
// date format such as "Thu Dec 17 16:01:28 PST 1998" (Notice that the year is _after_ the time zone
if ((rgdwDateParseResults[i] == DATE_TOKEN_ERROR)
&&
!(fIsANSIDateFormat && (i == DATE_ANSI_INDEX_YEAR)))
{
fRet = false;
goto quit;
}
//
// At this point if we have a vaild string
// at this index, we know for sure that we're
// looking at a ANSI type DATE format.
//
if (i == DATE_ANSI_INDEX_MONTH)
{
fIsANSIDateFormat = true;
}
//
// Read past the end of the current set of alpha characters,
// as MapDayMonthToDword only peeks at a few characters
//
do
{
index++;
} while (index < DateString.Length &&
((lpInputBuffer[index] >= 'A' && lpInputBuffer[index] <= 'Z') ||
(lpInputBuffer[index] >= 'a' && lpInputBuffer[index] <= 'z')));
i++; // next token
}
else
{
//
// For the generic case its either a space, comma, semi-colon, etc.
// the point is we really don't care, nor do we need to waste time
// worring about it (the orginal code did). The point is we
// care about the actual date information, So we just advance to the
// next lexume.
//
index++;
}
}
//
// We're finished parsing the string, now take the parsed tokens
// and turn them to the actual structured information we care about.
// So we build lpSysTime from the Array, using a local if none is passed in.
//
int year;
int month;
int day;
int hour;
int minute;
int second;
int millisecond;
millisecond = 0;
if (fIsANSIDateFormat)
{
day = rgdwDateParseResults[DATE_ANSI_INDEX_DAY];
month = rgdwDateParseResults[DATE_ANSI_INDEX_MONTH];
hour = rgdwDateParseResults[DATE_ANSI_INDEX_HRS];
minute = rgdwDateParseResults[DATE_ANSI_INDEX_MINS];
second = rgdwDateParseResults[DATE_ANSI_INDEX_SECS];
if (iLastLettered != DATE_ANSI_INDEX_YEAR)
{
year = rgdwDateParseResults[DATE_ANSI_INDEX_YEAR];
}
else
{
// This is a fix to get around toString/toGMTstring (where the timezone is
// appended at the end. (See above)
year = rgdwDateParseResults[DATE_INDEX_TZ];
}
}
else
{
day = rgdwDateParseResults[DATE_1123_INDEX_DAY];
month = rgdwDateParseResults[DATE_1123_INDEX_MONTH];
year = rgdwDateParseResults[DATE_1123_INDEX_YEAR];
hour = rgdwDateParseResults[DATE_1123_INDEX_HRS];
minute = rgdwDateParseResults[DATE_1123_INDEX_MINS];
second = rgdwDateParseResults[DATE_1123_INDEX_SECS];
}
//
// Normalize the year, 90 == 1990, handle the year 2000, 02 == 2002
// This is Year 2000 handling folks!!! We get this wrong and
// we all look bad.
//
if (year < 100)
{
year += ((year < 80) ? 2000 : 1900);
}
//
// if we got misformed time, then plug in the current time
// !lpszHrs || !lpszMins || !lpszSec
//
if ((i < 4)
|| (day > 31)
|| (hour > 23)
|| (minute > 59)
|| (second > 59))
{
fRet = false;
goto quit;
}
//
// Now do the DateTime conversion
//
dtOut = new DateTime(year, month, day, hour, minute, second, millisecond);
//
// we want the system time to be accurate. This is _suhlow_
// The time passed in is in the local time zone; we have to convert this into GMT.
//
if (iLastLettered == DATE_ANSI_INDEX_YEAR)
{
// this should be an unusual case.
dtOut = dtOut.ToUniversalTime();
}
//
// If we have an Offset to another Time Zone
// then convert to appropriate GMT time
//
if ((i > DATE_INDEX_TZ &&
rgdwDateParseResults[DATE_INDEX_TZ] != DATE_TOKEN_GMT))
{
//
// if we received +/-nnnn as offset (hhmm), modify the output FILETIME
//
double offset;
offset = (double)rgdwDateParseResults[DATE_INDEX_TZ];
dtOut.AddHours(offset);
}
// In the end, we leave it all in LocalTime
dtOut = dtOut.ToLocalTime();
quit:
return fRet;
}
}
}

View File

@ -0,0 +1,16 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Web
{
using System;
using System.Net;
interface IWebFaultException
{
HttpStatusCode StatusCode { get; }
Type DetailType { get; }
object DetailObject { get; }
Type[] KnownTypes { get; }
}
}

View File

@ -0,0 +1,456 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634, 1691
namespace System.ServiceModel.Web
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Net;
using System.Net.Mime;
using System.Runtime;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
public class IncomingWebRequestContext
{
static readonly string HttpGetMethod = "GET";
static readonly string HttpHeadMethod = "HEAD";
static readonly string HttpPutMethod = "PUT";
static readonly string HttpPostMethod = "POST";
static readonly string HttpDeleteMethod = "DELETE";
Collection<ContentType> cachedAcceptHeaderElements;
string acceptHeaderWhenHeaderElementsCached;
internal const string UriTemplateMatchResultsPropertyName = "UriTemplateMatchResults";
OperationContext operationContext;
internal IncomingWebRequestContext(OperationContext operationContext)
{
Fx.Assert(operationContext != null, "operationContext is null");
this.operationContext = operationContext;
}
public string Accept
{
get { return EnsureMessageProperty().Headers[HttpRequestHeader.Accept]; }
}
public long ContentLength
{
get { return long.Parse(this.EnsureMessageProperty().Headers[HttpRequestHeader.ContentLength], CultureInfo.InvariantCulture); }
}
public string ContentType
{
get { return this.EnsureMessageProperty().Headers[HttpRequestHeader.ContentType]; }
}
public IEnumerable<string> IfMatch
{
get
{
string ifMatchHeader = MessageProperty.Headers[HttpRequestHeader.IfMatch];
return (string.IsNullOrEmpty(ifMatchHeader)) ? null : Utility.QuoteAwareStringSplit(ifMatchHeader);
}
}
public IEnumerable<string> IfNoneMatch
{
get
{
string ifNoneMatchHeader = MessageProperty.Headers[HttpRequestHeader.IfNoneMatch];
return (string.IsNullOrEmpty(ifNoneMatchHeader)) ? null : Utility.QuoteAwareStringSplit(ifNoneMatchHeader);
}
}
public DateTime? IfModifiedSince
{
get
{
string dateTime = this.MessageProperty.Headers[HttpRequestHeader.IfModifiedSince];
if (!string.IsNullOrEmpty(dateTime))
{
DateTime parsedDateTime;
if (HttpDateParse.ParseHttpDate(dateTime, out parsedDateTime))
{
return parsedDateTime;
}
}
return null;
}
}
public DateTime? IfUnmodifiedSince
{
get
{
string dateTime = this.MessageProperty.Headers[HttpRequestHeader.IfUnmodifiedSince];
if (!string.IsNullOrEmpty(dateTime))
{
DateTime parsedDateTime;
if (HttpDateParse.ParseHttpDate(dateTime, out parsedDateTime))
{
return parsedDateTime;
}
}
return null;
}
}
public WebHeaderCollection Headers
{
get { return this.EnsureMessageProperty().Headers; }
}
public string Method
{
get { return this.EnsureMessageProperty().Method; }
}
public UriTemplateMatch UriTemplateMatch
{
get
{
if (this.operationContext.IncomingMessageProperties.ContainsKey(UriTemplateMatchResultsPropertyName))
{
return this.operationContext.IncomingMessageProperties[UriTemplateMatchResultsPropertyName] as UriTemplateMatch;
}
else
{
return null;
}
}
set
{
this.operationContext.IncomingMessageProperties[UriTemplateMatchResultsPropertyName] = value;
}
}
public string UserAgent
{
get { return this.EnsureMessageProperty().Headers[HttpRequestHeader.UserAgent]; }
}
HttpRequestMessageProperty MessageProperty
{
get
{
if (operationContext.IncomingMessageProperties == null)
{
return null;
}
if (!operationContext.IncomingMessageProperties.ContainsKey(HttpRequestMessageProperty.Name))
{
return null;
}
return operationContext.IncomingMessageProperties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
}
}
public void CheckConditionalRetrieve(string entityTag)
{
string validEtag = OutgoingWebResponseContext.GenerateValidEtagFromString(entityTag);
CheckConditionalRetrieveWithValidatedEtag(validEtag);
}
public void CheckConditionalRetrieve(int entityTag)
{
string validEtag = OutgoingWebResponseContext.GenerateValidEtag(entityTag);
CheckConditionalRetrieveWithValidatedEtag(validEtag);
}
public void CheckConditionalRetrieve(long entityTag)
{
string validEtag = OutgoingWebResponseContext.GenerateValidEtag(entityTag);
CheckConditionalRetrieveWithValidatedEtag(validEtag);
}
public void CheckConditionalRetrieve(Guid entityTag)
{
string validEtag = OutgoingWebResponseContext.GenerateValidEtag(entityTag);
CheckConditionalRetrieveWithValidatedEtag(validEtag);
}
public void CheckConditionalRetrieve(DateTime lastModified)
{
if (!string.Equals(this.Method, IncomingWebRequestContext.HttpGetMethod, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(this.Method, IncomingWebRequestContext.HttpHeadMethod, StringComparison.OrdinalIgnoreCase))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
SR2.GetString(SR2.ConditionalRetrieveGetAndHeadOnly, this.Method)));
}
DateTime? ifModifiedSince = this.IfModifiedSince;
if (ifModifiedSince.HasValue)
{
long ticksDifference = lastModified.ToUniversalTime().Ticks - ifModifiedSince.Value.ToUniversalTime().Ticks;
if (ticksDifference < TimeSpan.TicksPerSecond)
{
WebOperationContext.Current.OutgoingResponse.LastModified = lastModified;
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new WebFaultException(HttpStatusCode.NotModified));
}
}
}
public void CheckConditionalUpdate(string entityTag)
{
string validEtag = OutgoingWebResponseContext.GenerateValidEtagFromString(entityTag);
CheckConditionalUpdateWithValidatedEtag(validEtag);
}
public void CheckConditionalUpdate(int entityTag)
{
string validEtag = OutgoingWebResponseContext.GenerateValidEtag(entityTag);
CheckConditionalUpdateWithValidatedEtag(validEtag);
}
public void CheckConditionalUpdate(long entityTag)
{
string validEtag = OutgoingWebResponseContext.GenerateValidEtag(entityTag);
CheckConditionalUpdateWithValidatedEtag(validEtag);
}
public void CheckConditionalUpdate(Guid entityTag)
{
string validEtag = OutgoingWebResponseContext.GenerateValidEtag(entityTag);
CheckConditionalUpdateWithValidatedEtag(validEtag);
}
public Collection<ContentType> GetAcceptHeaderElements()
{
string acceptHeader = this.Accept;
if (cachedAcceptHeaderElements == null ||
(!string.Equals(acceptHeaderWhenHeaderElementsCached, acceptHeader, StringComparison.OrdinalIgnoreCase)))
{
if (string.IsNullOrEmpty(acceptHeader))
{
cachedAcceptHeaderElements = new Collection<ContentType>();
acceptHeaderWhenHeaderElementsCached = acceptHeader;
}
else
{
List<ContentType> contentTypeList = new List<ContentType>();
int offset = 0;
while (true)
{
string nextItem = Utility.QuoteAwareSubString(acceptHeader, ref offset);
if (nextItem == null)
{
break;
}
ContentType contentType = Utility.GetContentTypeOrNull(nextItem);
if (contentType != null)
{
contentTypeList.Add(contentType);
}
}
contentTypeList.Sort(new AcceptHeaderElementComparer());
cachedAcceptHeaderElements = new Collection<ContentType>(contentTypeList);
acceptHeaderWhenHeaderElementsCached = acceptHeader;
}
}
return cachedAcceptHeaderElements;
}
HttpRequestMessageProperty EnsureMessageProperty()
{
if (this.MessageProperty == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
SR2.GetString(SR2.HttpContextNoIncomingMessageProperty, typeof(HttpRequestMessageProperty).Name)));
}
return this.MessageProperty;
}
void CheckConditionalRetrieveWithValidatedEtag(string entityTag)
{
if (!string.Equals(this.Method, IncomingWebRequestContext.HttpGetMethod, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(this.Method, IncomingWebRequestContext.HttpHeadMethod, StringComparison.OrdinalIgnoreCase))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
SR2.GetString(SR2.ConditionalRetrieveGetAndHeadOnly, this.Method)));
}
if (!string.IsNullOrEmpty(entityTag))
{
string entityTagHeader = this.Headers[HttpRequestHeader.IfNoneMatch];
if (!string.IsNullOrEmpty(entityTagHeader))
{
if (IsWildCardCharacter(entityTagHeader) ||
DoesHeaderContainEtag(entityTagHeader, entityTag))
{
// set response entityTag directly because it has already been validated
WebOperationContext.Current.OutgoingResponse.ETag = entityTag;
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new WebFaultException(HttpStatusCode.NotModified));
}
}
}
}
void CheckConditionalUpdateWithValidatedEtag(string entityTag)
{
bool isPutMethod = string.Equals(this.Method, IncomingWebRequestContext.HttpPutMethod, StringComparison.OrdinalIgnoreCase);
if (!isPutMethod &&
!string.Equals(this.Method, IncomingWebRequestContext.HttpPostMethod, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(this.Method, IncomingWebRequestContext.HttpDeleteMethod, StringComparison.OrdinalIgnoreCase))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
SR2.GetString(SR2.ConditionalUpdatePutPostAndDeleteOnly, this.Method)));
}
string headerOfInterest;
// if the current entityTag is null then the resource doesn't currently exist and the
// a PUT request should only succeed if If-None-Match equals '*'.
if (isPutMethod && string.IsNullOrEmpty(entityTag))
{
headerOfInterest = this.Headers[HttpRequestHeader.IfNoneMatch];
if (string.IsNullOrEmpty(headerOfInterest) ||
!IsWildCardCharacter(headerOfInterest))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new WebFaultException(HttpStatusCode.PreconditionFailed));
}
}
else
{
// all remaining cases are with an If-Match header
headerOfInterest = this.Headers[HttpRequestHeader.IfMatch];
if (string.IsNullOrEmpty(headerOfInterest) ||
(!IsWildCardCharacter(headerOfInterest) &&
!DoesHeaderContainEtag(headerOfInterest, entityTag)))
{
// set response entityTag directly because it has already been validated
WebOperationContext.Current.OutgoingResponse.ETag = entityTag;
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new WebFaultException(HttpStatusCode.PreconditionFailed));
}
}
}
static bool DoesHeaderContainEtag(string header, string entityTag)
{
int offset = 0;
while (true)
{
string nextEntityTag = Utility.QuoteAwareSubString(header, ref offset);
if (nextEntityTag == null)
{
break;
}
if (string.Equals(nextEntityTag, entityTag, StringComparison.Ordinal))
{
return true;
}
}
return false;
}
static bool IsWildCardCharacter(string header)
{
return (header.Trim() == "*");
}
}
class AcceptHeaderElementComparer : IComparer<ContentType>
{
static NumberStyles numberStyles = NumberStyles.AllowDecimalPoint;
public int Compare(ContentType x, ContentType y)
{
string[] xTypeSubType = x.MediaType.Split('/');
string[] yTypeSubType = y.MediaType.Split('/');
Fx.Assert(xTypeSubType.Length == 2, "The creation of the ContentType would have failed if there wasn't a type and subtype.");
Fx.Assert(yTypeSubType.Length == 2, "The creation of the ContentType would have failed if there wasn't a type and subtype.");
if (string.Equals(xTypeSubType[0], yTypeSubType[0], StringComparison.OrdinalIgnoreCase))
{
if (string.Equals(xTypeSubType[1], yTypeSubType[1], StringComparison.OrdinalIgnoreCase))
{
// need to check the number of parameters to determine which is more specific
bool xHasParam = HasParameters(x);
bool yHasParam = HasParameters(y);
if (xHasParam && !yHasParam)
{
return 1;
}
else if (!xHasParam && yHasParam)
{
return -1;
}
}
else
{
if (xTypeSubType[1][0] == '*' && xTypeSubType[1].Length == 1)
{
return 1;
}
if (yTypeSubType[1][0] == '*' && yTypeSubType[1].Length == 1)
{
return -1;
}
}
}
else if (xTypeSubType[0][0] == '*' && xTypeSubType[0].Length == 1)
{
return 1;
}
else if (yTypeSubType[0][0] == '*' && yTypeSubType[0].Length == 1)
{
return -1;
}
decimal qualityDifference = GetQualityFactor(x) - GetQualityFactor(y);
if (qualityDifference < 0)
{
return 1;
}
else if (qualityDifference > 0)
{
return -1;
}
return 0;
}
decimal GetQualityFactor(ContentType contentType)
{
decimal result;
foreach (string key in contentType.Parameters.Keys)
{
if (string.Equals("q", key, StringComparison.OrdinalIgnoreCase))
{
if (decimal.TryParse(contentType.Parameters[key], numberStyles, CultureInfo.InvariantCulture, out result) &&
(result <= (decimal)1.0))
{
return result;
}
}
}
return (decimal)1.0;
}
bool HasParameters(ContentType contentType)
{
int number = 0;
foreach (string param in contentType.Parameters.Keys)
{
if (!string.Equals("q", param, StringComparison.OrdinalIgnoreCase))
{
number++;
}
}
return (number > 0);
}
}
}

View File

@ -0,0 +1,70 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634, 1691
namespace System.ServiceModel.Web
{
using System;
using System.Globalization;
using System.Net;
using System.Runtime;
using System.ServiceModel;
using System.ServiceModel.Channels;
public class IncomingWebResponseContext
{
OperationContext operationContext;
internal IncomingWebResponseContext(OperationContext operationContext)
{
Fx.Assert(operationContext != null, "operationContext is null");
this.operationContext = operationContext;
}
public long ContentLength
{ get { return long.Parse(EnsureMessageProperty().Headers[HttpResponseHeader.ContentLength], CultureInfo.InvariantCulture); } }
public string ContentType
{ get { return EnsureMessageProperty().Headers[HttpResponseHeader.ContentType]; } }
public string ETag
{ get { return EnsureMessageProperty().Headers[HttpResponseHeader.ETag]; } }
public WebHeaderCollection Headers
{ get { return EnsureMessageProperty().Headers; } }
public string Location
{ get { return EnsureMessageProperty().Headers[HttpResponseHeader.Location]; } }
public HttpStatusCode StatusCode
{ get { return this.EnsureMessageProperty().StatusCode; } }
public string StatusDescription
{ get { return this.EnsureMessageProperty().StatusDescription; } }
HttpResponseMessageProperty MessageProperty
{ get
{
if (operationContext.IncomingMessageProperties == null)
{
return null;
}
if (!operationContext.IncomingMessageProperties.ContainsKey(HttpResponseMessageProperty.Name))
{
return null;
}
return operationContext.IncomingMessageProperties[HttpResponseMessageProperty.Name] as HttpResponseMessageProperty;
}
}
HttpResponseMessageProperty EnsureMessageProperty()
{
if (this.MessageProperty == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
SR2.GetString(SR2.HttpContextNoIncomingMessageProperty, typeof(HttpResponseMessageProperty).Name)));
}
return this.MessageProperty;
}
}
}

View File

@ -0,0 +1,58 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Web
{
using System;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.ServiceModel.Administration;
using System.Collections.Generic;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class JavascriptCallbackBehaviorAttribute : Attribute, IContractBehavior
{
string urlParameterName;
public string UrlParameterName
{
get { return urlParameterName; }
set
{
if (string.IsNullOrEmpty(value))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
}
else
{
urlParameterName = value;
}
}
}
public JavascriptCallbackBehaviorAttribute()
{
}
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
{
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
}
}
}

View File

@ -0,0 +1,100 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634, 1691
namespace System.ServiceModel.Web
{
using System.Globalization;
using System.Net;
using System.Runtime;
using System.ServiceModel;
using System.ServiceModel.Channels;
public class OutgoingWebRequestContext
{
OperationContext operationContext;
internal OutgoingWebRequestContext(OperationContext operationContext)
{
Fx.Assert(operationContext != null, "operationContext is null");
this.operationContext = operationContext;
}
public string Accept
{
get { return this.MessageProperty.Headers[HttpRequestHeader.Accept]; }
set { this.MessageProperty.Headers[HttpRequestHeader.Accept] = value; }
}
public long ContentLength
{
get { return long.Parse(this.MessageProperty.Headers[HttpRequestHeader.ContentLength], CultureInfo.InvariantCulture); }
set { this.MessageProperty.Headers[HttpRequestHeader.ContentLength] = value.ToString(CultureInfo.InvariantCulture); }
}
public string ContentType
{
get { return this.MessageProperty.Headers[HttpRequestHeader.ContentType]; }
set { this.MessageProperty.Headers[HttpRequestHeader.ContentType] = value; }
}
public WebHeaderCollection Headers
{
get { return this.MessageProperty.Headers; }
}
public string IfMatch
{
get { return this.MessageProperty.Headers[HttpRequestHeader.IfMatch]; }
set { this.MessageProperty.Headers[HttpRequestHeader.IfMatch] = value; }
}
public string IfModifiedSince
{
get { return this.MessageProperty.Headers[HttpRequestHeader.IfModifiedSince]; }
set { this.MessageProperty.Headers[HttpRequestHeader.IfModifiedSince] = value; }
}
public string IfNoneMatch
{
get { return this.MessageProperty.Headers[HttpRequestHeader.IfNoneMatch]; }
set { this.MessageProperty.Headers[HttpRequestHeader.IfNoneMatch] = value; }
}
public string IfUnmodifiedSince
{
get { return this.MessageProperty.Headers[HttpRequestHeader.IfUnmodifiedSince]; }
set { this.MessageProperty.Headers[HttpRequestHeader.IfUnmodifiedSince] = value; }
}
public string Method
{
get { return this.MessageProperty.Method; }
set { this.MessageProperty.Method = value; }
}
public bool SuppressEntityBody
{
get { return this.MessageProperty.SuppressEntityBody; }
set { this.MessageProperty.SuppressEntityBody = value; }
}
public string UserAgent
{
get { return this.MessageProperty.Headers[HttpRequestHeader.UserAgent]; }
set { this.MessageProperty.Headers[HttpRequestHeader.UserAgent] = value; }
}
HttpRequestMessageProperty MessageProperty
{
get
{
if (!operationContext.OutgoingMessageProperties.ContainsKey(HttpRequestMessageProperty.Name))
{
operationContext.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, new HttpRequestMessageProperty());
}
return operationContext.OutgoingMessageProperties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
}
}
}
}

View File

@ -0,0 +1,320 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634, 1691
namespace System.ServiceModel.Web
{
using System;
using System.Globalization;
using System.Net;
using System.Runtime;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Collections.Generic;
public class OutgoingWebResponseContext
{
internal static readonly string WebResponseFormatPropertyName = "WebResponseFormatProperty";
internal static readonly string AutomatedFormatSelectionContentTypePropertyName = "AutomatedFormatSelectionContentTypePropertyName";
Encoding bindingWriteEncoding = null;
OperationContext operationContext;
internal OutgoingWebResponseContext(OperationContext operationContext)
{
Fx.Assert(operationContext != null, "operationContext is null");
this.operationContext = operationContext;
}
public long ContentLength
{
get { return long.Parse(this.MessageProperty.Headers[HttpResponseHeader.ContentLength], CultureInfo.InvariantCulture); }
set { this.MessageProperty.Headers[HttpResponseHeader.ContentLength] = value.ToString(CultureInfo.InvariantCulture); }
}
public string ContentType
{
get { return this.MessageProperty.Headers[HttpResponseHeader.ContentType]; }
set { this.MessageProperty.Headers[HttpResponseHeader.ContentType] = value; }
}
public string ETag
{
get { return this.MessageProperty.Headers[HttpResponseHeader.ETag]; }
set { this.MessageProperty.Headers[HttpResponseHeader.ETag] = value; }
}
public WebHeaderCollection Headers
{
get { return this.MessageProperty.Headers; }
}
public DateTime LastModified
{
get
{
string dateTime = this.MessageProperty.Headers[HttpRequestHeader.LastModified];
if (!string.IsNullOrEmpty(dateTime))
{
DateTime parsedDateTime;
if (DateTime.TryParse(dateTime, CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedDateTime))
{
return parsedDateTime;
}
}
return DateTime.MinValue;
}
set
{
this.MessageProperty.Headers[HttpResponseHeader.LastModified] =
(value.Kind == DateTimeKind.Utc ?
value.ToString("R", CultureInfo.InvariantCulture) :
value.ToUniversalTime().ToString("R", CultureInfo.InvariantCulture));
}
}
public string Location
{
get { return this.MessageProperty.Headers[HttpResponseHeader.Location]; }
set { this.MessageProperty.Headers[HttpResponseHeader.Location] = value; }
}
public HttpStatusCode StatusCode
{
get { return this.MessageProperty.StatusCode; }
set { this.MessageProperty.StatusCode = value; }
}
public string StatusDescription
{
get { return this.MessageProperty.StatusDescription; }
set { this.MessageProperty.StatusDescription = value; }
}
public bool SuppressEntityBody
{
get { return this.MessageProperty.SuppressEntityBody; }
set { this.MessageProperty.SuppressEntityBody = value; }
}
public WebMessageFormat? Format
{
get
{
if (!operationContext.OutgoingMessageProperties.ContainsKey(WebResponseFormatPropertyName))
{
return null;
}
return operationContext.OutgoingMessageProperties[WebResponseFormatPropertyName] as WebMessageFormat?;
}
set
{
if (value.HasValue)
{
if (!WebMessageFormatHelper.IsDefined(value.Value))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
}
else
{
operationContext.OutgoingMessageProperties[WebResponseFormatPropertyName] = value.Value;
}
}
else
{
operationContext.OutgoingMessageProperties[WebResponseFormatPropertyName] = null;
}
this.AutomatedFormatSelectionContentType = null;
}
}
// This is an internal property because we need to carry the content-type that was selected by the FormatSelectingMessageInspector
// forward so that the formatter has access to it. However, we dond't want to use the ContentType property on this, because then
// developers would have to clear the ContentType property manually when overriding the format set by the
// FormatSelectingMessageInspector
internal string AutomatedFormatSelectionContentType
{
get
{
if (!operationContext.OutgoingMessageProperties.ContainsKey(AutomatedFormatSelectionContentTypePropertyName))
{
return null;
}
return operationContext.OutgoingMessageProperties[AutomatedFormatSelectionContentTypePropertyName] as string;
}
set
{
operationContext.OutgoingMessageProperties[AutomatedFormatSelectionContentTypePropertyName] = value;
}
}
public Encoding BindingWriteEncoding
{
get
{
if (this.bindingWriteEncoding == null)
{
string endpointId = this.operationContext.EndpointDispatcher.Id;
Fx.Assert(endpointId != null, "There should always be an valid EndpointDispatcher.Id");
foreach (ServiceEndpoint endpoint in this.operationContext.Host.Description.Endpoints)
{
if (endpoint.Id == endpointId)
{
WebMessageEncodingBindingElement encodingElement = endpoint.Binding.CreateBindingElements().Find<WebMessageEncodingBindingElement>() as WebMessageEncodingBindingElement;
if (encodingElement != null)
{
this.bindingWriteEncoding = encodingElement.WriteEncoding;
}
}
}
}
return this.bindingWriteEncoding;
}
}
internal HttpResponseMessageProperty MessageProperty
{
get
{
if (!operationContext.OutgoingMessageProperties.ContainsKey(HttpResponseMessageProperty.Name))
{
operationContext.OutgoingMessageProperties.Add(HttpResponseMessageProperty.Name, new HttpResponseMessageProperty());
}
return operationContext.OutgoingMessageProperties[HttpResponseMessageProperty.Name] as HttpResponseMessageProperty;
}
}
public void SetETag(string entityTag)
{
this.ETag = GenerateValidEtagFromString(entityTag);
}
public void SetETag(int entityTag)
{
this.ETag = GenerateValidEtag(entityTag);
}
public void SetETag(long entityTag)
{
this.ETag = GenerateValidEtag(entityTag);
}
public void SetETag(Guid entityTag)
{
this.ETag = GenerateValidEtag(entityTag);
}
public void SetStatusAsCreated(Uri locationUri)
{
if (locationUri == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("locationUri");
}
this.StatusCode = HttpStatusCode.Created;
this.Location = locationUri.ToString();
}
public void SetStatusAsNotFound()
{
this.StatusCode = HttpStatusCode.NotFound;
}
public void SetStatusAsNotFound(string description)
{
this.StatusCode = HttpStatusCode.NotFound;
this.StatusDescription = description;
}
internal static string GenerateValidEtagFromString(string entityTag)
{
// This method will generate a valid entityTag from a string by doing the following:
// 1) Adding surrounding double quotes if the string doesn't already start and end with them
// 2) Escaping any internal double quotes that aren't already escaped (preceded with a backslash)
// 3) If a string starts with a double quote but doesn't end with one, or vice-versa, then the
// double quote is considered internal and is escaped.
if (string.IsNullOrEmpty(entityTag))
{
return null;
}
if (entityTag.StartsWith("W/\"", StringComparison.OrdinalIgnoreCase) &&
entityTag.EndsWith("\"", StringComparison.OrdinalIgnoreCase))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
SR2.GetString(SR2.WeakEntityTagsNotSupported, entityTag)));
}
List<int> escapeCharacterInsertIndices = null;
int lastEtagIndex = entityTag.Length - 1;
bool startsWithQuote = entityTag[0] == '\"';
bool endsWithQuote = entityTag[lastEtagIndex] == '\"';
// special case where the entityTag is a single character, a double quote, '"'
if (lastEtagIndex == 0 && startsWithQuote)
{
endsWithQuote = false;
}
bool needsSurroundingQuotes = !startsWithQuote || !endsWithQuote;
if (startsWithQuote && !endsWithQuote)
{
if (escapeCharacterInsertIndices == null)
{
escapeCharacterInsertIndices = new List<int>();
}
escapeCharacterInsertIndices.Add(0);
}
for (int x = 1; x < lastEtagIndex; x++)
{
if (entityTag[x] == '\"' && entityTag[x - 1] != '\\')
{
if (escapeCharacterInsertIndices == null)
{
escapeCharacterInsertIndices = new List<int>();
}
escapeCharacterInsertIndices.Add(x + escapeCharacterInsertIndices.Count);
}
}
// Possible that the ending internal quote is already escaped so must check the character before it
if (!startsWithQuote && endsWithQuote && entityTag[lastEtagIndex - 1] != '\\')
{
if (escapeCharacterInsertIndices == null)
{
escapeCharacterInsertIndices = new List<int>();
}
escapeCharacterInsertIndices.Add(lastEtagIndex + escapeCharacterInsertIndices.Count);
}
if (needsSurroundingQuotes || escapeCharacterInsertIndices != null)
{
int escapeCharacterInsertIndicesCount = (escapeCharacterInsertIndices == null) ? 0 : escapeCharacterInsertIndices.Count;
StringBuilder editedEtag = new StringBuilder(entityTag, entityTag.Length + escapeCharacterInsertIndicesCount + 2);
for (int x = 0; x < escapeCharacterInsertIndicesCount; x++)
{
editedEtag.Insert(escapeCharacterInsertIndices[x], '\\');
}
if (needsSurroundingQuotes)
{
editedEtag.Insert(entityTag.Length + escapeCharacterInsertIndicesCount, '\"');
editedEtag.Insert(0, '\"');
}
entityTag = editedEtag.ToString();
}
return entityTag;
}
internal static string GenerateValidEtag(object entityTag)
{
return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", entityTag.ToString());
}
}
}

View File

@ -0,0 +1,213 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Web
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Mime;
using System.Runtime;
using System.Text;
using System.Globalization;
using System.ServiceModel.Channels;
static class Utility
{
public const string applicationXml = "application/xml";
public const string textXml = "text/xml";
public const string applicationJson = "application/json";
public const string textJson = "text/json";
public const string GET = "GET";
public static bool IsXmlContent(this string contentType)
{
if (contentType == null)
{
return true;
}
string contentTypeProcessed = contentType.Trim();
return contentTypeProcessed.StartsWith(applicationXml, StringComparison.OrdinalIgnoreCase)
|| contentTypeProcessed.StartsWith(textXml, StringComparison.OrdinalIgnoreCase);
}
public static bool IsJsonContent(this string contentType)
{
if (contentType == null)
{
return true;
}
string contentTypeProcessed = contentType.Trim();
return contentTypeProcessed.StartsWith(applicationJson, StringComparison.OrdinalIgnoreCase)
|| contentTypeProcessed.StartsWith(textJson, StringComparison.OrdinalIgnoreCase);
}
public static string CombineUri(string former, string latter)
{
// Appending the latter string to the form string,
// while making sure there is a single slash char seperating the latter and the former.
// This method behaves differently than new Uri(baseUri, relativeUri)
// as CombineUri simply appends, whereas new Uri() actually replaces the last segment
// of the its base path with the relative uri.
StringBuilder builder = new StringBuilder();
if (former.Length > 0 && latter.Length > 0)
{
if (former[former.Length - 1] == '/' && latter[0] == '/')
{
builder.Append(former, 0, former.Length - 1);
builder.Append(latter);
return builder.ToString();
}
if (former[former.Length - 1] != '/' && latter[0] != '/')
{
builder.Append(former);
builder.Append('/');
builder.Append(latter);
return builder.ToString();
}
}
return former + latter;
}
public static List<string> QuoteAwareStringSplit(string str)
{
List<string> subStrings = new List<string>();
int offset = 0;
while (true)
{
string subString = QuoteAwareSubString(str, ref offset);
if (subString == null)
{
break;
}
subStrings.Add(subString);
}
return subStrings;
}
// This method extracts substrings from a string starting at the offset
// and up until the next comma in the string. The sub string extraction is
// quote aware such that commas inside quoted-strings are ignored. On return,
// offset points to the next char beyond the comma of the substring returned
// and may point beyond the length of the header.
public static string QuoteAwareSubString(string str, ref int offset)
{
// this method will filter out empty-string and white-space-only items in
// the header. For example "x,,y" and "x, ,y" would result in just "x" and "y"
// substrings being returned.
if (string.IsNullOrEmpty(str) || offset >= str.Length)
{
return null;
}
int startIndex = (offset > 0) ? offset : 0;
// trim whitespace and commas from the begining of the item
while (char.IsWhiteSpace(str[startIndex]) || str[startIndex] == ',')
{
startIndex++;
if (startIndex >= str.Length)
{
return null;
}
}
int endIndex = startIndex;
bool insideQuotes = false;
while (endIndex < str.Length)
{
if (str[endIndex] == '\"' &&
(!insideQuotes || endIndex == 0 || str[endIndex - 1] != '\\'))
{
insideQuotes = !insideQuotes;
}
else if (str[endIndex] == ',' && !insideQuotes)
{
break;
}
endIndex++;
}
offset = endIndex + 1;
// trim whitespace from the end of the item; the substring is guaranteed to
// have at least one non-whitespace character
while (char.IsWhiteSpace(str[endIndex - 1]))
{
endIndex--;
}
return str.Substring(startIndex, endIndex - startIndex);
}
public static ContentType GetContentType(string contentType)
{
string contentTypeTrimmed = contentType.Trim();
if (!string.IsNullOrEmpty(contentTypeTrimmed))
{
return GetContentTypeOrNull(contentTypeTrimmed);
}
return null;
}
public static ContentType GetContentTypeOrNull(string contentType)
{
try
{
Fx.Assert(contentType == contentType.Trim(), "The ContentType input argument should already be trimmed.");
Fx.Assert(!string.IsNullOrEmpty(contentType), "The ContentType input argument should not be null or empty.");
ContentType contentTypeToReturn = new ContentType(contentType);
// Need to check for "*/<Something-other-than-*>" because the ContentType constructor doesn't catch this
string[] typeAndSubType = contentTypeToReturn.MediaType.Split('/');
Fx.Assert(typeAndSubType.Length == 2, "The creation of the ContentType would have failed if there wasn't a type and subtype.");
if (typeAndSubType[0][0] == '*' && typeAndSubType[0].Length == 1 &&
!(typeAndSubType[1][0] == '*' && typeAndSubType[1].Length == 1))
{
//
// throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new FormatException(
// SR2.GetString(SR2.InvalidContentType, contentType)));
return null;
}
return contentTypeToReturn;
}
catch (FormatException e)
{
// Return null to indicate that the content type creation failed
System.ServiceModel.DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
}
return null;
}
public static string IEnumerableToCommaSeparatedString(IEnumerable<string> items)
{
Fx.Assert(items != null, "The 'items' argument should never be null.");
return string.Join(", ", items);
}
public static void AddRange<T>(ICollection<T> list, IEnumerable<T> itemsToAdd)
{
Fx.Assert(list != null, "The 'list' argument should never be null.");
Fx.Assert(itemsToAdd != null, "The 'itemsToAdd' argument should never be null.");
foreach (T item in itemsToAdd)
{
list.Add(item);
}
}
}
}

View File

@ -0,0 +1,102 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Web
{
using System.IO;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Diagnostics.CodeAnalysis;
using System.Configuration;
using System.Net;
using System.Globalization;
public class WebChannelFactory<TChannel> : ChannelFactory<TChannel>
where TChannel : class
{
public WebChannelFactory()
: base()
{
}
public WebChannelFactory(Binding binding)
: base(binding)
{
}
public WebChannelFactory(ServiceEndpoint endpoint) :
base(endpoint)
{
}
[SuppressMessage("Microsoft.Design", "CA1057:StringUriOverloadsCallSystemUriOverloads", Justification = "This is a configuration string and not a network location")]
public WebChannelFactory(string endpointConfigurationName)
: base(endpointConfigurationName)
{
}
public WebChannelFactory(Type channelType)
: base(channelType)
{
}
public WebChannelFactory(Uri remoteAddress)
: this(GetDefaultBinding(remoteAddress), remoteAddress)
{
}
public WebChannelFactory(Binding binding, Uri remoteAddress)
: base(binding, (remoteAddress != null) ? new EndpointAddress(remoteAddress) : null)
{
}
public WebChannelFactory(string endpointConfigurationName, Uri remoteAddress)
: base(endpointConfigurationName, (remoteAddress != null) ? new EndpointAddress(remoteAddress) : null)
{
}
protected override void OnOpening()
{
if (this.Endpoint == null)
{
return;
}
// if the binding is missing, set up a default binding
if (this.Endpoint.Binding == null && this.Endpoint.Address != null)
{
this.Endpoint.Binding = GetDefaultBinding(this.Endpoint.Address.Uri);
}
WebServiceHost.SetRawContentTypeMapperIfNecessary(this.Endpoint, false);
if (this.Endpoint.Behaviors.Find<WebHttpBehavior>() == null)
{
this.Endpoint.Behaviors.Add(new WebHttpBehavior());
}
base.OnOpening();
}
static Binding GetDefaultBinding(Uri remoteAddress)
{
if (remoteAddress == null || (remoteAddress.Scheme != Uri.UriSchemeHttp && remoteAddress.Scheme != Uri.UriSchemeHttps))
{
return null;
}
if (remoteAddress.Scheme == Uri.UriSchemeHttp)
{
return new WebHttpBinding();
}
else
{
WebHttpBinding result = new WebHttpBinding();
result.Security.Mode = WebHttpSecurityMode.Transport;
result.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
return result;
}
}
}
}

View File

@ -0,0 +1,202 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Web
{
using System;
using System.Linq;
using System.Runtime;
using System.Net;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
using System.ServiceModel;
using System.Globalization;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
[Serializable]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "REST Exceptions cannot contain InnerExceptions or messages")]
public class WebFaultException : FaultException, IWebFaultException
{
internal const string WebFaultCodeNamespace = "http://schemas.microsoft.com/2009/WebFault";
public WebFaultException(HttpStatusCode statusCode)
: base(GetDefaultReason(statusCode), GetFaultCode(statusCode))
{
this.StatusCode = statusCode;
}
protected WebFaultException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
this.StatusCode = (HttpStatusCode)info.GetValue("statusCode", typeof(HttpStatusCode));
}
public HttpStatusCode StatusCode { get; private set; }
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes",
Justification = "The interface is used merely to be able to handled both the generic and non-generic versions and doesn't need to be exposed.")]
Type IWebFaultException.DetailType
{
get { return null; }
}
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes",
Justification = "The interface is used merely to be able to handled both the generic and non-generic versions and doesn't need to be exposed.")]
object IWebFaultException.DetailObject
{
get { return null; }
}
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes",
Justification = "The interface is used merely to be able to handled both the generic and non-generic versions and doesn't need to be exposed.")]
Type[] IWebFaultException.KnownTypes
{
get { return null; }
}
[Fx.Tag.SecurityNote(Critical = "Overrides the base.GetObjectData which is critical, as well as calling this method.", Safe = "Replicates the LinkDemand.")]
[SecurityCritical]
[SecurityPermissionAttribute(SecurityAction.LinkDemand, SerializationFormatter = true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("statusCode", this.StatusCode);
}
internal static FaultCode GetFaultCode(HttpStatusCode statusCode)
{
if ((int) statusCode >= (int) HttpStatusCode.InternalServerError)
{
return FaultCode.CreateReceiverFaultCode(statusCode.ToString(), WebFaultCodeNamespace);
}
else
{
return FaultCode.CreateSenderFaultCode(statusCode.ToString(), WebFaultCodeNamespace);
}
}
// These reasons come from section 6.1.1 of http://www.ietf.org/rfc/rfc2616.txt
internal static string GetDefaultReason(HttpStatusCode statusCode)
{
switch ((int)statusCode)
{
case 100: return "Continue";
case 101: return "Switching Protocols";
case 200: return "OK";
case 201: return "Created";
case 202: return "Accepted";
case 203: return "Non-Authoritative Information";
case 204: return "No Content";
case 205: return "Reset Content";
case 206: return "Partial Content";
case 300: return "Multiple Choices";
case 301: return "Moved Permanently";
case 302: return "Found";
case 303: return "See Other";
case 304: return "Not Modified";
case 305: return "Use Proxy";
case 307: return "Temporary Redirect";
case 400: return "Bad Request";
case 401: return "Unauthorized";
case 402: return "Payment Required";
case 403: return "Forbidden";
case 404: return "Not Found";
case 405: return "Method Not Allowed";
case 406: return "Not Acceptable";
case 407: return "Proxy Authentication Required";
case 408: return "Request Time-out";
case 409: return "Conflict";
case 410: return "Gone";
case 411: return "Length Required";
case 412: return "Precondition Failed";
case 413: return "Request Entity Too Large";
case 414: return "Request-URI Too Large";
case 415: return "Unsupported Media Type";
case 416: return "Requested range not satisfiable";
case 417: return "Expectation Failed";
case 500: return "Internal Server Error";
case 501: return "Not Implemented";
case 502: return "Bad Gateway";
case 503: return "Service Unavailable";
case 504: return "Gateway Time-out";
case 505: return "HTTP Version not supported";
default:
{
int errorClass = ((int)statusCode) / 100;
switch (errorClass)
{
case 1: return "Informational";
case 2: return "Success";
case 3: return "Redirection";
case 4: return "Client Error";
case 5: return "Server Error";
default: return null;
}
}
}
}
}
[Serializable]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "REST Exceptions cannot contain InnerExceptions or messages")]
public class WebFaultException<T> : FaultException<T>, IWebFaultException
{
Type[] knownTypes;
public WebFaultException(T detail, HttpStatusCode statusCode)
: base(detail, WebFaultException.GetDefaultReason(statusCode), WebFaultException.GetFaultCode(statusCode))
{
this.StatusCode = statusCode;
}
public WebFaultException(T detail, HttpStatusCode statusCode, IEnumerable<Type> knownTypes)
: base(detail, WebFaultException.GetDefaultReason(statusCode), WebFaultException.GetFaultCode(statusCode))
{
this.StatusCode = statusCode;
this.knownTypes = (knownTypes == null) ? null : new List<Type>(knownTypes).ToArray();
}
protected WebFaultException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
this.StatusCode = (HttpStatusCode)info.GetValue("statusCode", typeof(HttpStatusCode));
this.knownTypes = (Type[])info.GetValue("knownTypes", typeof(Type[]));
}
public HttpStatusCode StatusCode { get; private set; }
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes",
Justification = "The interface is used merely to be able to handled both the generic and non-generic versions and doesn't need to be exposed.")]
Type IWebFaultException.DetailType
{
get { return typeof(T); }
}
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes",
Justification = "The interface is used merely to be able to handled both the generic and non-generic versions and doesn't need to be exposed.")]
object IWebFaultException.DetailObject
{
get { return this.Detail; }
}
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes",
Justification = "The interface is used merely to be able to handled both the generic and non-generic versions and doesn't need to be exposed.")]
Type[] IWebFaultException.KnownTypes
{
get { return this.knownTypes; }
}
[Fx.Tag.SecurityNote(Critical = "Overrides the base.GetObjectData which is critical, as well as calling this method.", Safe = "Replicates the LinkDemand.")]
[SecurityCritical]
[SecurityPermissionAttribute(SecurityAction.LinkDemand, SerializationFormatter = true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("statusCode", this.StatusCode);
info.AddValue("knownTypes", this.knownTypes);
}
}
}

View File

@ -0,0 +1,148 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Web
{
using System;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.ServiceModel.Administration;
using System.Collections.Generic;
[AttributeUsage(AttributeTargets.Method)]
public sealed class WebGetAttribute : Attribute, IOperationContractAttributeProvider, IOperationBehavior, IWmiInstanceProvider
{
WebMessageBodyStyle bodyStyle;
bool isBodyStyleDefined;
bool isRequestMessageFormatSet;
bool isResponseMessageFormatSet;
WebMessageFormat requestMessageFormat;
WebMessageFormat responseMessageFormat;
string uriTemplate; // Note: HttpTransferEndpointBehavior interprets uriTemplate as: null means 'no opinion', whereas string.Empty means relative path of ""
public WebGetAttribute()
{
}
public WebMessageBodyStyle BodyStyle
{
get { return this.bodyStyle; }
set
{
if (!WebMessageBodyStyleHelper.IsDefined(value))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
}
this.bodyStyle = value;
this.isBodyStyleDefined = true;
}
}
public bool IsBodyStyleSetExplicitly
{
get { return this.isBodyStyleDefined; }
}
public bool IsRequestFormatSetExplicitly
{
get { return this.isRequestMessageFormatSet; }
}
public bool IsResponseFormatSetExplicitly
{
get { return this.isResponseMessageFormatSet; }
}
public WebMessageFormat RequestFormat
{
get
{
return this.requestMessageFormat;
}
set
{
if (!WebMessageFormatHelper.IsDefined(value))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
}
this.requestMessageFormat = value;
this.isRequestMessageFormatSet = true;
}
}
public WebMessageFormat ResponseFormat
{
get
{
return this.responseMessageFormat;
}
set
{
if (!WebMessageFormatHelper.IsDefined(value))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
}
this.responseMessageFormat = value;
this.isResponseMessageFormatSet = true;
}
}
public string UriTemplate
{ get { return this.uriTemplate; } set { this.uriTemplate = value; } }
void IOperationBehavior.AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
} // do nothing
void IOperationBehavior.ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
} // do nothing
void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
} // do nothing
void IOperationBehavior.Validate(OperationDescription operationDescription)
{
} // do nothing
void IWmiInstanceProvider.FillInstance(IWmiInstance wmiInstance)
{
if (wmiInstance == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("wmiInstance");
}
wmiInstance.SetProperty("BodyStyle", this.BodyStyle.ToString());
wmiInstance.SetProperty("IsBodyStyleSetExplicitly", this.IsBodyStyleSetExplicitly.ToString());
wmiInstance.SetProperty("RequestFormat", this.RequestFormat.ToString());
wmiInstance.SetProperty("IsRequestFormatSetExplicitly", this.IsRequestFormatSetExplicitly.ToString());
wmiInstance.SetProperty("ResponseFormat", this.ResponseFormat.ToString());
wmiInstance.SetProperty("IsResponseFormatSetExplicitly", this.IsResponseFormatSetExplicitly.ToString());
wmiInstance.SetProperty("UriTemplate", this.UriTemplate);
}
string IWmiInstanceProvider.GetInstanceType()
{
return "WebGetAttribute";
}
internal WebMessageBodyStyle GetBodyStyleOrDefault(WebMessageBodyStyle defaultStyle)
{
if (this.IsBodyStyleSetExplicitly)
{
return this.BodyStyle;
}
else
{
return defaultStyle;
}
}
OperationContractAttribute IOperationContractAttributeProvider.GetOperationContractAttribute()
{
return new OperationContractAttribute();
}
}
}

View File

@ -0,0 +1,152 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Web
{
using System;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.ServiceModel.Administration;
[AttributeUsage(AttributeTargets.Method)]
public sealed class WebInvokeAttribute : Attribute, IOperationContractAttributeProvider, IOperationBehavior, IWmiInstanceProvider
{
WebMessageBodyStyle bodyStyle;
bool isBodyStyleDefined;
bool isRequestMessageFormatSet;
bool isResponseMessageFormatSet;
string method; // http verb
WebMessageFormat requestMessageFormat;
WebMessageFormat responseMessageFormat;
string uriTemplate; // Note: HttpTransferEndpointBehavior interprets uriTemplate as: null means 'no opinion', whereas string.Empty means relative path of ""
public WebInvokeAttribute()
{
}
public WebMessageBodyStyle BodyStyle
{
get { return this.bodyStyle; }
set
{
if (!WebMessageBodyStyleHelper.IsDefined(value))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
}
this.bodyStyle = value;
this.isBodyStyleDefined = true;
}
}
public bool IsBodyStyleSetExplicitly
{
get { return this.isBodyStyleDefined; }
}
public bool IsRequestFormatSetExplicitly
{
get { return this.isRequestMessageFormatSet; }
}
public bool IsResponseFormatSetExplicitly
{
get { return this.isResponseMessageFormatSet; }
}
public string Method
{ get { return this.method; } set { this.method = value; } }
public WebMessageFormat RequestFormat
{
get
{
return this.requestMessageFormat;
}
set
{
if (!WebMessageFormatHelper.IsDefined(value))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
}
this.requestMessageFormat = value;
this.isRequestMessageFormatSet = true;
}
}
public WebMessageFormat ResponseFormat
{
get
{
return this.responseMessageFormat;
}
set
{
if (!WebMessageFormatHelper.IsDefined(value))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
}
this.responseMessageFormat = value;
this.isResponseMessageFormatSet = true;
}
}
public string UriTemplate
{ get { return this.uriTemplate; } set { this.uriTemplate = value; } }
void IOperationBehavior.AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
} // do nothing
void IOperationBehavior.ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
} // do nothing
void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
} // do nothing
void IOperationBehavior.Validate(OperationDescription operationDescription)
{
} // do nothing
internal WebMessageBodyStyle GetBodyStyleOrDefault(WebMessageBodyStyle defaultStyle)
{
if (this.IsBodyStyleSetExplicitly)
{
return this.BodyStyle;
}
else
{
return defaultStyle;
}
}
void IWmiInstanceProvider.FillInstance(IWmiInstance wmiInstance)
{
if (wmiInstance == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("wmiInstance");
}
wmiInstance.SetProperty("BodyStyle", this.BodyStyle.ToString());
wmiInstance.SetProperty("IsBodyStyleSetExplicitly", this.IsBodyStyleSetExplicitly.ToString());
wmiInstance.SetProperty("RequestFormat", this.RequestFormat.ToString());
wmiInstance.SetProperty("IsRequestFormatSetExplicitly", this.IsRequestFormatSetExplicitly.ToString());
wmiInstance.SetProperty("ResponseFormat", this.ResponseFormat.ToString());
wmiInstance.SetProperty("IsResponseFormatSetExplicitly", this.IsResponseFormatSetExplicitly.ToString());
wmiInstance.SetProperty("UriTemplate", this.UriTemplate);
wmiInstance.SetProperty("Method", this.Method);
}
string IWmiInstanceProvider.GetInstanceType()
{
return "WebInvokeAttribute";
}
OperationContractAttribute IOperationContractAttributeProvider.GetOperationContractAttribute()
{
return new OperationContractAttribute();
}
}
}

View File

@ -0,0 +1,14 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Web
{
public enum WebMessageBodyStyle
{
Bare,
Wrapped,
WrappedRequest,
WrappedResponse
}
}

View File

@ -0,0 +1,17 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Web
{
internal static class WebMessageBodyStyleHelper
{
internal static bool IsDefined(WebMessageBodyStyle style)
{
return (style == WebMessageBodyStyle.Bare
|| style == WebMessageBodyStyle.Wrapped
|| style == WebMessageBodyStyle.WrappedRequest
|| style == WebMessageBodyStyle.WrappedResponse);
}
}
}

View File

@ -0,0 +1,12 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Web
{
public enum WebMessageFormat
{
Xml,
Json
}
}

View File

@ -0,0 +1,14 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Web
{
internal static class WebMessageFormatHelper
{
internal static bool IsDefined(WebMessageFormat format)
{
return (format == WebMessageFormat.Xml || format == WebMessageFormat.Json);
}
}
}

View File

@ -0,0 +1,393 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634, 1691
namespace System.ServiceModel.Web
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net;
using System.Runtime.Serialization.Json;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Syndication;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.ServiceModel.Dispatcher;
public class WebOperationContext : IExtension<OperationContext>
{
internal static readonly string DefaultTextMediaType = "text/plain";
internal static readonly string DefaultJsonMediaType = JsonGlobals.applicationJsonMediaType;
internal static readonly string DefaultXmlMediaType = "application/xml";
internal static readonly string DefaultAtomMediaType = "application/atom+xml";
internal static readonly string DefaultStreamMediaType = WebHttpBehavior.defaultStreamContentType;
OperationContext operationContext;
public WebOperationContext(OperationContext operationContext)
{
if (operationContext == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operationContext");
}
this.operationContext = operationContext;
#pragma warning disable 56506 // [....], operationContext.Extensions is never null
if (operationContext.Extensions.Find<WebOperationContext>() == null)
{
operationContext.Extensions.Add(this);
}
#pragma warning enable 56506
}
public static WebOperationContext Current
{
get
{
if (OperationContext.Current == null)
{
return null;
}
WebOperationContext existing = OperationContext.Current.Extensions.Find<WebOperationContext>();
if (existing != null)
{
return existing;
}
return new WebOperationContext(OperationContext.Current);
}
}
public IncomingWebRequestContext IncomingRequest
{
get { return new IncomingWebRequestContext(this.operationContext); }
}
public IncomingWebResponseContext IncomingResponse
{
get { return new IncomingWebResponseContext(this.operationContext); }
}
public OutgoingWebRequestContext OutgoingRequest
{
get { return new OutgoingWebRequestContext(this.operationContext); }
}
public OutgoingWebResponseContext OutgoingResponse
{
get { return new OutgoingWebResponseContext(this.operationContext); }
}
public void Attach(OperationContext owner)
{
}
public void Detach(OperationContext owner)
{
}
public Message CreateJsonResponse<T>(T instance)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
return CreateJsonResponse<T>(instance, serializer);
}
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "CreateJsonMessage requires the DataContractJsonSerializer. Allowing the base type XmlObjectSerializer would let deveopers supply a non-Json Serializer.")]
public Message CreateJsonResponse<T>(T instance, DataContractJsonSerializer serializer)
{
if (serializer == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer");
}
Message message = Message.CreateMessage(MessageVersion.None, (string)null, instance, serializer);
message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.JsonProperty);
AddContentType(WebOperationContext.DefaultJsonMediaType, this.OutgoingResponse.BindingWriteEncoding);
return message;
}
public Message CreateXmlResponse<T>(T instance)
{
System.Runtime.Serialization.DataContractSerializer serializer = new System.Runtime.Serialization.DataContractSerializer(typeof(T));
return CreateXmlResponse(instance, serializer);
}
public Message CreateXmlResponse<T>(T instance, System.Runtime.Serialization.XmlObjectSerializer serializer)
{
if (serializer == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer");
}
Message message = Message.CreateMessage(MessageVersion.None, (string)null, instance, serializer);
message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
AddContentType(WebOperationContext.DefaultXmlMediaType, this.OutgoingResponse.BindingWriteEncoding);
return message;
}
public Message CreateXmlResponse<T>(T instance, XmlSerializer serializer)
{
if (serializer == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer");
}
Message message = Message.CreateMessage(MessageVersion.None, (string)null, new XmlSerializerBodyWriter(instance, serializer));
message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
AddContentType(WebOperationContext.DefaultXmlMediaType, this.OutgoingResponse.BindingWriteEncoding);
return message;
}
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Other XNode derived types such as XAttribute don't make sense in this context, so we are not using the XNode base type.")]
public Message CreateXmlResponse(XDocument document)
{
if (document == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("document");
}
Message message;
if (document.FirstNode == null)
{
message = Message.CreateMessage(MessageVersion.None, (string)null);
}
else
{
message = Message.CreateMessage(MessageVersion.None, (string)null, document.CreateReader());
}
message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
AddContentType(WebOperationContext.DefaultXmlMediaType, this.OutgoingResponse.BindingWriteEncoding);
return message;
}
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Other XNode derived types such as XAttribute don't make sense in this context, so we are not using the XNode base type.")]
public Message CreateXmlResponse(XElement element)
{
if (element == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("element");
}
Message message = Message.CreateMessage(MessageVersion.None, (string)null, element.CreateReader());
message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
AddContentType(WebOperationContext.DefaultXmlMediaType, this.OutgoingResponse.BindingWriteEncoding);
return message;
}
public Message CreateAtom10Response(SyndicationItem item)
{
if (item == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item");
}
Message message = Message.CreateMessage(MessageVersion.None, (string)null, item.GetAtom10Formatter());
message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
AddContentType(WebOperationContext.DefaultAtomMediaType, this.OutgoingResponse.BindingWriteEncoding);
return message;
}
public Message CreateAtom10Response(SyndicationFeed feed)
{
if (feed == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("feed");
}
Message message = Message.CreateMessage(MessageVersion.None, (string)null, feed.GetAtom10Formatter());
message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
AddContentType(WebOperationContext.DefaultAtomMediaType, this.OutgoingResponse.BindingWriteEncoding);
return message;
}
public Message CreateAtom10Response(ServiceDocument document)
{
if (document == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("document");
}
Message message = Message.CreateMessage(MessageVersion.None, (string)null, document.GetFormatter());
message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
AddContentType(WebOperationContext.DefaultAtomMediaType, this.OutgoingResponse.BindingWriteEncoding);
return message;
}
public Message CreateTextResponse(string text)
{
return CreateTextResponse(text, WebOperationContext.DefaultTextMediaType, Encoding.UTF8);
}
public Message CreateTextResponse(string text, string contentType)
{
return CreateTextResponse(text, contentType, Encoding.UTF8);
}
public Message CreateTextResponse(string text, string contentType, Encoding encoding)
{
if (text == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("text");
}
if (contentType == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contentType");
}
if (encoding == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("encoding");
}
Message message = new HttpStreamMessage(StreamBodyWriter.CreateStreamBodyWriter((stream) =>
{
byte[] preamble = encoding.GetPreamble();
if (preamble.Length > 0)
{
stream.Write(preamble, 0, preamble.Length);
}
byte[] bytes = encoding.GetBytes(text);
stream.Write(bytes, 0, bytes.Length);
stream.Flush();
}));
message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.RawProperty);
AddContentType(contentType, null);
return message;
}
public Message CreateTextResponse(Action<TextWriter> textWriter, string contentType)
{
Encoding encoding = this.OutgoingResponse.BindingWriteEncoding;
if (encoding == null)
{
encoding = Encoding.UTF8;
}
return CreateTextResponse(textWriter, contentType, encoding);
}
public Message CreateTextResponse(Action<TextWriter> textWriter, string contentType, Encoding encoding)
{
if (textWriter == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("textWriter");
}
if (contentType == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contentType");
}
if (encoding == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("encoding");
}
Message message = new HttpStreamMessage(StreamBodyWriter.CreateStreamBodyWriter((stream) =>
{
using (TextWriter writer = new StreamWriter(stream, encoding))
{
textWriter(writer);
}
}));
message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.RawProperty);
AddContentType(contentType, null);
return message;
}
public Message CreateStreamResponse(Stream stream, string contentType)
{
if (stream == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("stream");
}
if (contentType == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contentType");
}
Message message = ByteStreamMessage.CreateMessage(stream);
message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.RawProperty);
AddContentType(contentType, null);
return message;
}
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Using the StreamBodyWriter type instead of the BodyWriter type for discoverability. The StreamBodyWriter provides a helpful overload of the OnWriteBodyContents method that takes a Stream")]
public Message CreateStreamResponse(StreamBodyWriter bodyWriter, string contentType)
{
if (bodyWriter == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("bodyWriter");
}
if (contentType == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contentType");
}
Message message = new HttpStreamMessage(bodyWriter);
message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.RawProperty);
AddContentType(contentType, null);
return message;
}
public Message CreateStreamResponse(Action<Stream> streamWriter, string contentType)
{
if (streamWriter == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("streamWriter");
}
if (contentType == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contentType");
}
Message message = new HttpStreamMessage(StreamBodyWriter.CreateStreamBodyWriter(streamWriter));
message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.RawProperty);
AddContentType(contentType, null);
return message;
}
public UriTemplate GetUriTemplate(string operationName)
{
if (String.IsNullOrEmpty(operationName))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operationName");
}
WebHttpDispatchOperationSelector selector = OperationContext.Current.EndpointDispatcher.DispatchRuntime.OperationSelector as WebHttpDispatchOperationSelector;
if (selector == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR2.GetString(SR2.OperationSelectorNotWebSelector, typeof(WebHttpDispatchOperationSelector))));
}
return selector.GetUriTemplate(operationName);
}
void AddContentType(string contentType, Encoding encoding)
{
if (string.IsNullOrEmpty(this.OutgoingResponse.ContentType))
{
if (encoding != null)
{
contentType = WebMessageEncoderFactory.GetContentType(contentType, encoding);
}
this.OutgoingResponse.ContentType = contentType;
}
}
class XmlSerializerBodyWriter : BodyWriter
{
object instance;
XmlSerializer serializer;
public XmlSerializerBodyWriter(object instance, XmlSerializer serializer)
: base(false)
{
if (instance == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instance");
}
if (serializer == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer");
}
this.instance = instance;
this.serializer = serializer;
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
serializer.Serialize(writer, instance);
}
}
}
}

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