HttpContextServiceHost.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 / HttpContextServiceHost.cs / 1305376 / HttpContextServiceHost.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides an HttpContext-based implementation.
//  
// 
// @owner  [....]
//--------------------------------------------------------------------- 

namespace System.Data.Services
{
    #region Namespaces. 

    using System; 
    using System.Collections.Generic; 
    using System.Diagnostics;
    using System.IO; 
    using System.Net;
    using System.ServiceModel;
    using System.ServiceModel.Web;
 
    #endregion Namespaces.
 
    ///  
    /// Provides access to the environment for a DataService, including information about the current request, based
    /// on the current WebOperationContext. 
    /// 
    internal class HttpContextServiceHost : IDataServiceHost2
    {
        #region Private fields. 

        /// Message sent to server. 
        private readonly Stream incomingMessageBody; 

        /// The WCF-based operation context. 
        private readonly WebOperationContext operationContext;

        /// Whether an error was found when processing this request.
        private bool errorFound; 

        /// Gets the absolute URI to the resource upon which to apply the request. 
        private Uri absoluteRequestUri; 

        /// Gets the absolute URI to the service. 
        private Uri absoluteServiceUri;

        #endregion Private fields.
 
        #region Constructors.
 
        ///  
        /// Initializes a new System.Data.Services.HttpContextServiceHost instance.
        ///  
        /// Incoming message body to process.
        internal HttpContextServiceHost(Stream messageBody)
        {
            // We capture the current context at initialization time rather 
            // than accessing it repeatedly.
            this.incomingMessageBody = messageBody; 
            this.operationContext = WebOperationContext.Current; 
            if (this.operationContext == null)
            { 
                throw new InvalidOperationException(Strings.HttpContextServiceHost_WebOperationContextCurrentMissing);
            }
        }
 
        #endregion Constructors.
 
        #region Properties. 

        ///  
        /// Gets the character set encoding that the client requested,
        /// possibly null.
        /// 
        string IDataServiceHost.RequestAcceptCharSet 
        {
            get 
            { 
                // Returns a string that contains the comma-separated list of values
                // associated with the specified key, if found; otherwise, null. 
                return this.operationContext.IncomingRequest.Headers[HttpRequestHeader.AcceptCharset];
            }
        }
 
        /// Gets or sets the HTTP MIME type of the output stream.
        string IDataServiceHost.ResponseContentType 
        { 
            get
            { 
                return this.operationContext.OutgoingResponse.ContentType;
            }

            set 
            {
                this.operationContext.OutgoingResponse.ContentType = value; 
            } 
        }
 
        /// Gets the HTTP MIME type of the input stream.
        string IDataServiceHost.RequestContentType
        {
            get 
            {
                return this.operationContext.IncomingRequest.ContentType; 
            } 
        }
 
        /// 
        /// Gets a comma-separated list of client-supported MIME Accept types.
        /// 
        string IDataServiceHost.RequestAccept 
        {
            get 
            { 
                return this.operationContext.IncomingRequest.Accept;
            } 
        }

        /// 
        /// Gets the HTTP data transfer method (such as GET, POST, or HEAD) used by the client. 
        /// 
        string IDataServiceHost.RequestHttpMethod 
        { 
            get
            { 
                string result;
                string[] methodValues = this.operationContext.IncomingRequest.Headers.GetValues(XmlConstants.HttpXMethod);
                if (methodValues == null || methodValues.Length == 0)
                { 
                    result = this.operationContext.IncomingRequest.Method;
                } 
                else if (methodValues.Length == 1) 
                {
                    result = methodValues[0]; 
                    if (this.operationContext.IncomingRequest.Method != XmlConstants.HttpMethodPost)
                    {
                        throw DataServiceException.CreateBadRequestError(Strings.HttpContextServiceHost_XMethodNotUsingPost);
                    } 

                    if (result != XmlConstants.HttpMethodDelete && result != XmlConstants.HttpMethodPut && result != XmlConstants.HttpMethodMerge) 
                    { 
                        throw DataServiceException.CreateBadRequestError(Strings.HttpContextServiceHost_XMethodIncorrectValue(result));
                    } 
                }
                else
                {
                    throw DataServiceException.CreateBadRequestError(Strings.HttpContextServiceHost_XMethodIncorrectCount(methodValues.Length)); 
                }
 
                return result; 
            }
        } 

        /// Gets the value of the If-Match header from the request made
        string IDataServiceHost.RequestIfMatch
        { 
            get
            { 
                return this.operationContext.IncomingRequest.Headers[HttpRequestHeader.IfMatch]; 
            }
        } 

        /// Gets the value of the If-None-Match header from the request made
        string IDataServiceHost.RequestIfNoneMatch
        { 
            get
            { 
                return this.operationContext.IncomingRequest.Headers[HttpRequestHeader.IfNoneMatch]; 
            }
        } 

        /// Gets the value for the MaxDataServiceVersion request header.
        string IDataServiceHost.RequestMaxVersion
        { 
            get
            { 
                return this.operationContext.IncomingRequest.Headers[XmlConstants.HttpMaxDataServiceVersion]; 
            }
        } 

        /// Gets the value for the DataServiceVersion request header.
        string IDataServiceHost.RequestVersion
        { 
            get
            { 
                return this.operationContext.IncomingRequest.Headers[XmlConstants.HttpDataServiceVersion]; 
            }
        } 

        /// Gets the absolute URI to the resource upon which to apply the request.
        Uri IDataServiceHost.AbsoluteRequestUri
        { 
            get
            { 
                if (this.absoluteRequestUri == null) 
                {
                    object property; 
                    if (OperationContext.Current.IncomingMessageProperties.TryGetValue(XmlConstants.MicrosoftDataServicesRequestUri, out property))
                    {
                        this.absoluteRequestUri = property as Uri;
                        if (this.absoluteRequestUri == null) 
                        {
                            throw new InvalidOperationException(Strings.HttpContextServiceHost_IncomingMessagePropertyMustBeValidUriInstance(XmlConstants.MicrosoftDataServicesRequestUri)); 
                        } 
                    }
 
                    if (this.absoluteRequestUri == null)
                    {
                        UriTemplateMatch match = this.operationContext.IncomingRequest.UriTemplateMatch;
                        this.absoluteRequestUri = WebUtil.ApplyHostHeader(match.RequestUri, this.HostHeader); 
                    }
                } 
 
                return this.absoluteRequestUri;
            } 
        }

        /// Gets or sets the Cache-Control header on the response.
        string IDataServiceHost.ResponseCacheControl 
        {
            get { return this.operationContext.OutgoingResponse.Headers[HttpResponseHeader.CacheControl]; } 
            set { this.operationContext.OutgoingResponse.Headers[HttpResponseHeader.CacheControl] = value; } 
        }
 
        /// Gets/Sets the value of the ETag header on the outgoing response
        string IDataServiceHost.ResponseETag
        {
            get 
            {
                return this.operationContext.OutgoingResponse.ETag; 
            } 

            set 
            {
                this.operationContext.OutgoingResponse.ETag = value;
            }
        } 

        /// Gets or sets the Location header on the response. 
        string IDataServiceHost.ResponseLocation 
        {
            get { return this.operationContext.OutgoingResponse.Headers[HttpResponseHeader.Location]; } 
            set { this.operationContext.OutgoingResponse.Headers[HttpResponseHeader.Location] = value; }
        }

        ///  
        /// Gets/Sets the status code for the request made.
        ///  
        int IDataServiceHost.ResponseStatusCode 
        {
            get 
            {
                return (int) this.operationContext.OutgoingResponse.StatusCode;
            }
 
            set
            { 
                HttpStatusCode statusCode = (HttpStatusCode)value; 
                this.operationContext.OutgoingResponse.StatusCode = statusCode;
 
                // Some status codes such as NoContent or NotModified MUST NOT include a message-body in the response.
                // We need to set SupressEntityBody to true so that in the case of chuncked encoding WCF won't write
                // a '0' in the message body to indicate there is no more content.
                // Note that not setting this will result in a HTTP Protocol Violation exception when chuncked encoding is on. 
                this.operationContext.OutgoingResponse.SuppressEntityBody = MustNotReturnMessageBody(statusCode);
            } 
        } 

        ///  
        /// Gets the  to be written to send a response
        /// to the client.
        /// 
        Stream IDataServiceHost.ResponseStream 
        {
            get 
            { 
                // The ResponseStream is not directly accessible - this would
                // prevent WCF from streaming results back. For the WCF host, 
                // a Message subclass should write directly in the OnBodyWrite
                // method.
                throw Error.NotSupported();
            } 
        }
 
        /// Gets or sets the value for the DataServiceVersion response header. 
        string IDataServiceHost.ResponseVersion
        { 
            get { return this.operationContext.OutgoingResponse.Headers[XmlConstants.HttpDataServiceVersion]; }
            set { this.operationContext.OutgoingResponse.Headers[XmlConstants.HttpDataServiceVersion] = value; }
        }
 
        /// Gets the absolute URI to the service.
        Uri IDataServiceHost.AbsoluteServiceUri 
        { 
            get
            { 
                if (this.absoluteServiceUri == null)
                {
                    object property;
                    if (OperationContext.Current.IncomingMessageProperties.TryGetValue(XmlConstants.MicrosoftDataServicesRootUri, out property)) 
                    {
                        this.absoluteServiceUri = property as Uri; 
                        if (this.absoluteServiceUri == null) 
                        {
                            throw new InvalidOperationException(Strings.HttpContextServiceHost_IncomingMessagePropertyMustBeValidUriInstance(XmlConstants.MicrosoftDataServicesRootUri)); 
                        }
                    }

                    if (this.absoluteServiceUri == null) 
                    {
                        UriTemplateMatch match = this.operationContext.IncomingRequest.UriTemplateMatch; 
 
                        // We never want to consider the last segment of the base URI a 'document' type
                        // of segment to be replaced, ie, http://foo/svc.svc should never remove svc.svc 
                        // from the path.
                        this.absoluteServiceUri = WebUtil.ApplyHostHeader(match.BaseUri, this.HostHeader);
                    }
 
                    if (!String.IsNullOrEmpty(this.absoluteServiceUri.Fragment))
                    { 
                        throw new InvalidOperationException(Strings.HttpContextServiceHost_IncomingTemplateMatchFragment(this.absoluteServiceUri)); 
                    }
 
                    if (!String.IsNullOrEmpty(this.absoluteServiceUri.Query))
                    {
                        throw new InvalidOperationException(Strings.HttpContextServiceHost_IncomingTemplateMatchQuery(this.absoluteServiceUri));
                    } 

                    this.absoluteServiceUri = WebUtil.EnsureLastSegmentEmpty(this.absoluteServiceUri); 
                } 

                return this.absoluteServiceUri; 
            }
        }

        ///  
        /// Gets the  from which the request data can be read from
        /// to the client. 
        ///  
        Stream IDataServiceHost.RequestStream
        { 
            [DebuggerStepThrough]
            get { return this.incomingMessageBody; }
        }
 
        #region IDataServiceHost2 Properties
 
        /// Dictionary of all request headers from the host. 
        WebHeaderCollection IDataServiceHost2.RequestHeaders
        { 
            [DebuggerStepThrough]
            get { return this.operationContext.IncomingRequest.Headers; }
        }
 
        /// Enumerates all response headers that has been set.
        WebHeaderCollection IDataServiceHost2.ResponseHeaders 
        { 
            [DebuggerStepThrough]
            get { return this.operationContext.OutgoingResponse.Headers; } 
        }

        #endregion IDataServiceHost2 Properties
 
        /// Whether an error was found when processing this request.
        internal bool ErrorFound 
        { 
            get { return this.errorFound; }
        } 

        /// The value for the Host header in the request, possibly null.
        private string HostHeader
        { 
            get { return this.operationContext.IncomingRequest.Headers[HttpRequestHeader.Host]; }
        } 
 
        #endregion Properties.
 
        #region Methods.

        /// Gets the value for the specified item in the request query string.
        /// Item to return. 
        /// 
        /// The value for the specified item in the request query string; 
        /// null if  is not found. 
        /// 
        string IDataServiceHost.GetQueryStringItem(string item) 
        {
            Debug.Assert(item != null, "item != null");
            Debug.Assert(item.Trim() == item, "item.Trim() == item - otherwise, there are leading/trailing spaces in the name");
 
            System.Collections.Specialized.NameValueCollection collection = this.operationContext.IncomingRequest.UriTemplateMatch.QueryParameters;
            string[] values = collection.GetValues(item); 
            if (values == null || values.Length == 0) 
            {
                // Do a scan of arguments ignoring whitespace (SQLBUDT #555944). 
                string keyFound = null;
                foreach (string key in collection.Keys)
                {
                    if (key != null && StringComparer.OrdinalIgnoreCase.Equals(key.Trim(), item)) 
                    {
                        if (keyFound != null) 
                        { 
                            throw DataServiceException.CreateBadRequestError(Strings.HttpContextServiceHost_AmbiguousItemName(item, keyFound, key));
                        } 

                        keyFound = key;
                        values = collection.GetValues(key);
                    } 
                }
 
                if (values == null || values.Length == 0) 
                {
                    return null; 
                }
            }

            Debug.Assert(values != null && values.Length > 0, "values != null && values.Length > 0 - otherwise we should have returned already"); 
            if (values.Length == 1)
            { 
                return values[0]; 
            }
            else 
            {
                throw DataServiceException.CreateSyntaxError();
            }
        } 

        ///  
        /// Method to handle a data service exception during processing. 
        /// 
        /// Exception handling description. 
        void IDataServiceHost.ProcessException(HandleExceptionArgs args)
        {
            Debug.Assert(this.operationContext != null, "this.operationContext != null");
            this.errorFound = true; 
            if (!args.ResponseWritten)
            { 
                ((IDataServiceHost)this).ResponseStatusCode = args.ResponseStatusCode; 
                ((IDataServiceHost)this).ResponseContentType = args.ResponseContentType;
                if (args.ResponseAllowHeader != null) 
                {
                    this.operationContext.OutgoingResponse.Headers[HttpResponseHeader.Allow] = args.ResponseAllowHeader;
                }
            } 
        }
 
        /// Verifies that query parameters are valid. 
        internal void VerifyQueryParameters()
        { 
            HashSet namesFound = new HashSet(StringComparer.Ordinal);
            System.Collections.Specialized.NameValueCollection collection = this.operationContext.IncomingRequest.UriTemplateMatch.QueryParameters;
            for (int i = 0; i < collection.Count; i++)
            { 
                string name = collection.GetKey(i);
                if (name == null) 
                { 
                    // These are values of the form a&b&c, without '='. We just make sure they aren't system
                    // values at all. 
                    string[] values = collection.GetValues(i);
                    if (values != null)
                    {
                        for (int j = 0; j < values.Length; j++) 
                        {
                            string value = values[j].Trim(); 
                            if (value.Length > 0 && value[0] == '$') 
                            {
                                throw DataServiceException.CreateBadRequestError( 
                                    Strings.HttpContextServiceHost_QueryParameterMustBeSpecifiedOnce(value));
                            }
                        }
                    } 

                    continue; 
                } 

                name = name.Trim(); 
                if (!namesFound.Add(name))
                {
                    throw DataServiceException.CreateBadRequestError(
                        Strings.HttpContextServiceHost_QueryParameterMustBeSpecifiedOnce(name)); 
                }
 
                if (name.Length > 0 && name[0] == '$') 
                {
                    if (name != XmlConstants.HttpQueryStringExpand && 
                        name != XmlConstants.HttpQueryStringFilter &&
                        name != XmlConstants.HttpQueryStringOrderBy &&
                        name != XmlConstants.HttpQueryStringSkip &&
                        name != XmlConstants.HttpQueryStringSkipToken && 
                        name != XmlConstants.HttpQueryStringInlineCount &&
                        name != XmlConstants.HttpQueryStringTop && 
                        name != XmlConstants.HttpQueryStringSelect) 
                    {
                        throw DataServiceException.CreateBadRequestError( 
                            Strings.HttpContextServiceHost_UnknownQueryParameter(name));
                    }

                    string[] values = collection.GetValues(i); 
                    if (values == null || values.Length != 1)
                    { 
                        throw DataServiceException.CreateBadRequestError( 
                            Strings.HttpContextServiceHost_QueryParameterMustBeSpecifiedOnce(name));
                    } 
                }
            }
        }
 
        /// 
        /// Check to see if the given status code expects an empty message-body. 
        ///  
        /// Http status code
        /// True if the message-body must be empty for the given status code, false otherwise. 
        private static bool MustNotReturnMessageBody(HttpStatusCode statusCode)
        {
            // Both 204 and 304 must not include a message-body in the response.
            switch (statusCode) 
            {
                case HttpStatusCode.NoContent:    // 204 
                case HttpStatusCode.ResetContent: // 205 
                case HttpStatusCode.NotModified:  // 304
                    return true; 

                default:
                    return false;
            } 
        }
 
        #endregion Methods. 
    }
} 

// 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