您的位置:首页 > 移动开发 > Unity3D

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

2008-08-24 11:41 495 查看
在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="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" />

<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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: