问题描述
有没有人有关于如何使 Unity 1.2 或 2.0 与 ASP.NET WebForms 一起工作的好例子?
我以为我已经弄清楚了,但显然我遗漏了一些东西.现在我收到错误;没有为此对象定义无参数构造函数".我记得几年前遇到过这个错误,我只是不记得我做了什么.
显然 Unity 无法正常工作,因为在此过程中我忘记了某些东西.任何帮助将不胜感激.
这是我的一些代码:
Global.asax
<前>使用系统;使用 System.Collections.Generic;使用 System.Linq;使用 System.Web;使用 System.Web.Security;使用 System.Web.SessionState;使用 Microsoft.Practices.Unity;使用 PIA35.Unity;命名空间 PIA35.Web{公共类全局:System.Web.HttpApplication{protected void Application_Start(对象发送者,EventArgs e){IUnityContainer 容器 = Application.GetContainer();PIA35.Web.IoC.Bootstrapper.Configure(容器);}}}这是我的 web.config 文件的 httpModules 部分:
<前><http模块><add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/><add name="UnityHttpModule" type="PIA35.Unity.UnityHttpModule, PIA35.Unity"/></httpModules>这是我的 IoC 引导程序类的代码.
<前>使用系统;使用 System.Collections.Generic;使用 System.Linq;使用 System.Web;使用 Microsoft.Practices.Unity;使用 PIA35.Services.Interfaces;使用 PIA35.Services;使用 PIA35.DataObjects.Interfaces;使用 PIA35.DataObjects.SqlServer;命名空间 PIA35.Web.IoC{公共静态类引导程序{公共静态无效配置(IUnityContainer容器){容器.RegisterType这是 HttpApplicationStateExtensions.cs 文件.
<前>使用 System.Web;使用 Microsoft.Practices.Unity;命名空间 PIA35.Unity{公共静态类 HttpApplicationStateExtensions{private const string GlobalContainerKey = "GlobalUnityContainerKey";公共静态 IUnityContainer GetContainer(这个 HttpApplicationState 应用程序){application.Lock();尝试{IUnityContainer container = application[GlobalContainerKey] as IUnityContainer;如果(容器 == 空){容器 = 新的 UnityContainer();应用程序[GlobalContainerKey] = 容器;}返回容器;}最后{application.UnLock();}}}}这是我的 UnityHttpModule.cs 文件.
<前>使用系统;使用 System.Collections.Generic;使用 System.Web;使用 System.Web.UI;使用 Microsoft.Practices.Unity;命名空间 PIA35.Unity{公共类 UnityHttpModule : IHttpModule{#region IHttpModule 成员//////初始化一个模块并准备它来处理请求./////////一个///提供对方法、属性的访问,///和 ASP.NET 应用程序中所有应用程序对象共有的事件公共无效初始化(HttpApplication上下文){context.PreRequestHandlerExecute += OnPreRequestHandlerExecute;}//////处理资源(内存除外)///由实现 .//////公共无效处置(){}#endregionprivate void OnPreRequestHandlerExecute(对象发送者,EventArgs e){IHttpHandler 处理程序 = HttpContext.Current.Handler;HttpContext.Current.Application.GetContainer().BuildUp(handler.GetType(), handler);//页面初始化完成后就可以建立用户控件了Page page = HttpContext.Current.Handler as Page;如果(页面!= null){page.InitComplete += OnPageInitComplete;}}//获取页面控件树中不包括页面本身的控件私有 IEnumerable GetControlTree(控件根){foreach(在 root.Controls 中控制子级){yield return child;foreach (GetControlTree(child) 中的 Control c){收益率c;}}}//在页面的控件树中建立每个控件私有无效 OnPageInitComplete(对象发送者,EventArgs e){页面页面 = (Page)sender;IUnityContainer 容器 = HttpContext.Current.Application.GetContainer();foreach(GetControlTree(page) 中的 Control c){container.BuildUp(c.GetType(), c);}}}}这是我的一个服务类的示例.
<前>命名空间 PIA35.Services{公共类 CategoryService :ICategoryService{#region 依赖注入私有ICategoryDao categoryDao;公共类别服务(ICategoryDao CategoryDao){this.categoryDao = CategoryDao;}#endregion#region ICategoryService 成员公共列表 GetAll(){返回 categoryDao.GetAll().ToList();}公共类别 GetById(int CategoryId){返回 categoryDao.GetById(CategoryId);}公共无效添加(类别模型){categoryDao.Insert(模型);}公共无效更新(类别模型){categoryDao.Update(model);}公共无效删除(类别模型){categoryDao.Delete(模型);}#endregion}}我看到已经有人回答了,但我只是想指出您正在将所有对 GetContainer 的调用与您的锁定模式同步.对 Application.Lock() 的调用实际上会在 applicationState 上取出一个写锁,它是您的 Web 应用程序中的一个单例对象,如果您想扩展它,您会看到问题.
为了解决这个问题,你可以做一个双重检查的锁.像这样:
public static IUnityContainer GetContainer(这个HttpApplicationState应用程序){IUnityContainer container = application[GlobalContainerKey] as IUnityContainer;如果(容器 == 空){application.Lock();尝试{container = application[GlobalContainerKey] as IUnityContainer;如果(容器 == 空){容器 = 新的 UnityContainer();应用程序[GlobalContainerKey] = 容器;}}最后{application.UnLock();}}返回容器;}
我还想指出一个简洁的模式,我们用来确保控件和页面建立了它们的依赖关系.我们基本上有一个 Generic PageBase 和 Generic ControlBase,我们所有的页面和控件都继承自它们.我将进入页面库作为示例:
公共抽象类 SitePageBase:SitePageBase 其中 T :SitePageBase{protected override void OnInit(EventArgs e){BuildUpDerived();base.OnInit( e );}protected void BuildUpDerived(){ContainerProvider.Container.BuildUp( this as T );}}
然后在我们的页面中,我们可以简单地从 Generic base 派生,它会负责构建.
public partial class Default : SitePageBase{[依赖]公共 IContentService ContentService { 获取;放;}protected override void OnPreRender( EventArgs e ){this.label.Text = ContentService.GetContent("labelText");}}
Does anyone have any good examples of how to make Unity 1.2 or 2.0 work with ASP.NET WebForms?
I thought I had this figured out, but evidently I'm missing something. Now I'm getting the error; "No parameterless constructor defined for this object". I remember getting this error a couple years ago, I and just don't remember what I did.
Obviously Unity isn't working as it should because somewhere along the way I've forgotten something. Any help would be appreciated.
Here's some of my code:
Global.asax
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Security; using System.Web.SessionState; using Microsoft.Practices.Unity; using PIA35.Unity; namespace PIA35.Web { public class Global : System.Web.HttpApplication { protected void Application_Start(object sender, EventArgs e) { IUnityContainer container = Application.GetContainer(); PIA35.Web.IoC.Bootstrapper.Configure(container); } } }
Here's my httpModules section of the web.config file:
<httpModules> <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add name="UnityHttpModule" type="PIA35.Unity.UnityHttpModule, PIA35.Unity"/> </httpModules>
Here's the code for my IoC bootstrapper class.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Microsoft.Practices.Unity; using PIA35.Services.Interfaces; using PIA35.Services; using PIA35.DataObjects.Interfaces; using PIA35.DataObjects.SqlServer; namespace PIA35.Web.IoC { public static class Bootstrapper { public static void Configure(IUnityContainer container) { container .RegisterType<ICategoryService, CategoryService>() .RegisterType<ICustomerService, CustomerService>() .RegisterType<IOrderService, OrderService>() .RegisterType<IOrderDetailService, OrderDetailService>() .RegisterType<IProductService, ProductService>() .RegisterType<ICategoryDao, SqlServerCategoryDao>() .RegisterType<ICustomerDao, SqlServerCustomerDao>() .RegisterType<IOrderDao, SqlServerOrderDao>() .RegisterType<IOrderDetailDao, SqlServerOrderDetailDao>() .RegisterType<IProductDao, SqlServerProductDao>(); } } }
Here's the HttpApplicationStateExtensions.cs file.
using System.Web; using Microsoft.Practices.Unity; namespace PIA35.Unity { public static class HttpApplicationStateExtensions { private const string GlobalContainerKey = "GlobalUnityContainerKey"; public static IUnityContainer GetContainer(this HttpApplicationState application) { application.Lock(); try { IUnityContainer container = application[GlobalContainerKey] as IUnityContainer; if (container == null) { container = new UnityContainer(); application[GlobalContainerKey] = container; } return container; } finally { application.UnLock(); } } } }
Here's my UnityHttpModule.cs file.
using System; using System.Collections.Generic; using System.Web; using System.Web.UI; using Microsoft.Practices.Unity; namespace PIA35.Unity { public class UnityHttpModule : IHttpModule { #region IHttpModule Members /// ///Initializes a module and prepares it to handle requests. /// /// ///An ///that provides access to the methods, properties, ///and events common to all application objects within an ASP.NET application public void Init(HttpApplication context) { context.PreRequestHandlerExecute += OnPreRequestHandlerExecute; } /// ///Disposes of the resources (other than memory) ///used by the module that implements . /// /// public void Dispose() { } #endregion private void OnPreRequestHandlerExecute(object sender, EventArgs e) { IHttpHandler handler = HttpContext.Current.Handler; HttpContext.Current.Application.GetContainer().BuildUp(handler.GetType(), handler); // User Controls are ready to be built up after the page initialization is complete Page page = HttpContext.Current.Handler as Page; if (page != null) { page.InitComplete += OnPageInitComplete; } } // Get the controls in the page's control tree excluding the page itself private IEnumerable GetControlTree(Control root) { foreach (Control child in root.Controls) { yield return child; foreach (Control c in GetControlTree(child)) { yield return c; } } } // Build up each control in the page's control tree private void OnPageInitComplete(object sender, EventArgs e) { Page page = (Page)sender; IUnityContainer container = HttpContext.Current.Application.GetContainer(); foreach (Control c in GetControlTree(page)) { container.BuildUp(c.GetType(), c); } } } }
Here's an example of one of my service classes.
namespace PIA35.Services { public class CategoryService : ICategoryService { #region Dependency Injection private ICategoryDao categoryDao; public CategoryService(ICategoryDao CategoryDao) { this.categoryDao = CategoryDao; } #endregion #region ICategoryService Members public List GetAll() { return categoryDao.GetAll().ToList(); } public Category GetById(int CategoryId) { return categoryDao.GetById(CategoryId); } public void Add(Category model) { categoryDao.Insert(model); } public void Update(Category model) { categoryDao.Update(model); } public void Delete(Category model) { categoryDao.Delete(model); } #endregion } }
I see it has already been answered but just thought I would point out that you are synchronising all the calls to GetContainer with your locking pattern. A call to Application.Lock() actually takes out a write lock on the applicationState which is a singleton object in your web application and you will see issues if you want to scale this.
To tidy this up you could do a double checked lock. like this:
public static IUnityContainer GetContainer(this HttpApplicationState application)
{
IUnityContainer container = application[GlobalContainerKey] as IUnityContainer;
if (container == null)
{
application.Lock();
try
{
container = application[GlobalContainerKey] as IUnityContainer;
if (container == null)
{
container = new UnityContainer();
application[GlobalContainerKey] = container;
}
}
finally
{
application.UnLock();
}
}
return container;
}
I would also like to point out a neat pattern that we have used to ensure Controls and Pages have their Dependencies built up. We basically have a Generic PageBase and Generic ControlBase that all our pages and controls inherit from. I will just go into the pagebase as an example:
public abstract class SitePageBase<T> : SitePageBase where T : SitePageBase<T>
{
protected override void OnInit( EventArgs e )
{
BuildUpDerived();
base.OnInit( e );
}
protected void BuildUpDerived()
{
ContainerProvider.Container.BuildUp( this as T );
}
}
Then in our Pages we can simply derive from Generic base and it will look after the build up.
public partial class Default : SitePageBase<Default>
{
[Dependency]
public IContentService ContentService { get; set; }
protected override void OnPreRender( EventArgs e )
{
this.label.Text = ContentService.GetContent("labelText");
}
}
这篇关于Unity 和 ASP.NET WebForms - 没有为此对象定义无参数构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!