WebServiceHost.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / NetFx35 / System.ServiceModel.Web / System / ServiceModel / Web / WebServiceHost.cs / 3 / WebServiceHost.cs

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

namespace System.ServiceModel.Web 
{
    using System.IO; 
    using System.Collections.Generic; 
    using System.ServiceModel;
    using System.ServiceModel.Activation; 
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.Diagnostics.CodeAnalysis;
    using System.Configuration; 
    using System.Net;
    using System.Web.Hosting; 
    using System.Web; 
    using System.Globalization;
    using System.ServiceModel.Dispatcher; 
    using System.Web.Configuration;
    using System.Runtime.CompilerServices;

    public class WebServiceHost : ServiceHost 
    {
        static bool isAspNetAuthenticationModeDetermined; 
        static bool isWindowsAuthentication; 

        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)
        {
            AuthenticationSchemes supportedSchemes; 
            if (ServiceHostingEnvironment.IsHosted)
            { 
                supportedSchemes = GetAuthenticationSchemes(host.BaseAddresses[0]); 
            }
            else 
            {
                supportedSchemes = AuthenticationSchemes.None;
            }
            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;
                        } 
                    }
                    WebHttpBinding binding = new WebHttpBinding();
                    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; 
                    }
                    ServiceEndpoint automaticEndpoint = host.AddServiceEndpoint(contractType, binding, baseAddress); 
                    if (ServiceHostingEnvironment.IsHosted) 
                    {
                        SetBindingCredentialBasedOnHostedEnvironment(automaticEndpoint, supportedSchemes); 
                    }
                }
            }
        } 

        internal static AuthenticationSchemes GetAuthenticationSchemes(Uri baseAddress) 
        { 
            string fileName = VirtualPathUtility.GetFileName(baseAddress.AbsolutePath);
            string virtualPath = ServiceHostingEnvironment.CurrentVirtualPath; 
            string completePath;
            if (virtualPath != null && virtualPath.EndsWith("/", StringComparison.Ordinal))
            {
                completePath = virtualPath + fileName; 
            }
            else 
            { 
                completePath = String.Format(CultureInfo.InvariantCulture, "{0}/{1}", virtualPath, fileName);
            } 
            return HostedTransportConfigurationManager.MetabaseSettings.GetAuthenticationSchemes(completePath);
        }

        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()
        {
            base.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)); 
 
            // 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)
                    { 
                        serviceEndpoint.Behaviors.Add(new WebHttpBehavior()); 
                    }
                } 
            }
        }

        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));
        }

        [MethodImpl(MethodImplOptions.NoInlining)] 
        static bool IsWindowsAuthenticationConfigured()
        { 
            if (!isAspNetAuthenticationModeDetermined) 
            {
                AuthenticationSection authSection = (AuthenticationSection) WebConfigurationManager.GetSection("system.web/authentication"); 
                if (authSection != null)
                {
                    isWindowsAuthentication = (authSection.Mode == AuthenticationMode.Windows);
                } 
                isAspNetAuthenticationModeDetermined = true;
            } 
            return isWindowsAuthentication; 
        }
 

        // 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.
        // For Cassini, we alway pick Ntlm (Cassini always returns the supported schemes as Ntlm | Anonymous and the 
        // user cannot configure this.
        static void SetBindingCredentialBasedOnHostedEnvironment(ServiceEndpoint serviceEndpoint, AuthenticationSchemes supportedSchemes) 
        { 
            if (ServiceHostingEnvironment.IsSimpleApplicationHost)
            { 
                // Cassini always reports the auth scheme as anonymous or Ntlm. Map this to Ntlm, except when forms auth
                // is requested
                if (supportedSchemes == (AuthenticationSchemes.Anonymous | AuthenticationSchemes.Ntlm))
                { 
                    if (IsWindowsAuthenticationConfigured())
                    { 
                        supportedSchemes = AuthenticationSchemes.Ntlm; 
                    }
                    else 
                    {
                        supportedSchemes = AuthenticationSchemes.Anonymous;
                    }
                } 
            }
            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.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

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