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

本文来自云栖社区合作伙伴“doNET跨平台”,了解相关信息可以关注“opendotnet”微信公众号

目录
相关文章
|
27天前
|
开发框架 .NET API
Windows Forms应用程序中集成一个ASP.NET API服务
Windows Forms应用程序中集成一个ASP.NET API服务
80 9
|
2月前
|
设计模式 存储 人工智能
深度解析Unity游戏开发:从零构建可扩展与可维护的游戏架构,让你的游戏项目在模块化设计、脚本对象运用及状态模式处理中焕发新生,实现高效迭代与团队协作的完美平衡之路
【9月更文挑战第1天】游戏开发中的架构设计是项目成功的关键。良好的架构能提升开发效率并确保项目的长期可维护性和可扩展性。在使用Unity引擎时,合理的架构尤为重要。本文探讨了如何在Unity中实现可扩展且易维护的游戏架构,包括模块化设计、使用脚本对象管理数据、应用设计模式(如状态模式)及采用MVC/MVVM架构模式。通过这些方法,可以显著提高开发效率和游戏质量。例如,模块化设计将游戏拆分为独立模块。
160 3
|
2月前
|
图形学 iOS开发 Android开发
从Unity开发到移动平台制胜攻略:全面解析iOS与Android应用发布流程,助你轻松掌握跨平台发布技巧,打造爆款手游不是梦——性能优化、广告集成与内购设置全包含
【8月更文挑战第31天】本书详细介绍了如何在Unity中设置项目以适应移动设备,涵盖性能优化、集成广告及内购功能等关键步骤。通过具体示例和代码片段,指导读者完成iOS和Android应用的打包与发布,确保应用顺利上线并获得成功。无论是性能调整还是平台特定的操作,本书均提供了全面的解决方案。
143 0
|
2月前
|
图形学 开发者 UED
Unity游戏开发必备技巧:深度解析事件系统运用之道,从生命周期回调到自定义事件,打造高效逻辑与流畅交互的全方位指南
【8月更文挑战第31天】在游戏开发中,事件系统是连接游戏逻辑与用户交互的关键。Unity提供了多种机制处理事件,如MonoBehaviour生命周期回调、事件系统组件及自定义事件。本文介绍如何有效利用这些机制,包括创建自定义事件和使用Unity内置事件系统提升游戏体验。通过合理安排代码执行时机,如在Awake、Start等方法中初始化组件,以及使用委托和事件处理复杂逻辑,可以使游戏更加高效且逻辑清晰。掌握这些技巧有助于开发者更好地应对游戏开发挑战。
100 0
|
3月前
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
69 0
|
5月前
|
存储 图形学
【unity小技巧】unity事件系统创建通用的对象交互的功能
【unity小技巧】unity事件系统创建通用的对象交互的功能
50 0
|
5月前
|
JSON 开发框架 API
【推荐100个unity插件之20】一个强大的JSON处理库——Newtonsoft.Json(也称为Json.NET)
【推荐100个unity插件之20】一个强大的JSON处理库——Newtonsoft.Json(也称为Json.NET)
365 0
|
5月前
|
程序员 图形学 Android开发
Unity脚本生命周期
Unity脚本生命周期
|
6月前
|
JSON API 定位技术
.NET集成DeveloperSharp实现http网络请求&与其它工具的比较
该内容介绍了一个支持.NET Core 2.0及以上和.NET Framework 4.0及以上的HTTP请求调用方法,主要讨论了POST和GET两种形式。POST请求较为常见,涉及调用地址、发送参数、HTTP请求头和编码格式设置。文中提供了一个使用DeveloperSharp库发送POST请求的C#代码示例,用于发送短信,其中`IU.HttpPost`方法用于执行POST请求。此外,还提到了`HttpPost`方法的参数和返回值说明。最后简要提及了GET请求,通常用于URL带有查询参数的情况,并给出一个简单的GET请求示例。
|
6月前
|
Java 数据库连接 mybatis
在SpringBoot集成下,Mybatis的mapper代理对象究竟是如何生成的
在SpringBoot集成下,Mybatis的mapper代理对象究竟是如何生成的
78 0