File: System\ServiceModel\ComIntegration\ComPlusInstanceContextInitializer.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.EnterpriseServices;
    using System.IO;
    using System.Reflection;
    using System.Runtime;
    using System.Runtime.InteropServices;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Dispatcher;
    using System.Transactions;
 
    class ComPlusInstanceContextInitializer : IInstanceContextInitializer
    {
        ServiceInfo info;
 
        static readonly Guid IID_IServiceActivity = new Guid("67532E0C-9E2F-4450-A354-035633944E17");
        static readonly Guid DefaultPartitionId = new Guid("41E90F3E-56C1-4633-81C3-6E8BAC8BDD70");
 
        private static object manifestLock = new object();
        private static string manifestFileName = Guid.NewGuid().ToString();
 
        static ComPlusInstanceContextInitializer()
        {
            AppDomain currentDomain = AppDomain.CurrentDomain;
            currentDomain.AssemblyResolve += new ResolveEventHandler(ResolveAssembly);
        }
 
        public ComPlusInstanceContextInitializer(ServiceInfo info)
        {
            this.info = info;
 
            if (this.info.HasUdts())
            {
                string tempPath = String.Empty;
                lock (manifestLock)
                {
 
                    try
                    {
                        tempPath = Path.GetTempPath();
                    }
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                            throw;
 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(System.ServiceModel.ComIntegration.Error.CannotAccessDirectory(tempPath));
                    }
 
                    string manifestDirectory = tempPath + this.info.AppID.ToString();
                    if (Directory.Exists(manifestDirectory))
                        Directory.Delete(manifestDirectory, true);
                }
 
            }
        }
 
        public void Initialize(InstanceContext instanceContext, Message message)
        {
            object serviceConfig = null;
            serviceConfig = SetupServiceConfig(instanceContext, message);
 
            IServiceActivity activity;
            activity = (IServiceActivity)SafeNativeMethods.CoCreateActivity(
                serviceConfig,
                IID_IServiceActivity);
 
            ComPlusSynchronizationContext syncContext;
            bool postSynchronous = (this.info.ThreadingModel ==
                                    ThreadingModel.MTA);
            syncContext = new ComPlusSynchronizationContext(activity,
                                                            postSynchronous);
            instanceContext.SynchronizationContext = syncContext;
 
            instanceContext.Closing += this.OnInstanceContextClosing;
            Marshal.ReleaseComObject(serviceConfig);
        }
 
        public void OnInstanceContextClosing(object sender, EventArgs args)
        {
            InstanceContext instanceContext = (InstanceContext)sender;
            ComPlusSynchronizationContext syncContext;
            syncContext = (ComPlusSynchronizationContext)instanceContext.SynchronizationContext;
            syncContext.Dispose();
 
        }
 
        static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
        {
            int indexOfComma = args.Name.IndexOf(",", StringComparison.Ordinal);
            if (indexOfComma != -1)
            {
                Guid assemblyGuid = Guid.Empty;
                string assemblyGuidString = args.Name.Substring(0, indexOfComma).Trim().ToLowerInvariant();
 
                if (Guid.TryParse(assemblyGuidString, out assemblyGuid))
                {
                    return TypeCacheManager.Provider.ResolveAssembly(assemblyGuid);
                }
            }
 
            return null;
        }
 
 
        object SetupServiceConfig(InstanceContext instanceContext, Message message)
        {
            object serviceConfig = new CServiceConfig();
 
            // Threading
            //
            IServiceThreadPoolConfig threadPoolConfig;
            threadPoolConfig = (IServiceThreadPoolConfig)(serviceConfig);
            switch (this.info.ThreadingModel)
            {
                case ThreadingModel.MTA:
                    threadPoolConfig.SelectThreadPool(ThreadPoolOption.MTA);
                    break;
 
                case ThreadingModel.STA:
                    threadPoolConfig.SelectThreadPool(ThreadPoolOption.STA);
                    break;
 
                default:
                    Fx.Assert("Unexpected threading model");
 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.UnexpectedThreadingModel());
            }
            threadPoolConfig.SetBindingInfo(BindingOption.BindingToPoolThread);
 
            // SxS activation context properties
            //                   
 
 
            // Manifest for VARIANT UDT types
            //
 
            // this only gets executed if we actually have UDTs
            if (this.info.HasUdts())
            {
                IServiceSxsConfig sxsConfig = serviceConfig as IServiceSxsConfig;
                if (sxsConfig == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(System.ServiceModel.ComIntegration.Error.QFENotPresent());
                }
 
                lock (manifestLock)
                {
                    string tempPath = String.Empty;
 
                    try
                    {
                        tempPath = Path.GetTempPath();
                    }
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                            throw;
 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(System.ServiceModel.ComIntegration.Error.CannotAccessDirectory(tempPath));
                    }
 
                    string manifestDirectory = tempPath + this.info.AppID.ToString() + @"\";
 
 
                    if (!Directory.Exists(manifestDirectory))
                    {
                        try
                        {
                            Directory.CreateDirectory(manifestDirectory);
                        }
                        catch (Exception e)
                        {
                            if (Fx.IsFatal(e))
                                throw;
 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(System.ServiceModel.ComIntegration.Error.CannotAccessDirectory(manifestDirectory));
                        }
 
                        Guid[] assemblyGuids = this.info.Assemblies;
                        ComIntegrationManifestGenerator.GenerateManifestCollectionFile(assemblyGuids, manifestDirectory + manifestFileName + @".manifest", manifestFileName);
 
                        foreach (Guid g in assemblyGuids)
                        {
                            Type[] types = this.info.GetTypes(g);
                            if (types.Length > 0)
                            {
                                String guidStr = g.ToString();
                                ComIntegrationManifestGenerator.GenerateWin32ManifestFile(types, manifestDirectory + guidStr + @".manifest", guidStr);
                            }
                        }
                    }
 
 
                    sxsConfig.SxsConfig(CSC_SxsConfig.CSC_NewSxs);
                    sxsConfig.SxsName(manifestFileName + @".manifest");
                    sxsConfig.SxsDirectory(manifestDirectory);
                }
            }
 
 
            // Partitions
            //
            if (this.info.PartitionId != DefaultPartitionId)
            {
                IServicePartitionConfig partitionConfig;
                partitionConfig = (IServicePartitionConfig)(serviceConfig);
                partitionConfig.PartitionConfig(PartitionOption.New);
                partitionConfig.PartitionID(this.info.PartitionId);
            }
 
            // Transactions
            //
            IServiceTransactionConfig transactionConfig;
            transactionConfig = (IServiceTransactionConfig)(serviceConfig);
            transactionConfig.ConfigureTransaction(
                TransactionConfig.NoTransaction);
 
            if ((this.info.TransactionOption == TransactionOption.Required) ||
                (this.info.TransactionOption == TransactionOption.Supported))
            {
                Transaction messageTransaction = null;
                messageTransaction = MessageUtil.GetMessageTransaction(message);
                if (messageTransaction != null)
                {
                    TransactionProxy proxy = new TransactionProxy(info.AppID, info.Clsid);
                    proxy.SetTransaction(messageTransaction);
 
                    instanceContext.Extensions.Add(proxy);
                    IServiceSysTxnConfig sysTxnconfing = (IServiceSysTxnConfig)transactionConfig;
                    IntPtr pUnk = TransactionProxyBuilder.CreateTransactionProxyTearOff(proxy);
                    sysTxnconfing.ConfigureBYOTSysTxn(pUnk);
                    Marshal.Release(pUnk);
                }
            }
            return serviceConfig;
        }
    }
}