自定义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 条评论
登录 后参与评论

相关文章

来自专栏跟着阿笨一起玩NET

VS2010在C#头文件中添加文件注释的方法

1.VS2010 中找到安装盘符(本人安装目录在D盘,所以以D盘为例)D:\Program Files (x86)\Microsoft Visual Studi...

1161
来自专栏逸鹏说道

由Dapper QueryMultiple 返回数据的问题

今天帮群友整理Dapper基础教程的时候手脚快了点,然后遇到了一个小问题,Dapper QueryMultiple 返回数据的问题 多个返回值用QueryMul...

27412
来自专栏菩提树下的杨过

利用FileWatcher实现文件实时监视

FileWatcher能实现对某一目录的文件(新建,改名,内容修改,删除)的实时监视 using System; using System.IO; using ...

2218
来自专栏Porschev[钟慰]的专栏

asp.net生成静态页

做个生成静态页示例: 采用替换模版页的形式生成静态页 第一步:新建项目,创建一个简单模版页:TemplatePage.htm <!DOCTYPE html PU...

2216
来自专栏walterlv - 吕毅的博客

.NET 命令行参数包含应用程序路径吗?

发布于 2018-09-11 13:28 更新于 2018-09...

983
来自专栏ZKEASOFT

.Net Core在Middleware中解析RouteData

在ASP.Net Core中,如果直接在Middleware中获取RouteData返回的是空值,这是因为RouterMiddleware还没执行。但有些情况下...

1913
来自专栏菩提树下的杨过

socket中的byte消息格式设计

这二天在研究webabcd的socket多人聊天室,想尝试增加一些功能,比如:允许用户除发送文字外,还能发送图片或文件。 问题: socket发送数据时,只能发...

2017
来自专栏bluesummer

StackExchange.Redis学习笔记(二) Redis查询 五种数据类型的应用

ConnectionMultiplexer ConnectionMultiplexer 是StackExchange.Redis的核心对象,用这个类的实例来进行...

3699
来自专栏码农阿宇

.Net Core中利用TPL(任务并行库)构建Pipeline处理Dataflow

在学习的过程中,看一些一线的技术文档很吃力,而且考虑到国内那些技术牛人英语都不差的,要向他们看齐,所以每天下班都在疯狂地背单词,博客有些日子没有更新了,见谅见谅...

2521
来自专栏菩提树下的杨过

XmlSpy / XSD 以及 验证

很早以前看过一句话:“XML就象空气”,在企业应用开发中XML是一个重要的数据交换标准。而XSD则可以用来校验XML的数据格式是否正确。 一个典型的XSD文件如...

23410

扫码关注云+社区

领取腾讯云代金券