Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Server / System / Data / Services / WebUtil.cs / 1305376 / WebUtil.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Provides some utility functions for this project // // // @owner [....] //--------------------------------------------------------------------- namespace System.Data.Services { #region Namespaces. using System; using System.Collections; using System.Collections.Generic; using System.Data.Linq; using System.Data.Services.Internal; using System.Data.Services.Providers; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; using System.Xml; using System.Xml.Linq; #endregion Namespaces. ///Utility methods for this project. internal static class WebUtil { ///Bindings Flags for public instance members. internal const BindingFlags PublicInstanceBindingFlags = BindingFlags.Public | BindingFlags.Instance; ///A zero-length object array. internal static readonly object[] EmptyObjectArray = new object[0]; ///A zero-length string array. internal static readonly string[] EmptyStringArray = new string[0]; ///MethodInfo for object WebUtil.GetNamedPropertyValue(this object value, string propertyName, IDataServiceQueryProvider provider). internal static readonly MethodInfo GetNamedPropertyValueMethodInfo = typeof(WebUtil).GetMethod( "GetNamedPropertyValue", BindingFlags.Static | BindingFlags.NonPublic); ///Constant for "null" literal. internal static readonly ConstantExpression NullLiteral = Expression.Constant(null); // Only StackOverflowException & ThreadAbortException are sealed classes. ///Type of OutOfMemoryException. private static readonly Type OutOfMemoryType = typeof(System.OutOfMemoryException); ///Type of StackOverflowException. private static readonly Type StackOverflowType = typeof(System.StackOverflowException); ///Type of ThreadAbortException. private static readonly Type ThreadAbortType = typeof(System.Threading.ThreadAbortException); ///List of primitive types supported by Astoria and their corresponding edm names. private static readonly KeyValuePair[] PrimitiveTypesEdmNameMapping = new KeyValuePair [] { new KeyValuePair (typeof(string), XmlConstants.EdmStringTypeName), new KeyValuePair (typeof(Boolean), XmlConstants.EdmBooleanTypeName), new KeyValuePair (typeof(Boolean?), XmlConstants.EdmBooleanTypeName), new KeyValuePair (typeof(Byte), XmlConstants.EdmByteTypeName), new KeyValuePair (typeof(Byte?), XmlConstants.EdmByteTypeName), new KeyValuePair (typeof(DateTime), XmlConstants.EdmDateTimeTypeName), new KeyValuePair (typeof(DateTime?), XmlConstants.EdmDateTimeTypeName), new KeyValuePair (typeof(Decimal), XmlConstants.EdmDecimalTypeName), new KeyValuePair (typeof(Decimal?), XmlConstants.EdmDecimalTypeName), new KeyValuePair (typeof(Double), XmlConstants.EdmDoubleTypeName), new KeyValuePair (typeof(Double?), XmlConstants.EdmDoubleTypeName), new KeyValuePair (typeof(Guid), XmlConstants.EdmGuidTypeName), new KeyValuePair (typeof(Guid?), XmlConstants.EdmGuidTypeName), new KeyValuePair (typeof(Int16), XmlConstants.EdmInt16TypeName), new KeyValuePair (typeof(Int16?), XmlConstants.EdmInt16TypeName), new KeyValuePair (typeof(Int32), XmlConstants.EdmInt32TypeName), new KeyValuePair (typeof(Int32?), XmlConstants.EdmInt32TypeName), new KeyValuePair (typeof(Int64), XmlConstants.EdmInt64TypeName), new KeyValuePair (typeof(Int64?), XmlConstants.EdmInt64TypeName), new KeyValuePair (typeof(SByte), XmlConstants.EdmSByteTypeName), new KeyValuePair (typeof(SByte?), XmlConstants.EdmSByteTypeName), new KeyValuePair (typeof(Single), XmlConstants.EdmSingleTypeName), new KeyValuePair (typeof(Single?), XmlConstants.EdmSingleTypeName), new KeyValuePair (typeof(byte[]), XmlConstants.EdmBinaryTypeName), // Keep the Binary and XElement in the end, since there are not the default mappings for Edm.Binary and Edm.String. new KeyValuePair (typeof(XElement), XmlConstants.EdmStringTypeName), new KeyValuePair (typeof(Binary), XmlConstants.EdmBinaryTypeName), }; /// List of primitive types supported by Astoria and their corresponding default MIME types. private static readonly KeyValuePair[] PrimitiveTypesMimeTypeMapping = new KeyValuePair [] { new KeyValuePair (typeof(byte[]), XmlConstants.MimeApplicationOctetStream), new KeyValuePair (typeof(Binary), XmlConstants.MimeApplicationOctetStream), }; /// List of primitive types supported by Astoria and their corresponding default content format. private static readonly KeyValuePair[] PrimitiveTypesContentFormatMapping = new KeyValuePair [] { new KeyValuePair (typeof(byte[]), ContentFormat.Binary), new KeyValuePair (typeof(Binary), ContentFormat.Binary), }; /// /// Collection of ExpandedWrapper types and their corresponding number of parameters /// private static readonly ExpandWrapperTypeWithIndex[] GenericExpandedWrapperTypes = new ExpandWrapperTypeWithIndex[] { new ExpandWrapperTypeWithIndex { Type = typeof(ExpandedWrapper<,>), Index = 1 }, new ExpandWrapperTypeWithIndex { Type = typeof(ExpandedWrapper<,,>), Index = 2 }, new ExpandWrapperTypeWithIndex { Type = typeof(ExpandedWrapper<,,,>), Index = 3 }, new ExpandWrapperTypeWithIndex { Type = typeof(ExpandedWrapper<,,,,>), Index = 4 }, new ExpandWrapperTypeWithIndex { Type = typeof(ExpandedWrapper<,,,,,>), Index = 5 }, new ExpandWrapperTypeWithIndex { Type = typeof(ExpandedWrapper<,,,,,,>), Index = 6 }, new ExpandWrapperTypeWithIndex { Type = typeof(ExpandedWrapper<,,,,,,,>), Index = 7 }, new ExpandWrapperTypeWithIndex { Type = typeof(ExpandedWrapper<,,,,,,,,>), Index = 8 }, new ExpandWrapperTypeWithIndex { Type = typeof(ExpandedWrapper<,,,,,,,,,>), Index = 9 }, new ExpandWrapperTypeWithIndex { Type = typeof(ExpandedWrapper<,,,,,,,,,,>), Index = 10 }, new ExpandWrapperTypeWithIndex { Type = typeof(ExpandedWrapper<,,,,,,,,,,,>), Index = 11 }, new ExpandWrapperTypeWithIndex { Type = typeof(ExpandedWrapper<,,,,,,,,,,,,>), Index = 12 } }; ///List of primitive resource types. We don't want to create them again and again, so creating them once and caching them private static ResourceType[] primitiveResourceTypes; ////// Applies the host specified in a request if available to the given /// URI to update with host (and port) information. /// Host header (possibly null or empty) ///. /// The updated URI. internal static Uri ApplyHostHeader(Uri baseUri, string requestHost) { Debug.Assert(baseUri != null, "baseUri"); if (!String.IsNullOrEmpty(requestHost)) { UriBuilder builder = new UriBuilder(baseUri); string host; int port; if (GetHostAndPort(requestHost, baseUri.Scheme, out host, out port)) { builder.Host = host; builder.Port = port; } else { builder.Host = requestHost; } baseUri = builder.Uri; } return baseUri; } ////// Checks the argument value for null and throw ArgumentNullException if it is null /// ///type of the argument /// argument whose value needs to be checked /// name of the argument ///returns the argument back internal static T CheckArgumentNull(T value, string parameterName) where T : class { if (null == value) { throw Error.ArgumentNull(parameterName); } return value; } /// /// Checks the string argument value for empty or null and throw ArgumentNullException if it is null /// /// argument whose value needs to be checked /// name of the argument ///returns the argument back internal static string CheckStringArgumentNull(string value, string parameterName) { if (string.IsNullOrEmpty(value)) { throw Error.ArgumentNull(parameterName); } return value; } ////// Check whether the given value for ServiceOperationResultKind is valid. If not, throw argument exception. /// /// value for ServiceOperationResultKind /// name of the parameter ///if the value is not valid. internal static void CheckServiceOperationResultKind(ServiceOperationResultKind kind, string parameterName) { if (kind < ServiceOperationResultKind.DirectValue || kind > ServiceOperationResultKind.Void) { throw new ArgumentException(Strings.InvalidEnumValue(kind.GetType().Name), parameterName); } } ////// Check whether the given value for ResourceTypeKind is valid. If not, throw argument exception. /// /// value for ResourceTypeKind /// name of the parameter ///if the value is not valid. internal static void CheckResourceTypeKind(ResourceTypeKind kind, string parameterName) { if (kind < ResourceTypeKind.EntityType || kind > ResourceTypeKind.Primitive) { throw new ArgumentException(Strings.InvalidEnumValue(kind.GetType().Name), parameterName); } } ///Checks that the /// Value to check. /// Name of parameter for the exception message. internal static void CheckResourceContainerRights(EntitySetRights rights, string parameterName) { if (rights < 0 || rights > EntitySetRights.All) { throw Error.ArgumentOutOfRange(parameterName); } } ///are valid and throws an exception otherwise. Checks that the /// Value to check. /// Name of parameter for the exception message. internal static void CheckServiceOperationRights(ServiceOperationRights rights, string parameterName) { if (rights < 0 || rights > (ServiceOperationRights.All | ServiceOperationRights.OverrideEntitySetRights)) { throw Error.ArgumentOutOfRange(parameterName); } } ///are valid and throws an exception otherwise. Checks the specifid value for syntax validity. /// Whether syntax is valid. /// segment indentifier for which the resource was null. ///This helper method is used to keep syntax check code more terse. internal static void CheckResourceExists(bool resourceExists, string identifier) { if (!resourceExists) { throw DataServiceException.CreateResourceNotFound(identifier); } } ///Checks the specific value for syntax validity. /// Whether syntax is valid. ///This helper method is used to keep syntax check code more terse. internal static void CheckSyntaxValid(bool valid) { if (!valid) { throw DataServiceException.CreateSyntaxError(); } } ///Creates a new instance if the specified value is null. ///Type of variable. /// Current value. internal static void CreateIfNull(ref T value) where T : new() { if (value == null) { value = new T(); } } /// /// Debug.Assert(Enum.IsDefined(typeof(T), value)) /// ///type of enum /// enum value [Conditional("DEBUG")] internal static void DebugEnumIsDefined(T value) { Debug.Assert(Enum.IsDefined(typeof(T), value), "enum value is not valid"); } /// Disposes of /// Object to dispose, possibly null. internal static void Dispose(object o) { IDisposable disposable = o as IDisposable; if (disposable != null) { disposable.Dispose(); } } ///if it implements . Adds an empty last segment as necessary to the specified /// An absolute URI. ///. internal static Uri EnsureLastSegmentEmpty(Uri absoluteUri) { Debug.Assert(absoluteUri != null, "absoluteUri != null"); Debug.Assert(absoluteUri.IsAbsoluteUri, "absoluteUri.IsAbsoluteUri"); string[] segments = absoluteUri.Segments; if (segments.Length > 0) { string lastBaseSegment = segments[segments.Length - 1]; if (lastBaseSegment.Length > 0 && lastBaseSegment[lastBaseSegment.Length - 1] != '/') { absoluteUri = new Uri(absoluteUri, lastBaseSegment + "/"); } } return absoluteUri; } /// with an empty last segment (ie, "ending with '/'"). /// Get the expected responseFormat and the content type for the given primitive type /// /// type of the primitive /// expected content type for the given primitive type ///the expected response format for the given primitive type internal static ContentFormat GetResponseFormatForPrimitiveValue(ResourceType valueType, out string contentType) { ContentFormat result = ContentFormat.Text; contentType = XmlConstants.MimeTextPlain; // For open properties, resourceType can be null, since we don't know the property type yet. if (valueType != null) { foreach (KeyValuePairmapping in PrimitiveTypesMimeTypeMapping) { if (valueType.InstanceType == mapping.Key) { contentType = mapping.Value; break; } } foreach (KeyValuePair mapping in PrimitiveTypesContentFormatMapping) { if (valueType.InstanceType == mapping.Key) { result = mapping.Value; break; } } } return result; } /// Gets the public name for the specified /// Type to get name for. ///. A public name for the specified internal static string GetTypeName(Type type) { Debug.Assert(type != null, "type != null"); return type.FullName; } ///, empty if it cannot be found. /// Determines whether the specified exception can be caught and /// handled, or whether it should be allowed to continue unwinding. /// ///to test. /// /// true if the specified exception can be caught and handled; /// false otherwise. /// internal static bool IsCatchableExceptionType(Exception e) { // a 'catchable' exception is defined by what it is not. Debug.Assert(e != null, "Unexpected null exception!"); Type type = e.GetType(); return ((type != StackOverflowType) && (type != OutOfMemoryType) && (type != ThreadAbortType)); } ///Marks the fact that a recursive method was entered, and checks that the depth is allowed. /// Maximum recursion limit. /// Depth of recursion. internal static void RecurseEnterQueryParser(int recursionLimit, ref int recursionDepth) { recursionDepth++; Debug.Assert(recursionDepth <= recursionLimit, "recursionDepth <= recursionLimit"); if (recursionDepth == recursionLimit) { throw DataServiceException.CreateDeepRecursion_General(); } } ///Marks the fact that a recursive method was entered, and checks that the depth is allowed. /// Maximum recursion limit. /// Depth of recursion. internal static void RecurseEnter(int recursionLimit, ref int recursionDepth) { recursionDepth++; Debug.Assert(recursionDepth <= recursionLimit, "recursionDepth <= recursionLimit"); if (recursionDepth == recursionLimit) { throw DataServiceException.CreateDeepRecursion(recursionLimit); } } ///Marks the fact that a recursive method is leaving. /// Depth of recursion. internal static void RecurseLeave(ref int recursionDepth) { recursionDepth--; Debug.Assert(0 <= recursionDepth, "0 <= recursionDepth"); } ///Selects the request format type from the content type. /// content type as specified in the request header /// request description for which the content type was specified. ///enum representing the response format for the given content type internal static ContentFormat SelectRequestFormat(string contentType, RequestDescription description) { ContentFormat contentFormat; if (WebUtil.CompareMimeType(contentType, XmlConstants.MimeApplicationJson)) { contentFormat = ContentFormat.Json; } else if (WebUtil.CompareMimeType(contentType, XmlConstants.MimeTextXml) || WebUtil.CompareMimeType(contentType, XmlConstants.MimeApplicationXml)) { contentFormat = ContentFormat.PlainXml; } else if (WebUtil.CompareMimeType(contentType, XmlConstants.MimeApplicationAtom) || WebUtil.CompareMimeType(contentType, XmlConstants.MimeAny)) { contentFormat = ContentFormat.Atom; } else { return ContentFormat.Unsupported; } if (description.LinkUri) { if (contentFormat == ContentFormat.Atom) { throw new DataServiceException( 415, Strings.BadRequest_InvalidContentTypeForRequestUri(contentType, String.Format(CultureInfo.InvariantCulture, "'{0}', '{1}', '{2}'", XmlConstants.MimeApplicationJson, XmlConstants.MimeApplicationXml, XmlConstants.MimeTextXml))); } } else if (description.TargetKind == RequestTargetKind.Resource || description.LastSegmentInfo.HasKeyValues) { // If the target is a resource (for open properties, it must have key values or its a collection - nav properties) // For reference open properties, this check needs to be done in each deserializer if (contentFormat == ContentFormat.PlainXml) { throw new DataServiceException( 415, Strings.BadRequest_InvalidContentTypeForRequestUri(contentType, String.Format(CultureInfo.InvariantCulture, "'{0}', '{1}', '{2}'", XmlConstants.MimeApplicationJson, XmlConstants.MimeApplicationAtom, XmlConstants.MimeAny))); } } else if ( description.TargetKind != RequestTargetKind.OpenProperty && contentFormat == ContentFormat.Atom) { throw new DataServiceException( 415, Strings.BadRequest_InvalidContentTypeForRequestUri(contentType, String.Format(CultureInfo.InvariantCulture, "'{0}', '{1}', '{2}'", XmlConstants.MimeApplicationJson, XmlConstants.MimeApplicationXml, XmlConstants.MimeTextXml))); } return contentFormat; } ///Converts comma-separated entries with no quotes into a text array. /// Text to convert. ///A string array that represents the comma-separated values in the text. ///This method can be used to provide a simpler API facade instead of identifier arrays. internal static string[] StringToSimpleArray(string text) { if (String.IsNullOrEmpty(text)) { return EmptyStringArray; } else { return text.Split(new char[] { ',' }, StringSplitOptions.None); } } ////// Test if any of the types in the hierarchy of /// base type of the hierarchy /// IDataServiceMetadataProvider interface instance ///is a Media Link Entry. /// Returns true if internal static bool HasMediaLinkEntryInHierarchy(ResourceType baseType, DataServiceProviderWrapper provider) { if (baseType.IsMediaLinkEntry) { return true; } else { foreach (ResourceType derivedType in provider.GetDerivedTypes(baseType)) { if (derivedType.IsMediaLinkEntry) { return true; } } } return false; } ///or at least one of its descendants is a Media Link Entry. copy from one stream to another /// input stream /// output stream /// reusable buffer ///count of copied bytes internal static long CopyStream(Stream input, Stream output, byte[] buffer) { Debug.Assert(null != input, "null input stream"); Debug.Assert(input.CanRead, "input.CanRead"); Debug.Assert(null != output, "null output stream"); Debug.Assert(output.CanWrite, "output.CanWrite"); Debug.Assert(buffer != null, "buffer != null"); long total = 0; int count = 0; while (0 < (count = input.Read(buffer, 0, buffer.Length))) { output.Write(buffer, 0, count); total += count; } return total; } ///copy from one stream to another /// input stream /// output stream /// size of buffer to use during copying. If 0 is specified, the default of 64K will be used. ///count of copied bytes internal static long CopyStream(Stream input, Stream output, int bufferSize) { // 64K = 65536 bytes. const int DefaultBufferSize = 65536; byte[] buffer = new byte[bufferSize <= 0 ? DefaultBufferSize : bufferSize]; return CopyStream(input, output, buffer); } ////// Creates a delegate that when called creates a new instance of the specified /// Type of the instance. /// full name of the given clr type. /// If the type name is not specified, it takes the full name from the clr type. /// Type to return from the delegate. ///. /// A delegate that when called creates a new instance of the specified internal static Delegate CreateNewInstanceConstructor(Type type, string fullName, Type targetType) { Debug.Assert(type != null, "type != null"); Debug.Assert(targetType != null, "targetType != null"); // Create the new instance of the type ConstructorInfo emptyConstructor = type.GetConstructor(Type.EmptyTypes); if (emptyConstructor == null) { fullName = fullName ?? type.FullName; throw new InvalidOperationException(Strings.NoEmptyConstructorFoundForType(fullName)); } System.Reflection.Emit.DynamicMethod method = new System.Reflection.Emit.DynamicMethod("invoke_constructor", targetType, Type.EmptyTypes, false); var generator = method.GetILGenerator(); generator.Emit(System.Reflection.Emit.OpCodes.Newobj, emptyConstructor); if (targetType.IsValueType) { generator.Emit(System.Reflection.Emit.OpCodes.Box); } generator.Emit(System.Reflection.Emit.OpCodes.Ret); return method.CreateDelegate(typeof(Func<>).MakeGenericType(targetType)); } ///. Checks whether the specified type is a known primitive type. /// Type to check. ///true if the specified type is known to be a primitive type; false otherwise. internal static bool IsPrimitiveType(Type type) { if (type == null) { return false; } foreach (KeyValuePairprimitiveTypeInfo in PrimitiveTypesEdmNameMapping) { if (type == primitiveTypeInfo.Key) { return true; } } return false; } /// /// Try to resolve a type by name by first trying primitive types and then provider's types /// /// Provider to resolve non-primitive types against /// Type name ///ResourceType object for this type, or null if none found internal static ResourceType TryResolveResourceType(DataServiceProviderWrapper provider, string typeName) { Debug.Assert(provider != null, "provider != null"); Debug.Assert(typeName != null, "typeName != null"); ResourceType resourceType = null; ResourceType[] types = WebUtil.GetPrimitiveTypes(); for (int i = 0; i < types.Length; i++) { if (types[i].FullName == typeName) { resourceType = types[i]; break; } } if (resourceType == null) { resourceType = provider.TryResolveResourceType(typeName); } return resourceType; } ////// Get a primitive or EDM type from an instance /// /// Provider to get EDM types from, in caseis not a primitive. /// Instance to get the type from /// A ResourceType for this instance or null if it is not a known type internal static ResourceType GetResourceType(DataServiceProviderWrapper provider, object obj) { Debug.Assert(obj != null, "obj != null"); Debug.Assert(provider != null, "provider != null"); ResourceType r = ResourceType.GetPrimitiveResourceType(obj.GetType()); if (r == null) { // Note that GetNonPrimitiveResourceType() will throw if we fail to get the resource type. r = GetNonPrimitiveResourceType(provider, obj); } return r; } ////// Get the non primitive type resource and checks that the given instance represents a single resource. /// /// underlying data source. /// instance of the resource. ///returns the resource type representing the given resource instance. internal static ResourceType GetNonPrimitiveResourceType(DataServiceProviderWrapper provider, object obj) { Debug.Assert(obj != null, "obj != null"); ResourceType resourceType; IProjectedResult projectedResult = obj as IProjectedResult; if (projectedResult != null) { resourceType = provider.TryResolveResourceType(projectedResult.ResourceTypeName); } else { resourceType = provider.GetResourceType(obj); } if (resourceType == null) { throw new DataServiceException(500, Strings.BadProvider_InvalidTypeSpecified(obj.GetType().FullName)); } return resourceType; } ///Gets the root type of the given resource type. /// ResourceType to get least derived type for. ///The least derived type for the specified internal static ResourceType GetRootType(ResourceType resourceType) { if (resourceType == null) { return resourceType; } while (resourceType.BaseType != null) { resourceType = resourceType.BaseType; } return resourceType; } ///. /// Checks whether the specified /// Simple MIME type. ////// is a valid MIME type with no parameters. /// /// true if the specified ///is valid; /// false otherwise. /// /// See http://tools.ietf.org/html/rfc2045#section-5.1 for futher details. /// internal static bool IsValidMimeType(string mimeType) { Debug.Assert(mimeType != null, "mimeType != null"); const string Tspecials = "()<>@,;:\\\"/[]?="; bool partFound = false; bool slashFound = false; bool subTypeFound = false; foreach (char c in mimeType) { Debug.Assert(partFound || !slashFound, "partFound || !slashFound -- slashFound->partFound"); Debug.Assert(slashFound || !subTypeFound, "slashFound || !subTypeFound -- subTypeFound->slashFound"); if (c == '/') { if (!partFound || slashFound) { return false; } slashFound = true; } else if (c < '\x20' || c > '\x7F' || c == ' ' || Tspecials.IndexOf(c) >= 0) { return false; } else { if (slashFound) { subTypeFound = true; } else { partFound = true; } } } return subTypeFound; } ////// Checks whether the specified element is an /// Element to check (possibly null). ////// of other elements. /// , or null if is not supported. /// /// true if internal static bool IsElementIEnumerable(object element, out IEnumerable enumerable) { enumerable = element as IEnumerable; if (enumerable == null) { return false; } // Primitive types are atomic, not enumerable, even if they implement IEnumerable. Type elementType = element.GetType(); foreach (ResourceType type in GetPrimitiveTypes()) { if (type.InstanceType == elementType) { return false; } } return true; } ///supports IEnumerable and is not /// a primitive type (strings and byte arrays are also enumerables, but /// they shouldn't be iterated over, so they return false). /// /// Returns false if the given etag value is not valid. /// Look in http://www.ietf.org/rfc/rfc2616.txt?number=2616 (Section 14.26) for more information /// /// etag value to be checked. /// true if we allow strong etag values. ///returns true if the etag value is valid, otherwise returns false. internal static bool IsETagValueValid(string etag, bool allowStrongEtag) { if (String.IsNullOrEmpty(etag) || etag == XmlConstants.HttpAnyETag) { return true; } // HTTP RFC 2616, section 3.11: // entity-tag = [ weak ] opaque-tag // weak = "W/" // opaque-tag = quoted-string int etagValueStartIndex = 1; if (etag.StartsWith(XmlConstants.HttpWeakETagPrefix, StringComparison.Ordinal) && etag[etag.Length - 1] == '"') { etagValueStartIndex = 3; } else if (!allowStrongEtag || etag[0] != '"' || etag[etag.Length - 1] != '"') { return false; } for (int i = etagValueStartIndex; i < etag.Length - 1; i++) { // Format of etag looks something like: W/"etag property values" or "strong etag value" // according to HTTP RFC 2616, if someone wants to specify more than 1 etag value, // then need to specify something like this: W/"etag values", W/"etag values", ... // To make sure only one etag is specified, we need to ensure that if " is part of the // key value, it needs to be escaped. if (etag[i] == '"') { return false; } } return true; } ///Checks whether the specified /// Type to check. ///can be assigned null. true if type is a reference type or a Nullable type; false otherwise. internal static bool TypeAllowsNull(Type type) { Debug.Assert(type != null, "type != null"); return !type.IsValueType || IsNullableType(type); } ///Gets a type for /// Type to base resulting type on. ///that allows null values. /// internal static Type GetTypeAllowingNull(Type type) { Debug.Assert(type != null, "type != null"); return TypeAllowsNull(type) ? type : typeof(Nullable<>).MakeGenericType(type); } ///if it's a reference or Nullable<> type; /// Nullable< > otherwise. /// Checks whether the specified type is a generic nullable type. /// Type to check. ///true if internal static bool IsNullableType(Type type) { return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); } ///is nullable; false otherwise. Checks whether /// Expression to check. ///is a null constant. true if internal static bool IsNullConstant(Expression expression) { Debug.Assert(expression != null, "expression != null"); return expression == NullLiteral || (expression.NodeType == ExpressionType.Constant && ((ConstantExpression)expression).Value == null); } ///is a null constant; false otherwise. Returns the etag for the given resource. /// Resource for which etag value needs to be returned. /// Resource type of the. /// list of etag properties for the given resource /// Service to which the request was made. /// whether the request was a get method or not. /// ETag value for the given resource, with values encoded for use in a URI. internal static string GetETagValue(object resource, ResourceType resourceType, ICollectionetagProperties, IDataService service, bool getMethod) { Debug.Assert(etagProperties.Count != 0, "etagProperties.Count != 0"); StringBuilder resultBuilder = new StringBuilder(); bool firstKey = true; resultBuilder.Append(XmlConstants.HttpWeakETagPrefix); foreach (ResourceProperty property in etagProperties) { object keyValue; // We need to call IUpdatable.GetValue, if we are still trying to get // property value as part of the update changes. If the CUD operation // is done (i.e. IUpdatable.SaveChanges) have been called, and if we // need to compute the etag, we go via the IDSP.GetPropertyValue. // This was the V1 behavior and not changing this now. // The getMethod variable name is misleading, since this might be true // even for CUD operations, but only after SaveChanges is called. if (getMethod) { keyValue = WebUtil.GetPropertyValue(service.Provider, resource, resourceType, property, null); } else { keyValue = service.Updatable.GetValue(resource, property.Name); } if (firstKey) { firstKey = false; } else { resultBuilder.Append(','); } string keyValueText; if (keyValue == null) { keyValueText = XmlConstants.NullLiteralInETag; } else if (!System.Data.Services.Parsing.WebConvert.TryKeyPrimitiveToString(keyValue, out keyValueText)) { throw new InvalidOperationException(Strings.Serializer_CannotConvertValue(keyValue)); } Debug.Assert(keyValueText != null, "keyValueText != null - otherwise TryKeyPrimitiveToString returned true and null value"); resultBuilder.Append(System.Uri.EscapeDataString(keyValueText)); } resultBuilder.Append('"'); return resultBuilder.ToString(); } /// Returns the etag for the given resource. /// Data service to which the request was made. /// Resource for which etag value needs to be returned. /// resource set to which the resource belongs to. ///ETag value for the given resource, with values encoded for use in a URI. internal static string GetETagValue(IDataService service, object resource, ResourceSetWrapper container) { ResourceType resourceType = WebUtil.GetNonPrimitiveResourceType(service.Provider, resource); ICollectionetagProperties = service.Provider.GetETagProperties(container.Name, resourceType); if (etagProperties.Count != 0) { return WebUtil.GetETagValue(resource, resourceType, etagProperties, service, true /*getMethod*/); } else { return null; } } /// /// Gets the type namespace of the specified /// Type to get namespace for. ///, /// appropriate as an externally-visible type name. /// The namespace for internal static string GetModelTypeNamespace(Type type) { Debug.Assert(type != null, "type != null"); return type.Namespace ?? ""; } ///. Returns an array of primitive types supported. ///An array of primitive types supported ///Most of the time ResourceType.GetPrimitiveResourceType should be used instead of /// searching this array directly, as it takes into account nullable types. internal static ResourceType[] GetPrimitiveTypes() { if (primitiveResourceTypes == null) { ResourceType[] types = new ResourceType[PrimitiveTypesEdmNameMapping.Length]; for (int i = 0; i < types.Length; i++) { string fullName = PrimitiveTypesEdmNameMapping[i].Value; Debug.Assert(fullName.StartsWith(XmlConstants.EdmNamespace, StringComparison.Ordinal), "fullName.StartsWith(XmlConstants.EdmNamespace, StringComparison.Ordinal)"); string name = fullName.Substring(XmlConstants.EdmNamespace.Length + 1); types[i] = new ResourceType(PrimitiveTypesEdmNameMapping[i].Key, XmlConstants.EdmNamespace, name); } System.Threading.Interlocked.CompareExchange(ref primitiveResourceTypes, types, null); } Debug.Assert(primitiveResourceTypes != null, "primitiveResourceTypes != null"); return primitiveResourceTypes; } /// /// Gets an /// Request enumerable to get enumerator for. ///for the specified , /// mapping well-known exceptions to the appropriate HTTP status code. /// An internal static IEnumerator GetRequestEnumerator(IEnumerable enumerable) { try { return enumerable.GetEnumerator(); } catch (NotImplementedException e) { // 501: Not Implemented throw new DataServiceException(501, null, Strings.DataService_NotImplementedException, null, e); } catch (NotSupportedException e) { // 501: Not Implemented throw new DataServiceException(501, null, Strings.DataService_NotImplementedException, null, e); } } ///for the specified . /// Given the request description, query for the parent entity resource /// and compare the etag, if specified in the header /// /// entity resource for which etag needs to be checked. /// token as returned by the IUpdatable interface methods. /// container to which the entity resource belongs to. /// Underlying service to which the request was made to. /// out bool which indicates whether response needs to be written for GET operations ///current etag value for the given entity resource. internal static string CompareAndGetETag( object parentEntityResource, object parentEntityToken, ResourceSetWrapper container, IDataService service, out bool writeResponseForGetMethods) { Debug.Assert(service.OperationContext.Host != null, "service.OperationContext.Host != null"); DataServiceHostWrapper host = service.OperationContext.Host; // If this method is called for Update, we need to pass the token object as well as the actual instance. // The actual instance is used to determine the type that's necessary to find out the etag properties. // The token is required to pass back to IUpdatable interface, if we need to get the values for etag properties. Debug.Assert(host.AstoriaHttpVerb == AstoriaVerbs.GET, "this method must be called for GET operations only"); writeResponseForGetMethods = true; string etag = null; // For .e.g when you are querying for /Customers(1)/BestFriend, the value can be null. // Hence in this case, if the If-Match header value is specified, we throw. if (parentEntityResource == null) { if (!String.IsNullOrEmpty(host.RequestIfMatch)) { throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch); } } else { ResourceType resourceType = WebUtil.GetNonPrimitiveResourceType(service.Provider, parentEntityResource); ICollectionetagProperties = service.Provider.GetETagProperties(container.Name, resourceType); if (etagProperties.Count == 0) { // Cannot specify etag for types that don't have etag properties. if (!String.IsNullOrEmpty(host.RequestIfMatch)) { throw DataServiceException.CreateBadRequestError(Strings.Serializer_NoETagPropertiesForType); } } else if (String.IsNullOrEmpty(host.RequestIfMatch) && String.IsNullOrEmpty(host.RequestIfNoneMatch)) { // no need to check anything if no header is specified. } else if (host.RequestIfMatch == XmlConstants.HttpAnyETag) { // just return - for put, perform the operation and get, return the payload } else if (host.RequestIfNoneMatch == XmlConstants.HttpAnyETag) { // If-None-Match is not allowed for PUT. Hence there is no point checking that // For GET, return Not Modified writeResponseForGetMethods = false; } else { etag = WebUtil.GetETagValue(parentEntityToken, resourceType, etagProperties, service, true /*getMethod*/); if (String.IsNullOrEmpty(host.RequestIfMatch)) { Debug.Assert(!String.IsNullOrEmpty(host.RequestIfNoneMatch), "Both can't be null, otherwise it should have entered the first condition"); if (host.RequestIfNoneMatch == etag) { writeResponseForGetMethods = false; } } else if (etag != host.RequestIfMatch) { throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch); } } if (etag == null && etagProperties.Count != 0) { etag = WebUtil.GetETagValue(parentEntityResource, resourceType, etagProperties, service, true /*getMethod*/); } } return etag; } #if DEBUG /// /// Write the etag header value in the response /// /// description about the request made /// etag value that needs to be written. /// Host implementation for this data service. internal static void WriteETagValueInResponseHeader(RequestDescription requestDescription, string etagValue, DataServiceHostWrapper host) #else ////// Write the etag header value in the response /// /// etag value that needs to be written. /// Host implementation for this data service. internal static void WriteETagValueInResponseHeader(string etagValue, DataServiceHostWrapper host) #endif { if (!string.IsNullOrEmpty(etagValue)) { #if DEBUG // asserting that etag response header is written only in cases when the etag request headers are allowed. Debug.Assert(requestDescription == null || RequestDescription.IsETagHeaderAllowed(requestDescription), "etag should not be computed before serialization time if etag response header is not allowed"); Debug.Assert(requestDescription == null || WebUtil.IsETagValueValid(etagValue, requestDescription.TargetKind == RequestTargetKind.MediaResource), "WebUtil.IsETagValueValid(etagValue)"); Debug.Assert(string.IsNullOrEmpty(host.ResponseETag), "string.IsNullOrEmpty(host.ResponseETag)"); #endif host.ResponseETag = etagValue; } } ///Writes an xml:space='preserve' attribute if the element value would need it. /// XmlWriter to write to. /// Value that will be written after this call. internal static void WriteSpacePreserveAttributeIfNecessary(XmlWriter writer, string elementValue) { if (elementValue.Length > 0 && (Char.IsWhiteSpace(elementValue, 0) || Char.IsWhiteSpace(elementValue, elementValue.Length - 1))) { WriteSpacePreserveAttribute(writer); } } ////// If the specified reader is not on an element, advances to one, skipping document declaration /// nodes (typically at the beginning of a document), comments, processing instructions and /// whitespace. /// /// Reader to reposition. ////// true if the reader is left on an element; false otherwise. /// internal static bool XmlReaderEnsureElement(XmlReader reader) { Debug.Assert(reader != null, "reader != null"); do { switch (reader.NodeType) { case XmlNodeType.Element: return true; case XmlNodeType.Comment: case XmlNodeType.None: case XmlNodeType.ProcessingInstruction: case XmlNodeType.XmlDeclaration: case XmlNodeType.Whitespace: break; case XmlNodeType.Text: if (WebUtil.IsWhitespace(reader.Value)) { break; } else { return false; } default: return false; } } while (reader.Read()); return false; } ///Gets the text for a well-known status code. /// Status code to get text for. ///Text for the status code; an empty string if internal static string GetStatusCodeText(int statusCode) { #region Non-localized messages for status codes. switch (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: return "Unknown Status Code"; } #endregion Non-localized messages for status codes. } ///is unknown. /// Checks whether a given object implements IServiceProvider and if it supports the specified service interface /// ///The type representing the requested service /// Object that acts as the service provider ///An object implementing the requested service, or null if not available internal static T GetService(object target) where T : class { IServiceProvider provider = target as IServiceProvider; if (provider != null) { object service = provider.GetService(typeof(T)); if (service != null) { return (T)service; } } return null; } /// /// Gets the type corresponding to the wrapper based in input parameter types /// /// Parameter types /// Delegate that generates the error ///Closed generic type internal static Type GetWrapperType(Type[] wrapperParameters, Func
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- RowToFieldTransformer.cs
- SupportingTokenSpecification.cs
- MetabaseServerConfig.cs
- XmlHierarchicalDataSourceView.cs
- WebPartConnectionsConfigureVerb.cs
- XmlAnyElementAttribute.cs
- Decoder.cs
- MultitargetUtil.cs
- InputBinder.cs
- Underline.cs
- MulticastDelegate.cs
- Figure.cs
- Rect3D.cs
- EntityException.cs
- XsltFunctions.cs
- SoapAttributeAttribute.cs
- ImportedNamespaceContextItem.cs
- CultureMapper.cs
- Encoder.cs
- WebBrowserSiteBase.cs
- PolyQuadraticBezierSegmentFigureLogic.cs
- followingsibling.cs
- TextBoxBaseDesigner.cs
- RuntimeResourceSet.cs
- NameObjectCollectionBase.cs
- FileDetails.cs
- FrameworkObject.cs
- ClientFormsAuthenticationCredentials.cs
- ConfigurationElementProperty.cs
- BitmapSource.cs
- EntityFunctions.cs
- BitmapFrame.cs
- DataControlLinkButton.cs
- DataGridRowDetailsEventArgs.cs
- MappingItemCollection.cs
- XmlQualifiedName.cs
- OleAutBinder.cs
- DSASignatureFormatter.cs
- StickyNoteHelper.cs
- EasingFunctionBase.cs
- GenericUriParser.cs
- GroupDescription.cs
- CanonicalFontFamilyReference.cs
- UnauthorizedAccessException.cs
- MenuItem.cs
- MobileControlDesigner.cs
- VirtualPathUtility.cs
- Underline.cs
- FrameworkName.cs
- DataBindingHandlerAttribute.cs
- PropertyGridView.cs
- _SafeNetHandles.cs
- AlignmentXValidation.cs
- Set.cs
- NativeCppClassAttribute.cs
- EntityContainerRelationshipSet.cs
- ModuleBuilder.cs
- _LocalDataStoreMgr.cs
- ExitEventArgs.cs
- DataServiceClientException.cs
- TextPointer.cs
- BrowserCapabilitiesFactoryBase.cs
- SQLInt16Storage.cs
- TypeValidationEventArgs.cs
- SendOperation.cs
- SeverityFilter.cs
- Accessible.cs
- RawMouseInputReport.cs
- ActivityExecutorOperation.cs
- WebPartPersonalization.cs
- EndpointInfo.cs
- ValidatingPropertiesEventArgs.cs
- ResourceDescriptionAttribute.cs
- NegotiateStream.cs
- PeerTransportBindingElement.cs
- Timer.cs
- rsa.cs
- AmbiguousMatchException.cs
- TransformerConfigurationWizardBase.cs
- ExpressionsCollectionEditor.cs
- TrackingValidationObjectDictionary.cs
- BufferedWebEventProvider.cs
- UserPrincipalNameElement.cs
- SecurityUtils.cs
- SequenceFullException.cs
- PrePostDescendentsWalker.cs
- QueryContinueDragEvent.cs
- MouseButtonEventArgs.cs
- SmtpMail.cs
- PenCursorManager.cs
- SimplePropertyEntry.cs
- PageThemeParser.cs
- IPPacketInformation.cs
- MarkerProperties.cs
- DelayedRegex.cs
- DbUpdateCommandTree.cs
- RuleSettings.cs
- MatrixTransform3D.cs
- MaterializeFromAtom.cs
- VirtualPathUtility.cs