首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自定义Unity对象生命周期管理集成ADO.NET Entity Framework

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

作者头像
张善友
发布2018-01-30 15:44:42
9470
发布2018-01-30 15:44:42
举报
文章被收录于专栏:张善友的专栏张善友的专栏

在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>
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2008-08-24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档