File: System\ServiceModel\ServiceBehaviorAttribute.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.ServiceModel
{
    using System.ServiceModel.Administration;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Dispatcher;
    using System.ServiceModel.Description;
    using System.ServiceModel.Configuration;
    using System.Runtime.Serialization;
    using System.Collections.ObjectModel;
    using System.Collections.Generic;
    using System.Threading;
    using System.Transactions;
    using System.Runtime.CompilerServices;
    using System.ComponentModel;
    using System.Globalization;
 
    [AttributeUsage(ServiceModelAttributeTargets.ServiceBehavior)]
    public sealed class ServiceBehaviorAttribute : Attribute, IServiceBehavior
    {
        internal static IsolationLevel DefaultIsolationLevel = IsolationLevel.Unspecified;
        ConcurrencyMode concurrencyMode = ConcurrencyMode.Single;
        bool ensureOrderedDispatch = false;
        string configurationName;
        bool includeExceptionDetailInFaults = false;
        InstanceContextMode instanceMode;
        bool releaseServiceInstanceOnTransactionComplete = true;
        bool releaseServiceInstanceOnTransactionCompleteSet = false;
        bool transactionAutoCompleteOnSessionClose = false;
        bool transactionAutoCompleteOnSessionCloseSet = false;
        object wellKnownSingleton = null;  // if the user passes an object to the ServiceHost, it is stored here
        object hiddenSingleton = null;     // if the user passes a type to the ServiceHost, and instanceMode==Single, we store the instance here
        bool validateMustUnderstand = true;
        bool ignoreExtensionDataObject = DataContractSerializerDefaults.IgnoreExtensionDataObject;
        int maxItemsInObjectGraph = DataContractSerializerDefaults.MaxItemsInObjectGraph;
        IsolationLevel transactionIsolationLevel = DefaultIsolationLevel;
        bool isolationLevelSet = false;
        bool automaticSessionShutdown = true;
        IInstanceProvider instanceProvider = null;
        TimeSpan transactionTimeout = TimeSpan.Zero;
        string transactionTimeoutString;
        bool transactionTimeoutSet = false;
        bool useSynchronizationContext = true;
        string serviceName = null;
        string serviceNamespace = null;
        AddressFilterMode addressFilterMode = AddressFilterMode.Exact;
 
        [DefaultValue(null)]
        public string Name
        {
            get { return serviceName; }
            set { serviceName = value; }
        }
 
        [DefaultValue(null)]
        public string Namespace
        {
            get { return serviceNamespace; }
            set { serviceNamespace = value; }
        }
 
        internal IInstanceProvider InstanceProvider
        {
            set { this.instanceProvider = value; }
        }
 
        [DefaultValue(AddressFilterMode.Exact)]
        public AddressFilterMode AddressFilterMode
        {
            get { return this.addressFilterMode; }
            set
            {
                if (!AddressFilterModeHelper.IsDefined(value))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
                }
 
                this.addressFilterMode = value;
            }
        }
 
        [DefaultValue(true)]
        public bool AutomaticSessionShutdown
        {
            get { return this.automaticSessionShutdown; }
            set { this.automaticSessionShutdown = value; }
        }
 
        [DefaultValue(null)]
        public string ConfigurationName
        {
            get { return this.configurationName; }
            set
            {
                if (value == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
                }
                if (value == string.Empty)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value",
                        SR.GetString(SR.SFxConfigurationNameCannotBeEmpty)));
                }
                this.configurationName = value;
            }
        }
 
        public IsolationLevel TransactionIsolationLevel
        {
            get { return this.transactionIsolationLevel; }
            set
            {
                switch (value)
                {
                    case IsolationLevel.Serializable:
                    case IsolationLevel.RepeatableRead:
                    case IsolationLevel.ReadCommitted:
                    case IsolationLevel.ReadUncommitted:
                    case IsolationLevel.Unspecified:
                    case IsolationLevel.Chaos:
                    case IsolationLevel.Snapshot:
                        break;
 
                    default:
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
                }
 
                this.transactionIsolationLevel = value;
                isolationLevelSet = true;
            }
        }
 
        public bool ShouldSerializeTransactionIsolationLevel()
        {
            return IsolationLevelSet;
        }
 
        internal bool IsolationLevelSet
        {
            get { return this.isolationLevelSet; }
        }
 
        [DefaultValue(false)]
        public bool IncludeExceptionDetailInFaults
        {
            get { return this.includeExceptionDetailInFaults; }
            set { this.includeExceptionDetailInFaults = value; }
        }
 
        [DefaultValue(ConcurrencyMode.Single)]
        public ConcurrencyMode ConcurrencyMode
        {
            get { return this.concurrencyMode; }
            set
            {
                if (!ConcurrencyModeHelper.IsDefined(value))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
                }
 
                this.concurrencyMode = value;
            }
        }
 
        [DefaultValue(false)]
        public bool EnsureOrderedDispatch
        {
            get { return this.ensureOrderedDispatch; }
            set { this.ensureOrderedDispatch = value; }
        }
 
        [DefaultValue(InstanceContextMode.PerSession)]
        public InstanceContextMode InstanceContextMode
        {
            get { return this.instanceMode; }
            set
            {
                if (!InstanceContextModeHelper.IsDefined(value))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
                }
 
                this.instanceMode = value;
            }
        }
 
        public bool ReleaseServiceInstanceOnTransactionComplete
        {
            get { return releaseServiceInstanceOnTransactionComplete; }
            set
            {
                this.releaseServiceInstanceOnTransactionComplete = value;
                this.releaseServiceInstanceOnTransactionCompleteSet = true;
            }
        }
 
        public bool ShouldSerializeConfigurationName()
        {
            return this.configurationName != null;
        }
 
        public bool ShouldSerializeReleaseServiceInstanceOnTransactionComplete()
        {
            return ReleaseServiceInstanceOnTransactionCompleteSet;
        }
 
        internal bool ReleaseServiceInstanceOnTransactionCompleteSet
        {
            get { return this.releaseServiceInstanceOnTransactionCompleteSet; }
        }
 
        public bool TransactionAutoCompleteOnSessionClose
        {
            get { return transactionAutoCompleteOnSessionClose; }
            set
            {
                this.transactionAutoCompleteOnSessionClose = value;
                this.transactionAutoCompleteOnSessionCloseSet = true;
            }
        }
 
        public bool ShouldSerializeTransactionAutoCompleteOnSessionClose()
        {
            return TransactionAutoCompleteOnSessionCloseSet;
        }
 
        internal bool TransactionAutoCompleteOnSessionCloseSet
        {
            get { return this.transactionAutoCompleteOnSessionCloseSet; }
        }
 
        public string TransactionTimeout
        {
            get { return transactionTimeoutString; }
            set
            {
                if (value == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value"));
                }
 
                try
                {
                    TimeSpan timeout = TimeSpan.Parse(value, CultureInfo.InvariantCulture);
 
                    if (timeout < TimeSpan.Zero)
                    {
                        string message = SR.GetString(SR.SFxTimeoutOutOfRange0);
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, message));
                    }
 
                    this.transactionTimeout = timeout;
                    this.transactionTimeoutString = value;
                    this.transactionTimeoutSet = true;
                }
                catch (FormatException e)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SFxTimeoutInvalidStringFormat), "value", e));
                }
                catch (OverflowException)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
                }
            }
        }
 
        public bool ShouldSerializeTransactionTimeout()
        {
            return TransactionTimeoutSet;
        }
 
        internal TimeSpan TransactionTimeoutTimespan
        {
            get { return this.transactionTimeout; }
        }
 
        internal bool TransactionTimeoutSet
        {
            get { return this.transactionTimeoutSet; }
        }
 
        [DefaultValue(true)]
        public bool ValidateMustUnderstand
        {
            get { return validateMustUnderstand; }
            set { validateMustUnderstand = value; }
        }
 
        [DefaultValue(DataContractSerializerDefaults.IgnoreExtensionDataObject)]
        public bool IgnoreExtensionDataObject
        {
            get { return ignoreExtensionDataObject; }
            set { ignoreExtensionDataObject = value; }
        }
 
        [DefaultValue(DataContractSerializerDefaults.MaxItemsInObjectGraph)]
        public int MaxItemsInObjectGraph
        {
            get { return maxItemsInObjectGraph; }
            set { maxItemsInObjectGraph = value; }
        }
 
        [DefaultValue(true)]
        public bool UseSynchronizationContext
        {
            get { return this.useSynchronizationContext; }
            set { this.useSynchronizationContext = value; }
        }
 
        public object GetWellKnownSingleton()
        {
            return this.wellKnownSingleton;
        }
 
        public void SetWellKnownSingleton(object value)
        {
            if (value == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
 
            this.wellKnownSingleton = value;
        }
 
        internal object GetHiddenSingleton()
        {
            return this.hiddenSingleton;
        }
 
        internal void SetHiddenSingleton(object value)
        {
            if (value == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
 
            this.hiddenSingleton = value;
        }
 
        [MethodImpl(MethodImplOptions.NoInlining)]
        void SetIsolationLevel(ChannelDispatcher channelDispatcher)
        {
            if (channelDispatcher == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("channelDispatcher");
 
            channelDispatcher.TransactionIsolationLevel = this.transactionIsolationLevel;
        }
 
        void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
            if (this.concurrencyMode != ConcurrencyMode.Single && this.ensureOrderedDispatch)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxNonConcurrentOrEnsureOrderedDispatch, description.Name)));
            }
        }
 
        void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
        {
        }
 
        void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
            for (int i = 0; i < serviceHostBase.ChannelDispatchers.Count; i++)
            {
                ChannelDispatcher channelDispatcher = serviceHostBase.ChannelDispatchers[i] as ChannelDispatcher;
                if (channelDispatcher != null)
                {
                    channelDispatcher.IncludeExceptionDetailInFaults = this.includeExceptionDetailInFaults;
 
                    if (channelDispatcher.HasApplicationEndpoints())
                    {
                        channelDispatcher.TransactionTimeout = transactionTimeout;
                        if (isolationLevelSet)
                            SetIsolationLevel(channelDispatcher);
 
                        foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
                        {
                            if (endpointDispatcher.IsSystemEndpoint)
                            {
                                continue;
                            }
                            DispatchRuntime behavior = endpointDispatcher.DispatchRuntime;
                            behavior.ConcurrencyMode = this.concurrencyMode;
                            behavior.EnsureOrderedDispatch = this.ensureOrderedDispatch;
                            behavior.ValidateMustUnderstand = validateMustUnderstand;
                            behavior.AutomaticInputSessionShutdown = this.automaticSessionShutdown;
                            behavior.TransactionAutoCompleteOnSessionClose = this.transactionAutoCompleteOnSessionClose;
                            behavior.ReleaseServiceInstanceOnTransactionComplete = this.releaseServiceInstanceOnTransactionComplete;
                            if (!this.useSynchronizationContext)
                            {
                                behavior.SynchronizationContext = null;
                            }
 
                            if (!endpointDispatcher.AddressFilterSetExplicit)
                            {
                                EndpointAddress address = endpointDispatcher.OriginalAddress;
                                if (address == null || this.AddressFilterMode == AddressFilterMode.Any)
                                {
                                    endpointDispatcher.AddressFilter = new MatchAllMessageFilter();
                                }
                                else if (this.AddressFilterMode == AddressFilterMode.Prefix)
                                {
                                    endpointDispatcher.AddressFilter = new PrefixEndpointAddressMessageFilter(address);
                                }
                                else if (this.AddressFilterMode == AddressFilterMode.Exact)
                                {
                                    endpointDispatcher.AddressFilter = new EndpointAddressMessageFilter(address);
                                }
                            }
                        }
                    }
#pragma warning suppress 56506
                }
            }
            DataContractSerializerServiceBehavior.ApplySerializationSettings(description, ignoreExtensionDataObject, maxItemsInObjectGraph);
            ApplyInstancing(description, serviceHostBase);
        }
 
        void ApplyInstancing(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
            Type serviceType = description.ServiceType;
            InstanceContext singleton = null;
 
            for (int i = 0; i < serviceHostBase.ChannelDispatchers.Count; i++)
            {
                ChannelDispatcher channelDispatcher = serviceHostBase.ChannelDispatchers[i] as ChannelDispatcher;
                if (channelDispatcher != null)
                {
                    foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
                    {
                        if (endpointDispatcher.IsSystemEndpoint)
                        {
                            continue;
                        }
                        DispatchRuntime dispatch = endpointDispatcher.DispatchRuntime;
                        if (dispatch.InstanceProvider == null)
                        {
                            if (instanceProvider == null)
                            {
                                if (serviceType == null && this.wellKnownSingleton == null)
                                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InstanceSettingsMustHaveTypeOrWellKnownObject0)));
 
                                if (this.instanceMode != InstanceContextMode.Single && this.wellKnownSingleton != null)
                                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxWellKnownNonSingleton0)));
                            }
                            else
                            {
                                dispatch.InstanceProvider = instanceProvider;
                            }
                        }
                        dispatch.Type = serviceType;
                        dispatch.InstanceContextProvider = InstanceContextProviderBase.GetProviderForMode(this.instanceMode, dispatch);
 
                        if ((this.instanceMode == InstanceContextMode.Single) &&
                            (dispatch.SingletonInstanceContext == null))
                        {
                            if (singleton == null)
                            {
                                if (this.wellKnownSingleton != null)
                                {
                                    singleton = new InstanceContext(serviceHostBase, this.wellKnownSingleton, true, false);
                                }
                                else if (this.hiddenSingleton != null)
                                {
                                    singleton = new InstanceContext(serviceHostBase, this.hiddenSingleton, false, false);
                                }
                                else
                                {
                                    singleton = new InstanceContext(serviceHostBase, false);
                                }
 
                                singleton.AutoClose = false;
                            }
                            dispatch.SingletonInstanceContext = singleton;
                        }
                    }
                }
            }
        }
    }
}