WebUtil.cs source code in C# .NET

Source code for the .NET framework in C#

                        

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  are valid and throws an exception otherwise. 
        /// 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);
            }
        } 

        /// Checks that the  are valid and throws an exception otherwise. 
        /// 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); 
            }
        } 
 
        /// 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  if it implements .
        /// Object to dispose, possibly null. 
        internal static void Dispose(object o)
        {
            IDisposable disposable = o as IDisposable;
            if (disposable != null) 
            {
                disposable.Dispose(); 
            } 
        }
 
        /// Adds an empty last segment as necessary to the specified .
        /// An absolute URI.
        ///  with an empty last segment (ie, "ending with '/'").
        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; 
        }

        /// 
        /// 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 (KeyValuePair mapping 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 , empty if it cannot be found.
        internal static string GetTypeName(Type type) 
        { 
            Debug.Assert(type != null, "type != null");
            return type.FullName; 
        }

        /// 
        /// 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  is a Media Link Entry.
        ///  
        /// base type of the hierarchy
        /// IDataServiceMetadataProvider interface instance
        /// Returns true if  or at least one of its descendants is a Media Link Entry.
        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;
        } 

        /// 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 (KeyValuePair primitiveTypeInfo 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 case  is 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 
        /// is a valid MIME type with no parameters.
        /// 
        /// Simple MIME type. 
        /// 
        /// 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  
        /// of other elements.
        /// 
        /// Element to check (possibly null).
        /// , or null if  is not supported. 
        /// 
        /// true if  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).
        ///  
        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;
        }
 
        /// 
        /// 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  can be assigned null. 
        /// Type to check.
        /// 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  that allows null values. 
        /// Type to base resulting type on.
        ///  
        ///  if it's a reference or Nullable<> type; 
        /// Nullable<> otherwise.
        ///  
        internal static Type GetTypeAllowingNull(Type type)
        {
            Debug.Assert(type != null, "type != null");
            return TypeAllowsNull(type) ? type : typeof(Nullable<>).MakeGenericType(type); 
        }
 
        /// Checks whether the specified type is a generic nullable type. 
        /// Type to check.
        /// true if  is nullable; false otherwise. 
        internal static bool IsNullableType(Type type)
        {
            return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
        } 

        /// Checks whether  is a null constant. 
        /// Expression to check. 
        /// true if  is a null constant; false otherwise.
        internal static bool IsNullConstant(Expression expression) 
        {
            Debug.Assert(expression != null, "expression != null");
            return
                expression == NullLiteral || 
                (expression.NodeType == ExpressionType.Constant && ((ConstantExpression)expression).Value == null);
        } 
 
        /// 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, ICollection etagProperties, 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); 
            ICollection etagProperties = 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 ,
        /// appropriate as an externally-visible type name. 
        /// 
        /// Type to get namespace for.
        /// 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  for the specified ,
        /// mapping well-known exceptions to the appropriate HTTP status code. 
        /// 
        /// Request enumerable to get enumerator for.
        /// An  for the specified .
        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); 
            }
        }

        ///  
        /// 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); 
                ICollection etagProperties = 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  is unknown. 
        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.
        }

        ///  
        /// 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 errorGenerator) 
        {
            Debug.Assert(wrapperParameters.Length > 1, "Must have 1 element besides the ProjectedType"); 
            if (wrapperParameters.Length - 1 > 12) 
            {
                throw DataServiceException.CreateBadRequestError(errorGenerator(wrapperParameters.Length - 1)); 
            }

            return WebUtil.GenericExpandedWrapperTypes.Single(x => x.Index == wrapperParameters.Length - 1).Type.MakeGenericType(wrapperParameters);
        } 

        ///  
        /// Checks if the given type is an ExpandedWrapper type 
        /// 
        /// Input closed type 
        /// true if the given type is one of ExpandedWrapper types
        internal static bool IsExpandedWrapperType(Type inputType)
        {
            return inputType.IsGenericType && WebUtil.GenericExpandedWrapperTypes.SingleOrDefault(x => x.Type == inputType.GetGenericTypeDefinition()) != null; 
        }
 
        ///  
        /// Returns an enumeration that picks one element from each enumerable and projects from them.
        ///  
        /// Type of first enumerable.
        /// Type of second enumerable.
        /// Type of zipped projection.
        /// Left enumerable. 
        /// Right enumerable.
        /// Projecting function. 
        /// An enumeration with the projected results. 
        internal static IEnumerable Zip(IEnumerable left, IEnumerable right, Func resultSelector)
        { 
            if (null == left || null == right)
            {
                yield break;
            } 

            resultSelector = resultSelector ?? ((x, y) => default(TResult)); 
            using (var l = left.GetEnumerator()) 
            using (var r = right.GetEnumerator())
            { 
                while (l.MoveNext() && r.MoveNext())
                {
                    yield return resultSelector(l.Current, r.Current);
                } 
            }
        } 
 
        /// are the two values the same reference
        /// value1 
        /// value2
        /// true if they are the same reference
        internal static bool AreSame(string value1, string value2)
        { 
            // bool result = Object.ReferenceEquals(value1, value2);
            // Debug.Assert(result == (value1 == value2), "!NameTable - unable to do reference comparison on '" + value1 + "'"); 
            // XElement uses a global name table which may have encountered 
            // our strings first and return a different instance than what was expected
            bool result = (value1 == value2); 
            return result;
        }

        /// is the reader on contentNode where the localName and namespaceUri match 
        /// reader
        /// localName 
        /// namespaceUri 
        /// true if localName and namespaceUri match reader current element
        internal static bool AreSame(XmlReader reader, string localName, string namespaceUri) 
        {
            Debug.Assert((null != reader) && (null != localName) && (null != namespaceUri), "null");
            return ((XmlNodeType.Element == reader.NodeType) || (XmlNodeType.EndElement == reader.NodeType)) &&
                    AreSame(reader.LocalName, localName) && AreSame(reader.NamespaceURI, namespaceUri); 
        }
 
        ///  
        /// Skips the children of the current node.
        ///  
        /// XmlReader to skip content from
        /// local name of the node we search to
        /// namespace of the node we search to
        internal static void SkipToEnd(XmlReader xmlReader, string localName, string namespaceURI) 
        {
            //  
            //  
            // 
            int readerDepth = xmlReader.Depth; 

            do
            {
                switch (xmlReader.NodeType) 
                {
                    case XmlNodeType.Element: 
                        if (xmlReader.IsEmptyElement && 
                            xmlReader.Depth == readerDepth &&
                            AreSame(xmlReader, localName, namespaceURI)) 
                        {
                            return;
                        }
 
                        break;
 
                    case XmlNodeType.EndElement: 
                        if (xmlReader.Depth <= readerDepth)
                        {   // new end element 
                            readerDepth--;

                            if (AreSame(xmlReader, localName, namespaceURI))
                            { 
                                return;
                            } 
                        } 

                        break; 
                }
            }
            while (xmlReader.Read());
        } 

        ///  
        /// get attribute value from specified namespace or empty namespace 
        /// 
        /// reader 
        /// attributeName
        /// namespaceUri
        /// attribute value
        internal static string GetAttributeEx(XmlReader reader, string attributeName, string namespaceUri) 
        {
            return reader.GetAttribute(attributeName, namespaceUri) ?? reader.GetAttribute(attributeName); 
        } 

        ///  
        /// Does a ordinal ignore case comparision of the given mime types.
        /// 
        /// mime type1.
        /// mime type2. 
        /// returns true if the mime type are the same.
        internal static bool CompareMimeType(string mimeType1, string mimeType2) 
        { 
            return String.Equals(mimeType1, mimeType2, StringComparison.OrdinalIgnoreCase);
        } 

        /// 
        /// Disposes the stream provider and returns a no-op method for a stream-writing action.
        ///  
        /// A delegate that can serialize the result.
        internal static Action GetEmptyStreamWriter() 
        { 
            return stream => { };
        } 

        /// Gets a named value from the specified object.
        /// Object to get value from.
        /// Name of property to get. 
        /// Data Service provider used for verification of rights
        /// The requested value; null if not found. 
        internal static object GetNamedPropertyValue(object value, string propertyName, DataServiceProviderWrapper provider) 
        {
            if (value != null) 
            {
                ResourceType resourceType = WebUtil.GetNonPrimitiveResourceType(provider, value);
                ResourceProperty resourceProperty = resourceType.TryResolvePropertyName(propertyName);
                return WebUtil.GetPropertyValue( 
                                    provider,
                                    value, 
                                    resourceType, 
                                    resourceProperty,
                                    resourceProperty == null ? propertyName : null); 
            }
            else
            {
                return null; 
            }
        } 
 
        /// 
        /// Get the value of the given property. 
        /// 
        /// underlying data provider.
        /// instance of the type which contains this property.
        /// resource type instance containing metadata about the declaring type. 
        /// resource property instance containing metadata about the property.
        /// Name of the property to read if  is not given. 
        /// the value of the given property. 
        internal static object GetPropertyValue(DataServiceProviderWrapper provider, object resource, ResourceType resourceType, ResourceProperty resourceProperty, String propertyName)
        { 
            Debug.Assert(provider != null, "provider != null");
            Debug.Assert(resource != null, "resource != null");
            Debug.Assert(
                (resourceProperty == null && propertyName != null) || (resourceProperty != null && propertyName == null), 
                "One of resourceProperty or propertyName should be null and other non-null.");
 
            IProjectedResult projectedResult = resource as IProjectedResult; 
            if (projectedResult != null)
            { 
                object result = projectedResult.GetProjectedPropertyValue(propertyName ?? resourceProperty.Name);
                if (result == DBNull.Value)
                {
                    result = null; 
                }
 
                return result; 
            }
 
            if (resourceProperty != null)
            {
                return provider.GetPropertyValue(resource, resourceProperty, resourceType);
            } 

            Debug.Assert(resourceType != null, "resourceType != null"); 
            Debug.Assert(propertyName != null, "propertyName != null"); 
            Debug.Assert(resourceType.IsOpenType, "resourceType must be of open type.");
            return provider.GetOpenPropertyValue(resource, propertyName); 
        }

        /// Checks that the specified  has a known version.
        /// Service to check. 
        /// The request description object
        internal static void CheckVersion(IDataService service, RequestDescription requestDescription) 
        { 
            Debug.Assert(service != null, "service != null");
            Debug.Assert(service.OperationContext != null, "service.OperationContext != null"); 

            // Check that the request/payload version is understood.
            string versionText = service.OperationContext.Host.RequestVersion;
            if (!String.IsNullOrEmpty(versionText)) 
            {
                KeyValuePair version; 
                if (!HttpProcessUtility.TryReadVersion(versionText, out version)) 
                {
                    throw DataServiceException.CreateBadRequestError( 
                        Strings.DataService_VersionCannotBeParsed(versionText));
                }

                // For both Batch and Non-Batch requests we need to verify that the request DSV 
                // is a known version number.
                if (!RequestDescription.IsKnownRequestVersion(version.Key)) 
                { 
                    // Resource strings are already frozen, we can't add new ones...  Hijacking an existing one to make it look close.
                    // The error message will look like: 
                    // "Request version '99.99' is not supported for the request payload. The only supported version is '1.0' or '2.0'."
                    // For non-english loc the error will have the english word 'or' which is bad, but this gives more detailed info
                    // than a generic error message.
                    string message = Strings.DataService_VersionNotSupported(version.Key.ToString(2), "1", "0' or '2.0"); 
                    throw DataServiceException.CreateBadRequestError(message);
                } 
 
                // For non-batch requests we also need to verify we meet the minimum request requirement.
                if (requestDescription != null) 
                {
                    if (version.Key < requestDescription.RequireMinimumVersion)
                    {
                        string message = Strings.DataService_VersionNotSupported( 
                            version.Key.ToString(2),
                            requestDescription.RequireMinimumVersion.Major, 
                            requestDescription.RequireMinimumVersion.Minor); 
                        throw DataServiceException.CreateBadRequestError(message);
                    } 
                }
            }

            // Check that the maximum version for the client will understand our response. 
            versionText = service.OperationContext.Host.RequestMaxVersion;
            if (!String.IsNullOrEmpty(versionText)) 
            { 
                KeyValuePair version;
                if (!HttpProcessUtility.TryReadVersion(versionText, out version)) 
                {
                    throw DataServiceException.CreateBadRequestError(
                        Strings.DataService_VersionCannotBeParsed(versionText));
                } 

                if (requestDescription != null) 
                { 
                    if (version.Key < requestDescription.ResponseVersion)
                    { 
                        string message = Strings.DataService_VersionTooLow(
                            version.Key.ToString(2),
                            requestDescription.ResponseVersion.Major,
                            requestDescription.ResponseVersion.Minor); 
                        throw DataServiceException.CreateBadRequestError(message);
                    } 
                } 
                else
                { 
                    // For batch requests we also need to make sure the MDSV is at least 1.0. This was the V1 behavior.
                    if (version.Key < RequestDescription.DataServiceDefaultResponseVersion)
                    {
                        string message = Strings.DataService_VersionTooLow( 
                            version.Key.ToString(2),
                            RequestDescription.DataServiceDefaultResponseVersion.Major, 
                            RequestDescription.DataServiceDefaultResponseVersion.Minor); 
                        throw DataServiceException.CreateBadRequestError(message);
                    } 
                }
            }
        }
 
        /// 
        /// Tests if the mime type text from a request header is application/atom+xml 
        ///  
        /// mime type text
        /// returns true if the mime type text is application/atom+xml 
        internal static bool IsAtomMimeType(string mimeTypeText)
        {
            string mime = HttpProcessUtility.SelectMimeType(mimeTypeText, new string[] { XmlConstants.MimeApplicationAtom });
            return WebUtil.CompareMimeType(mime, XmlConstants.MimeApplicationAtom); 
        }
 
        /// Gets the host and port parts of a Host header if they are both present. 
        /// Host header value (non-null).
        /// Scheme for the host and port values. 
        /// If the result is true, the host part of the header.
        /// If the result is false, the port part of the header.
        /// true if the header has a host and port part, false otherwise.
        private static bool GetHostAndPort(string hostHeader, string scheme, out string host, out int port) 
        {
            Debug.Assert(hostHeader != null, "hostHeader != null"); 
 
            if (scheme != null && !scheme.EndsWith("://", StringComparison.Ordinal))
            { 
                scheme += "://";
            }

            Uri result; 
            if (Uri.TryCreate(scheme + hostHeader, UriKind.Absolute, out result))
            { 
                host = result.Host; 
                port = result.Port;
                return true; 
            }
            else
            {
                host = null; 
                port = default(int);
                return false; 
            } 
        }
 
        /// Checks whether the specifies string is null or blank.
        /// Text to check.
        /// true if text is null, empty, or all whitespace characters.
        private static bool IsWhitespace(string text) 
        {
            if (text == null) 
            { 
                return true;
            } 
            else
            {
                foreach (char c in text)
                { 
                    if (!Char.IsWhiteSpace(c))
                    { 
                        return false; 
                    }
                } 

                return true;
            }
        } 

        /// Writes an xml:space='preserve' attribute to the specified writer. 
        /// XmlWriter to write to. 
        private static void WriteSpacePreserveAttribute(XmlWriter writer)
        { 
            Debug.Assert(writer != null, "writer != null");
            writer.WriteAttributeString(
                XmlConstants.XmlNamespacePrefix,        // prefix
                XmlConstants.XmlSpaceAttributeName,     // localName 
                null,                                   // ns
                XmlConstants.XmlSpacePreserveValue);    // value 
        } 

        ///  
        /// Represents a pair of Expanded wrapper with the index in  the array
        /// The only reason to create this class is to avoid CA908 for KeyValuePairs
        /// 
        private sealed class ExpandWrapperTypeWithIndex 
        {
            /// Type 
            internal Type Type 
            {
                get; 
                set;
            }

            /// Index 
            internal int Index
            { 
                get; 
                set;
            } 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK