• 自定义Unity对象生命周期管理集成ADO.NET Entity Framework


    在Unity中,从Unity 取得的实例为 Transient。如果你希望使用多线程方式,就需要在组成时使用lifecycle参数,这时候取出的组件就不再是同一个了。在Unity IOC中,它支持我们对于组件的实例进行控制,也就是说我们可以透明的管理一个组件拥有多少个实例。Unity IOC容器提供了如下几种生命处理方式:
    # Singleton:一个组件只有一个实例被创建,所有请求的客户使用程序得到的都是同一个实例。
    # Transient:这种处理方式与我们平时使用new的效果是一样的,对于每次的请求得到的都是一个新的实例。
    # Custom:自定义的生命处理方式。

    我要增加一个Request的,一个Request请求一个实例,然后在Request结束的时候,回收资源。 增加一个Resquest级别的LifetimeManager,HttpContext.Items中数据是Request期间共享数据用的,所以HttpContext.Items中放一个字典,用类型为key,类型的实例为value。如果当前Context.Items中有类型的实例,就直接返回实例。 ObjectContext本身是有缓存的,整个Request内都是一个ObjectContext,ObjectContext一级缓存能力进一步利用。

    用在Unity中,如何获取对象的实例及如何销毁对象都是由LifetimeManager完成的,其定义如下
    public abstract class LifetimeManager : ILifetimePolicy, IBuilderPolicy
    {
        protected LifetimeManager();

        public abstract object GetValue();
        public abstract void RemoveValue();
        public abstract void SetValue(object newValue);
    }

    其中GetValue方法获取对象实例,RemoveValue方法销毁对象,SetValue方法为对外引用的保存提供新的实例

    有了这3个方法,就可以通过自定义LifetimeManager来实现从HttpContext中取值。

    下面我们来实现Unity集成ADO.NET Entity Framework的工作:

    1、利用Unity的依赖注入,ObjectContext会给我们生成3个构造函数,类似于下面的代码:

    // Original file name:
    // Generation date: 2008/8/24 10:05:33
    namespace RequestLifeTimeManagerTest
    {
        using Microsoft.Practices.Unity;

        /// <summary>
        /// There are no comments for AdventureWorksLTEntities in the schema.
        /// </summary>
        public partial class AdventureWorksLTEntities : global::System.Data.Objects.ObjectContext
        {
            /// <summary>
            /// Initializes a new AdventureWorksLTEntities object using the connection string found in the 'AdventureWorksLTEntities' section of the application configuration file.
            /// </summary>
            public AdventureWorksLTEntities() :
                    base("name=AdventureWorksLTEntities", "AdventureWorksLTEntities")
            {
                this.OnContextCreated();
            }
            /// <summary>
            /// Initialize a new AdventureWorksLTEntities object.
            /// </summary>
            public AdventureWorksLTEntities(string connectionString) :
                    base(connectionString, "AdventureWorksLTEntities")
            {
                this.OnContextCreated();
            }
            /// <summary>
            /// Initialize a new AdventureWorksLTEntities object.
            /// </summary>
            public AdventureWorksLTEntities(global::System.Data.EntityClient.EntityConnection connection) :
                    base(connection, "AdventureWorksLTEntities")
            {
                this.OnContextCreated();
            }
            partial void OnContextCreated();

    ……

    }

    构造函数注入包含了二种情况,一种是类仅有一个构造函数时,Unity 可以进行自动注入;另一种情况是,类包含多个构造函数时,必须使用 Attribute 或者配置文件指定注入时使用的构造函数。

    ObjectContext有多个构造函数,而且ObjectContext的构造函数代码是Visual Studio 代码生成的,最好的选择是使用配置文件或者使用配置API指定注入时使用的构造函数。下面是使用配置API:

    namespace RequestLifeTimeManagerTest
    {
        public class EFContainerExtension : UnityContainerExtension  
        {
            protected override void Initialize()
            {
               this.Container.RegisterType<AdventureWorksLTEntities, AdventureWorksLTEntities>(new RequestControlledLifetimeManager(typeof(AdventureWorksLTEntities)))
                    .Configure<InjectedMembers>()
                        .ConfigureInjectionFor<AdventureWorksLTEntities>(new InjectionConstructor());

            }
        }
    }

    我们定义了一个Unity扩展,在扩展类EFContainerExtension 我们选择了第一个构造函数以及ObjectContext使用RequestControlledLifetimeManager实现ObjectContext的生命周期管理。

    2、实现RequestControlledLifetimeManager,完成对整个Request内都是一个ObjectContext的对象的生命周期管理:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using Microsoft.Practices.Unity;

    namespace RequestLifeTimeManagerTest
    {
        public class RequestControlledLifetimeManager : LifetimeManager
        {
            private Type objectType;

            /// <summary>  
            ///   
            /// </summary>  
            /// <param name="t"></param>  
            public RequestControlledLifetimeManager(Type t)
            {
                this.objectType = t;
            }

            private IDictionary<Type, object> GetObjectTable()
            {
                IDictionary<Type, object> objects = HttpContext.Current.Items[RequestLifeTimeManagerTest.UnityHttpModule.UNITYOBJECTS]
                    as IDictionary<Type, object>;
                if (objects == null)
                {
                    lock (this)
                    {
                        if (HttpContext.Current.Items[RequestLifeTimeManagerTest.UnityHttpModule.UNITYOBJECTS] == null)
                        {
                            objects = new Dictionary<Type, object>();
                            HttpContext.Current.Items[RequestLifeTimeManagerTest.UnityHttpModule.UNITYOBJECTS] = objects;
                        }
                        else
                        {
                            return HttpContext.Current.Items[RequestLifeTimeManagerTest.UnityHttpModule.UNITYOBJECTS]
                                as IDictionary<Type, object>;
                        }
                    }
                }
                return objects;
            }

            public override object GetValue()
            {
                IDictionary<Type, object> objects = this.GetObjectTable();
                object obj = null;
                if (objects.TryGetValue(this.objectType, out obj))
                {
                    return obj;
                }
                return null;
            }

            public override void RemoveValue()
            {
                IDictionary<Type, object> objects = this.GetObjectTable();
                object obj = null;
                if (objects.TryGetValue(this.objectType, out obj))
                {
                    ((IDisposable)obj).Dispose();
                    objects.Remove(this.objectType);
                }
            }

            public override void SetValue(object newValue)
            {
                IDictionary<Type, object> objects = this.GetObjectTable();
                objects.Add(this.objectType, newValue);
            }
        }
    }

    写一个HttpMoudle,在Request结束的时候回收资源。

    using System;
    using System.Web;
    using System.Collections.Generic;

     

    namespace RequestLifeTimeManagerTest
    {
        public class UnityHttpModule : IHttpModule
        {
            internal const string UNITYOBJECTS = "UNITYOBJECTS";
            #region IHttpModule Members

            public void Dispose()
            {
                //clean-up code here.
            }

            public void Init(HttpApplication context)
            {
                context.EndRequest += new EventHandler(context_EndRequest);

            }

            #endregion

            private void context_EndRequest(object sender, EventArgs e)
            {
                IDictionary<Type, object> objects = HttpContext.Current.Items[UNITYOBJECTS]
                    as IDictionary<Type, object>;
                if (objects != null)
                {
                    foreach (Type key in objects.Keys)
                    {
                        if (objects[key] is IDisposable)
                        {
                            ((IDisposable)objects[key]).Dispose();
                        }
                    }
                    HttpContext.Current.Items.Remove(UNITYOBJECTS);
                }
            }

        }
    }

    3、web.config中的配置文件内容如下,注意看红色部分:

    <?xml version="1.0"?>
    <configuration>
        <configSections>
            <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
                <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
                    <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
                    <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
                        <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere" />
                        <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
                        <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
                        <section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
                    </sectionGroup>
                </sectionGroup>
            </sectionGroup>
            <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
        </configSections>
        <unity>
            <typeAliases>
          <typeAlias alias="string" type="System.String, mscorlib" />
                <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
                <typeAlias alias="transient" type="Microsoft.Practices.Unity.TransientLifetimeManager, Microsoft.Practices.Unity" />
        </typeAliases>
            <containers>  
                <container>
            <types>
              <type type="RequestLifeTimeManagerTest.Gateways.IProductGateway,RequestLifeTimeManagerTest" mapTo="RequestLifeTimeManagerTest.Gateways.ProductGateway, RequestLifeTimeManagerTest">
              </type>
            </types>
            <extensions>
              <add type="RequestLifeTimeManagerTest.EFContainerExtension, RequestLifeTimeManagerTest" />
            </extensions>
                </container>
            </containers>
        </unity>

        <appSettings />
        <connectionStrings><add name="AdventureWorksLTEntities" connectionString="metadata=res://*/AdventureWorksModel.csdl|res://*/AdventureWorksModel.ssdl|res://*/AdventureWorksModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=GEFF-PC;Initial Catalog=AdventureWorksLT;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" /></connectionStrings>
        <system.web>
            <!--
                Set compilation debug="true" to insert debugging
                symbols into the compiled page. Because this
                affects performance, set this value to true only
                during development.
            -->
            <compilation debug="true">
                <assemblies>
                    <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
                    <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
                    <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
                    <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
                <add assembly="System.Data.Entity, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /></assemblies>
            </compilation>
            <!--
                The <authentication> section enables configuration
                of the security authentication mode used by
                ASP.NET to identify an incoming user.
            -->
            <authentication mode="Windows" />
            <!--
                The <customErrors> section enables configuration
                of what to do if/when an unhandled error occurs
                during the execution of a request. Specifically,
                it enables developers to configure html error pages
                to be displayed in place of a error stack trace.

            <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
                <error statusCode="403" redirect="NoAccess.htm" />
                <error statusCode="404" redirect="FileNotFound.htm" />
            </customErrors>
            -->
            <pages>
                <controls>
                    <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
                    <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
                </controls>
            </pages>
            <httpHandlers>
                <!--<remove verb="*" path="*.aspx"/>
                <add verb="*" path="*.aspx" type="RequestLifeTimeManagerTest.UnityHttpHandlerFactory, RequestLifeTimeManagerTest"/>-->
                <remove verb="*" path="*.asmx" />
                <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
                <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
                <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false" />
            </httpHandlers>
            <httpModules>
                <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

           <add name="UnityModule" type="RequestLifeTimeManagerTest.UnityHttpModule,RequestLifeTimeManagerTest"/>           
            </httpModules>
        </system.web>
        <system.codedom>
            <compilers>
                <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
                    <providerOption name="CompilerVersion" value="v3.5" />
                    <providerOption name="WarnAsError" value="false" />
                </compiler>
            </compilers>
        </system.codedom>
        <!--
            The system.webServer section is required for running ASP.NET AJAX under Internet
            Information Services 7.0.  It is not necessary for previous version of IIS.
        -->
        <system.webServer>
            <validation validateIntegratedModeConfiguration="false" />
            <modules>
                <remove name="ScriptModule" />
                <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            </modules>
            <handlers>
                <remove name="WebServiceHandlerFactory-Integrated" />
                <remove name="ScriptHandlerFactory" />
                <remove name="ScriptHandlerFactoryAppServices" />
                <remove name="ScriptResource" />
                <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
                <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
                <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            </handlers>
        </system.webServer>
        <runtime>
            <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
                <dependentAssembly>
                    <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35" />
                    <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0" />
                </dependentAssembly>
                <dependentAssembly>
                    <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35" />
                    <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0" />
                </dependentAssembly>
            </assemblyBinding>
        </runtime>
    </configuration>

    欢迎大家扫描下面二维码成为我的客户,为你服务和上云

  • 相关阅读:
    多态
    多继承
    传宗接代——继承
    解决vue项目更新版本后浏览器的缓存问题
    escape()、encodeURI()、encodeURIComponent()三种编码方式的区别
    epoll使用总结
    探讨c/c++的指针
    基于linux的pthread_t封装一个Thread类
    unix高并发编程中遇到的问题和笔记
    面向对象分析与设计 实验七
  • 原文地址:https://www.cnblogs.com/shanyou/p/1275059.html
Copyright © 2020-2023  润新知