学技术不只是为了吃饭,吃饭是为了更好的学技术.

导航

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

<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>

posted on 2010-05-30 16:27  KO__KO  阅读(493)  评论(1编辑  收藏  举报