211
技術社區[雲棲]
自定義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());
}
}
}
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="Data Source=GEFF-PC;Initial Catalog=AdventureWorksLT;Integrated Security=True;MultipleActiveResultSets=True"" 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" />
</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>
最後更新:2017-04-02 00:06:32