WebServiceHost.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 / cdf / src / NetFx35 / System.ServiceModel.Web / System / ServiceModel / Web / WebServiceHost.cs / 1477467 / WebServiceHost.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------

namespace System.ServiceModel.Web 
{
    using System.Collections.Generic; 
    using System.IO; 
    using System.Net;
    using System.Runtime; 
    using System.ServiceModel;
    using System.ServiceModel.Activation;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Configuration; 
    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher; 
 
    public class WebServiceHost : ServiceHost
    { 
        static readonly Type WebHttpBindingType = typeof(WebHttpBinding);
        static readonly string WebHttpEndpointKind = "webHttpEndpoint";

        public WebServiceHost() 
            : base()
        { 
        } 

        public WebServiceHost(object singletonInstance, params Uri[] baseAddresses) 
            : base(singletonInstance, baseAddresses)
        {
        }
 
        public WebServiceHost(Type serviceType, params Uri[] baseAddresses) :
            base(serviceType, baseAddresses) 
        { 
        }
 
        // This method adds automatic endpoints at the base addresses, 1 per site binding (http or https). It only configures
        // the security on the binding. It does not add any behaviors.
        // If there are no base addresses or endpoints have been configured explicitly at the base address it does not add any
        // automatic endpoints. 
        // If it adds automatic endpoints, it validates that the service implements a single contract
        internal static void AddAutomaticWebHttpBindingEndpoints(ServiceHost host, IDictionary implementedContracts,  string multipleContractsErrorMessage, string standardEndpointKind) 
        { 
            AuthenticationSchemes supportedSchemes = AuthenticationSchemes.None;
            if (host.BaseAddresses.Count > 0) 
            {
                supportedSchemes = AspNetEnvironment.Current.GetAuthenticationSchemes(host.BaseAddresses[0]);
            }
            Type contractType = null; 
            // add an endpoint with the contract at each base address
            foreach (Uri baseAddress in host.BaseAddresses) 
            { 
                string uriScheme = baseAddress.Scheme;
 
                // HTTP and HTTPs are only supported schemes
                if (Object.ReferenceEquals(uriScheme, Uri.UriSchemeHttp) || Object.ReferenceEquals(uriScheme, Uri.UriSchemeHttps))
                {
                    // bypass adding the automatic endpoint if there's already one at the base address 
                    bool isExplicitEndpointConfigured = false;
                    foreach (ServiceEndpoint endpoint in host.Description.Endpoints) 
                    { 
                        if (endpoint.Address != null && EndpointAddress.UriEquals(endpoint.Address.Uri, baseAddress, true, false))
                        { 
                            isExplicitEndpointConfigured = true;
                            break;
                        }
                    } 
                    if (isExplicitEndpointConfigured)
                    { 
                        continue; 
                    }
                    if (contractType == null) 
                    {
                        if (implementedContracts.Count != 1)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(multipleContractsErrorMessage)); 
                        }
                        foreach (ContractDescription contract in implementedContracts.Values) 
                        { 
                            contractType = contract.ContractType;
                            break; 
                        }
                    }

                    // Get the default web endpoint 
                    ConfigLoader configLoader = new ConfigLoader(host.GetContractResolver(implementedContracts));
                    ServiceEndpointElement serviceEndpointElement = new ServiceEndpointElement(); 
                    serviceEndpointElement.Contract = contractType.FullName; 
                    // Check for a protocol mapping
                    ProtocolMappingItem protocolMappingItem = ConfigLoader.LookupProtocolMapping(baseAddress.Scheme); 
                    if (protocolMappingItem != null &&
                        string.Equals(protocolMappingItem.Binding, WebHttpBinding.WebHttpBindingConfigurationStrings.WebHttpBindingCollectionElementName, StringComparison.Ordinal))
                    {
                        serviceEndpointElement.BindingConfiguration = protocolMappingItem.BindingConfiguration; 
                    }
                    serviceEndpointElement.Kind = standardEndpointKind; 
 
                    // LookupEndpoint will not set the Endpoint address and listenUri
                    // because omitSettingEndpointAddress is set to true. 
                    // We will set them after setting the binding security
                    ServiceEndpoint automaticEndpoint = configLoader.LookupEndpoint(serviceEndpointElement, null, host, host.Description, true /*omitSettingEndpointAddress*/);
                    WebHttpBinding binding = automaticEndpoint.Binding as WebHttpBinding;
 
                    bool automaticallyConfigureSecurity = !binding.Security.IsModeSet;
                    if (automaticallyConfigureSecurity) 
                    { 
                        if (Object.ReferenceEquals(uriScheme, Uri.UriSchemeHttps))
                        { 
                            binding.Security.Mode = WebHttpSecurityMode.Transport;
                        }
                        else if (supportedSchemes != AuthenticationSchemes.None && supportedSchemes != AuthenticationSchemes.Anonymous)
                        { 
                            binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly;
                        } 
                        else 
                        {
                            binding.Security.Mode = WebHttpSecurityMode.None; 
                        }
                    }

                    if (automaticallyConfigureSecurity && AspNetEnvironment.Enabled) 
                    {
                        SetBindingCredentialBasedOnHostedEnvironment(automaticEndpoint, supportedSchemes); 
                    } 

                    // Setting the Endpoint address and listenUri now that we've set the binding security 
                    ConfigLoader.ConfigureEndpointAddress(serviceEndpointElement, host, automaticEndpoint);
                    ConfigLoader.ConfigureEndpointListenUri(serviceEndpointElement, host, automaticEndpoint);

                    host.AddServiceEndpoint(automaticEndpoint); 
                }
            } 
        } 

        internal static void SetRawContentTypeMapperIfNecessary(ServiceEndpoint endpoint, bool isDispatch) 
        {
            Binding binding = endpoint.Binding;
            ContractDescription contract = endpoint.Contract;
            if (binding == null) 
            {
                return; 
            } 
            CustomBinding customBinding = new CustomBinding(binding);
            BindingElementCollection bec = customBinding.Elements; 
            WebMessageEncodingBindingElement encodingElement = bec.Find();
            if (encodingElement == null || encodingElement.ContentTypeMapper != null)
            {
                return; 
            }
            bool areAllOperationsRawMapperCompatible = true; 
            int numStreamOperations = 0; 
            foreach (OperationDescription operation in contract.Operations)
            { 
                bool isCompatible = (isDispatch) ? IsRawContentMapperCompatibleDispatchOperation(operation, ref numStreamOperations) : IsRawContentMapperCompatibleClientOperation(operation, ref numStreamOperations);
                if (!isCompatible)
                {
                    areAllOperationsRawMapperCompatible = false; 
                    break;
                } 
            } 
            if (areAllOperationsRawMapperCompatible && numStreamOperations > 0)
            { 
                encodingElement.ContentTypeMapper = RawContentTypeMapper.Instance;
                endpoint.Binding = customBinding;
            }
        } 

        protected override void OnOpening() 
        { 
            if (this.Description == null)
            { 
                return;
            }

            // disable other things that listen for GET at base address and may conflict with auto-endpoints 
            ServiceDebugBehavior sdb = this.Description.Behaviors.Find();
            if (sdb != null) 
            { 
                sdb.HttpHelpPageEnabled = false;
                sdb.HttpsHelpPageEnabled = false; 
            }
            ServiceMetadataBehavior smb = this.Description.Behaviors.Find();
            if (smb != null)
            { 
                smb.HttpGetEnabled = false;
                smb.HttpsGetEnabled = false; 
            } 

            AddAutomaticWebHttpBindingEndpoints(this, this.ImplementedContracts, SR2.GetString(SR2.HttpTransferServiceHostMultipleContracts, this.Description.Name), WebHttpEndpointKind); 

            // for both user-defined and automatic endpoints, ensure they have the right behavior and content type mapper added
            foreach (ServiceEndpoint serviceEndpoint in this.Description.Endpoints)
            { 
                if (serviceEndpoint.Binding != null && serviceEndpoint.Binding.CreateBindingElements().Find() != null)
                { 
                    SetRawContentTypeMapperIfNecessary(serviceEndpoint, true); 
                    if (serviceEndpoint.Behaviors.Find() == null)
                    { 
                        ConfigLoader.LoadDefaultEndpointBehaviors(serviceEndpoint);
                        if (serviceEndpoint.Behaviors.Find() == null)
                        {
                            serviceEndpoint.Behaviors.Add(new WebHttpBehavior()); 
                        }
                    } 
                } 
            }
 
            base.OnOpening();
        }

        static bool IsRawContentMapperCompatibleClientOperation(OperationDescription operation, ref int numStreamOperations) 
        {
            // An operation is raw encoder compatible on the client side iff the response is a Stream or void 
            // The request is driven by the format property on the message and not by the content type 
            if (operation.Messages.Count > 1 & !IsResponseStreamOrVoid(operation, ref numStreamOperations))
            { 
                return false;
            }
            return true;
 
        }
 
        static bool IsRawContentMapperCompatibleDispatchOperation(OperationDescription operation, ref int numStreamOperations) 
        {
            // An operation is raw encoder compatible on the dispatch side iff the request body is a Stream or void 
            // The response is driven by the format property on the message and not by the content type
            UriTemplateDispatchFormatter throwAway = new UriTemplateDispatchFormatter(operation, null, new QueryStringConverter(), operation.DeclaringContract.Name, new Uri("http://localhost"));
            int numUriVariables = throwAway.pathMapping.Count + throwAway.queryMapping.Count;
            bool isRequestCompatible = false; 
            if (numUriVariables > 0)
            { 
                // we need the local variable tmp because ref parameters are not allowed to be passed into 
                // anonymous methods by the compiler.
                int tmp = 0; 
                WebHttpBehavior.HideRequestUriTemplateParameters(operation, throwAway, delegate()
                {
                    isRequestCompatible = IsRequestStreamOrVoid(operation, ref tmp);
                }); 
                numStreamOperations += tmp;
            } 
            else 
            {
                isRequestCompatible = IsRequestStreamOrVoid(operation, ref numStreamOperations); 
            }
            return isRequestCompatible;
        }
 
        static bool IsRequestStreamOrVoid(OperationDescription operation, ref int numStreamOperations)
        { 
            MessageDescription message = operation.Messages[0]; 
            if (WebHttpBehavior.IsTypedMessage(message) || WebHttpBehavior.IsUntypedMessage(message))
            { 
                return false;
            }
            if (message.Body.Parts.Count == 0)
            { 
                return true;
            } 
            else if (message.Body.Parts.Count == 1) 
            {
                if (IsStreamPart(message.Body.Parts[0].Type)) 
                {
                    ++numStreamOperations;
                    return true;
                } 
                else if (IsVoidPart(message.Body.Parts[0].Type))
                { 
                    return true; 
                }
            } 
            return false;
        }

        static bool IsResponseStreamOrVoid(OperationDescription operation, ref int numStreamOperations) 
        {
            if (operation.Messages.Count < 1) 
            { 
                return true;
            } 
            MessageDescription message = operation.Messages[1];
            if (WebHttpBehavior.IsTypedMessage(message) || WebHttpBehavior.IsUntypedMessage(message))
            {
                return false; 
            }
            if (message.Body.Parts.Count == 0) 
            { 
                if (message.Body.ReturnValue == null || IsVoidPart(message.Body.ReturnValue.Type))
                { 
                    return true;
                }
                else if (IsStreamPart(message.Body.ReturnValue.Type))
                { 
                    ++numStreamOperations;
                    return true; 
                } 
            }
            return false; 
        }

        static bool IsStreamPart(Type type)
        { 
            return (type == typeof(Stream));
        } 
 
        static bool IsVoidPart(Type type)
        { 
            return (type == null || type == typeof(void));
        }

        // For automatic endpoints, in the hosted case we configure a credential type based on the vdir settings. 
        // For IIS, in IntegratedWindowsAuth mode we pick Negotiate.
        static void SetBindingCredentialBasedOnHostedEnvironment(ServiceEndpoint serviceEndpoint, AuthenticationSchemes supportedSchemes) 
        { 
            WebHttpBinding whb = serviceEndpoint.Binding as WebHttpBinding;
            Fx.Assert(whb != null, "Automatic endpoint must be WebHttpBinding"); 

            switch (supportedSchemes)
            {
                case AuthenticationSchemes.Digest: 
                    whb.Security.Transport.ClientCredentialType = HttpClientCredentialType.Digest;
                    break; 
                case AuthenticationSchemes.IntegratedWindowsAuthentication: 
                // fall through to Negotiate
                case AuthenticationSchemes.Negotiate: 
                    whb.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
                    break;
                case AuthenticationSchemes.Ntlm:
                    whb.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm; 
                    break;
                case AuthenticationSchemes.Basic: 
                    whb.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic; 
                    break;
                case AuthenticationSchemes.Anonymous: 
                    whb.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
                    break;
                default:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR2.GetString( 
                        SR2.HttpTransferServiceHostBadAuthSchemes, supportedSchemes)));
            } 
 
        }
    } 
}

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