File: System\ServiceModel\ComIntegration\ServiceInfo.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.ComIntegration
{
    using System;
    using System.ServiceModel.Dispatcher;
    using System.ServiceModel.Description;
    using System.Collections.Generic;
    using System.Collections;
    using System.Diagnostics;
    using System.EnterpriseServices;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.ServiceModel;
    using System.ServiceModel.Configuration;
    using System.Transactions;
    using SR = System.ServiceModel.SR;
    using System.ServiceModel.Diagnostics;
    using System.Runtime;
 
    // The values of the enum are reflected from the values in the
    // COM+ Admin SDK.
    //
    enum Bitness
    {
        Bitness32 = 0x01,
        Bitness64 = 0x02
    }
 
    enum ThreadingModel
    {
        MTA,
        STA
    }
 
    enum HostingMode
    {
        ComPlus,             // Living in a DllHost.exe
        WebHostOutOfProcess, // From webhost to dllhost.exe
        WebHostInProcess     // Inside webhost
    }
 
    class ServiceInfo
    {
        ServiceElement service;
        Guid clsid;
        Guid appid;
        HostingMode hostingMode;
        Guid partitionId;
        Bitness bitness;
        ThreadingModel threadingModel;
        TransactionOption transactionOption;
        IsolationLevel isolationLevel;
        bool checkRoles;
        string[] componentRoleMembers;
        bool objectPoolingEnabled;
        int maxPoolSize;
        Type managedType;
        List<ContractInfo> contracts;
        string serviceName;
        Dictionary<Guid, List<Type>> udts;
 
 
        public string ServiceName
        {
            get
            {
                return serviceName;
            }
        }
 
 
        // NOTE: Construction of this thing is quite inefficient-- it
        //       has several nested loops that could probably be
        //       improved. Such optimizations have been left for when
        //       it turns out to be a performance problem, for the
        //       sake of simplicity.
        //
        public ServiceInfo(Guid clsid,
                            ServiceElement service,
                            ComCatalogObject application,
                            ComCatalogObject classObject,
                            HostingMode hostingMode)
        {
            // Simple things...
            //
            this.service = service;
            this.clsid = clsid;
            this.appid = Fx.CreateGuid((string)application.GetValue("ID"));
            this.partitionId = Fx.CreateGuid((string)application.GetValue("AppPartitionID"));
            this.bitness = (Bitness)classObject.GetValue("Bitness");
            this.transactionOption = (TransactionOption)classObject.GetValue("Transaction");
            this.hostingMode = hostingMode;
            this.managedType = TypeCacheManager.ResolveClsidToType(clsid);
            this.serviceName = application.Name + "." + classObject.Name;
            this.udts = new Dictionary<Guid, List<Type>>();
 
            // Isolation Level
            COMAdminIsolationLevel adminIsolationLevel;
            adminIsolationLevel = (COMAdminIsolationLevel)classObject.GetValue("TxIsolationLevel");
            switch (adminIsolationLevel)
            {
                case COMAdminIsolationLevel.Any:
                    this.isolationLevel = IsolationLevel.Unspecified;
                    break;
                case COMAdminIsolationLevel.ReadUncommitted:
                    this.isolationLevel = IsolationLevel.ReadUncommitted;
                    break;
                case COMAdminIsolationLevel.ReadCommitted:
                    this.isolationLevel = IsolationLevel.ReadCommitted;
                    break;
                case COMAdminIsolationLevel.RepeatableRead:
                    this.isolationLevel = IsolationLevel.RepeatableRead;
                    break;
                case COMAdminIsolationLevel.Serializable:
                    this.isolationLevel = IsolationLevel.Serializable;
                    break;
                default:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ListenerInitFailed(
                        SR.GetString(SR.InvalidIsolationLevelValue,
                                     this.clsid, adminIsolationLevel)));
            }
 
            // Threading Model
            //
            COMAdminThreadingModel adminThreadingModel;
            adminThreadingModel = (COMAdminThreadingModel)classObject.GetValue("ThreadingModel");
            switch (adminThreadingModel)
            {
                case COMAdminThreadingModel.Apartment:
                case COMAdminThreadingModel.Main:
                    this.threadingModel = ThreadingModel.STA;
                    objectPoolingEnabled = false;
                    break;
 
                default:
                    this.threadingModel = ThreadingModel.MTA;
                    objectPoolingEnabled = (bool)classObject.GetValue("ObjectPoolingEnabled");
                    break;
            }
 
            // Object Pool settings
            // 
 
            if (objectPoolingEnabled)
            {
                maxPoolSize = (int)classObject.GetValue("MaxPoolSize");
            }
            else
                maxPoolSize = 0;
            // Security Settings
            //
            bool appSecurityEnabled;
            appSecurityEnabled = (bool)application.GetValue(
                "ApplicationAccessChecksEnabled");
            if (appSecurityEnabled)
            {
 
                bool classSecurityEnabled;
                classSecurityEnabled = (bool)classObject.GetValue(
                    "ComponentAccessChecksEnabled");
                if (classSecurityEnabled)
                {
                    this.checkRoles = true;
                }
            }
 
            // Component Roles
            //
            ComCatalogCollection roles;
            roles = classObject.GetCollection("RolesForComponent");
            this.componentRoleMembers = CatalogUtil.GetRoleMembers(application, roles);
            // Contracts
            // One ContractInfo per unique IID exposed, so we need to
            // filter duplicates.
            //
            this.contracts = new List<ContractInfo>();
            ComCatalogCollection interfaces;
            interfaces = classObject.GetCollection("InterfacesForComponent");
            foreach (ServiceEndpointElement endpoint in service.Endpoints)
            {
                ContractInfo contract = null;
                if (endpoint.Contract == ServiceMetadataBehavior.MexContractName)
                    continue;
 
                Guid iid;
                if (DiagnosticUtility.Utility.TryCreateGuid(endpoint.Contract, out iid))
                {
                    // (Filter duplicates.)
                    bool duplicate = false;
                    foreach (ContractInfo otherContract in this.contracts)
                    {
                        if (iid == otherContract.IID)
                        {
                            duplicate = true;
                            break;
                        }
                    }
                    if (duplicate) continue;
 
                    foreach (ComCatalogObject interfaceObject in interfaces)
                    {
                        Guid otherInterfaceID;
                        if (DiagnosticUtility.Utility.TryCreateGuid((string)interfaceObject.GetValue("IID"), out otherInterfaceID))
                        {
                            if (otherInterfaceID == iid)
                            {
                                contract = new ContractInfo(iid,
                                                            endpoint,
                                                            interfaceObject,
                                                            application);
                                break;
                            }
                        }
                    }
                }
 
                if (contract == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ListenerInitFailed(
                        SR.GetString(SR.EndpointNotAnIID,
                                     clsid.ToString("B").ToUpperInvariant(),
                                     endpoint.Contract)));
                }
                this.contracts.Add(contract);
            }
        }
 
        public Type ServiceType
        {
            get { return this.managedType; }
        }
 
        public ServiceElement ServiceElement
        {
            get { return this.service; }
        }
 
        public Guid Clsid
        {
            get { return this.clsid; }
        }
 
        public Guid AppID
        {
            get { return this.appid; }
        }
        public Guid PartitionId
        {
            get { return this.partitionId; }
        }
 
        public Bitness Bitness
        {
            get { return this.bitness; }
        }
 
        public bool CheckRoles
        {
            get { return this.checkRoles; }
        }
 
 
        public ThreadingModel ThreadingModel
        {
            get { return this.threadingModel; }
        }
 
        public TransactionOption TransactionOption
        {
            get { return this.transactionOption; }
        }
 
        public IsolationLevel IsolationLevel
        {
            get { return this.isolationLevel; }
        }
 
        public string[] ComponentRoleMembers
        {
            get { return this.componentRoleMembers; }
        }
 
        public List<ContractInfo> Contracts
        {
            get { return this.contracts; }
        }
 
        public HostingMode HostingMode
        {
            get { return this.hostingMode; }
        }
 
        public bool Pooled
        {
            get { return this.objectPoolingEnabled; }
        }
 
        public int MaxPoolSize
        {
            get { return this.maxPoolSize; }
        }
 
        internal Guid[] Assemblies
        {
            get
            {
                Guid[] ret = new Guid[this.udts.Keys.Count];
                this.udts.Keys.CopyTo(ret, 0);
 
                return ret;
            }
        }
 
        internal bool HasUdts()
        {
            // use the assembly count since we only add assemblies when we got UDTs
            return (this.udts.Keys.Count > 0);
        }
 
        internal Type[] GetTypes(Guid assemblyId)
        {
            List<Type> ret = null;
            udts.TryGetValue(assemblyId, out ret);
            if (null == ret)
                return new Type[0];
 
 
            return ret.ToArray();
        }
 
        internal void AddUdt(Type udt, Guid assemblyId)
        {
            if (!udts.ContainsKey(assemblyId))
                udts[assemblyId] = new List<Type>();
 
            if (!udts[assemblyId].Contains(udt))
                udts[assemblyId].Add(udt);
        }
 
    }
 
    class ContractInfo
    {
        string name;
        Guid iid;
        string[] interfaceRoleMembers;
        List<OperationInfo> operations;
 
        public ContractInfo(Guid iid,
                            ServiceEndpointElement endpoint,
                            ComCatalogObject interfaceObject,
                            ComCatalogObject application)
        {
            this.name = endpoint.Contract;
            this.iid = iid;
 
            // Interface Roles
            //
            ComCatalogCollection roles;
            roles = interfaceObject.GetCollection("RolesForInterface");
            this.interfaceRoleMembers = CatalogUtil.GetRoleMembers(application,
                                                                   roles);
 
            // Operations
            //
            this.operations = new List<OperationInfo>();
 
            ComCatalogCollection methods;
            methods = interfaceObject.GetCollection("MethodsForInterface");
            foreach (ComCatalogObject method in methods)
            {
                this.operations.Add(new OperationInfo(method,
                                                      application));
            }
        }
 
        public string Name
        {
            get { return this.name; }
        }
 
        public Guid IID
        {
            get { return this.iid; }
        }
 
        public string[] InterfaceRoleMembers
        {
            get { return this.interfaceRoleMembers; }
        }
 
        public List<OperationInfo> Operations
        {
            get { return this.operations; }
        }
    }
 
    class OperationInfo
    {
        string name;
        string[] methodRoleMembers;
 
        public OperationInfo(ComCatalogObject methodObject,
                             ComCatalogObject application)
        {
            this.name = (string)methodObject.GetValue("Name");
 
            // Method Roles
            //
            ComCatalogCollection roles;
            roles = methodObject.GetCollection("RolesForMethod");
            this.methodRoleMembers = CatalogUtil.GetRoleMembers(application,
                                                                roles);
        }
 
        public string Name
        {
            get { return this.name; }
        }
 
        public string[] MethodRoleMembers
        {
            get { return this.methodRoleMembers; }
        }
    }
}