专栏首页张善友的专栏自定义Unity对象生命周期管理集成ADO.NET Entity Framework

自定义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>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ASP.NET Web API 接口执行时间监控

    软件产品常常会出现这样的情况:产品性能因某些无法预料的瓶颈而受到干扰,导致程序的处理效率降低,性能得不到充分的发挥。如何快速有效地找到软件产品的性能瓶颈,则是我...

    张善友
  • Microsoft Web Farm Framework (WFF) 2.0正式发布

    Microsoft Web Farm Framework (WFF) 2.0 是微软开发的、基于IIS 7.x的小插件,能够帮助我们轻松实现Web网站的高性能、...

    张善友
  • asp.net mvc本地程序集和GAC的程序集冲突解决方法

    一个从asp.net mvc 3升级到asp.net mvc 4的项目发生了如下错误: [A]System.Web.WebPages.Razor.Config...

    张善友
  • 10 种最流行的 Web 挖掘工具

    互联网有数不清的网页,且不断在以指数级速度产生新内容。到 2022 年,整个互联网创建和复制的数据将达到 44 ZB,也就是 44 万亿 GB。这么大体量内容的...

    周萝卜
  • Web PI——微软的Web平台安装器

    用以下这个安装包来做silverlight开发环境会更方便了。 微软发布了Web平台安装器:aka Web PI,该工具用来安装微软的整个Web平台,包括I...

    用户1172164
  • ASP.NET MVC 3发布报错(ASP.NET MVC 3在没有安装环境的服务器上运行)的解决方案

    前言 ASP.NET MVC 3在没有安装MVC3的环境的服务器上运行,就会报错,缺少引用,本文就为mvc3发布报错的解决方案。 解决方案 思路:提供ASP....

    Java中文社群_老王
  • Exchange Server 2013之分角色部署

    前面几篇介绍了Exchange Server 2013预览版在Windows 2008 R2环境下单机部署。下面,将在Windows Server 2012 R...

    李珣
  • Lync server 2013 之office web apps server 搭建步骤

    office web apps server 搭建步骤: 一、 .NET Framework 4.5 节点下的HTTP 激活 .NET Framework 3....

    杨强生
  • Lync Server 2013企业版快速部署视频(第一期)

    近期在做Lync Server 2013站点迁移项目时,做POC顺便把第一个Lync站点的部署录制了,分享给大家!

    杨强生
  • 微软超融合私有云测试32-SCCM2016部署之SCCM管理服务器安装

    1) 前置条件安装完毕后,插入SCCM安装光盘,打开安装光盘的如下路径下的extadsh.exe程序并执行,(注意: 一定要从CMD中执行,并且使用管理员模式)

    SuperDream

扫码关注云+社区

领取腾讯云代金券