Asp.net mvc 如何将会话值与Unity和DependencyResolver一起使用
我正在使用MVC4和Unity 2.1。我的服务需要基于从会话状态检索到的凭据的服务密钥 我注册我的服务如下: 在我的网站中,当我需要一项服务时,我会使用一个服务定位器,该定位器使用会话中的凭据自动组合服务密钥Asp.net mvc 如何将会话值与Unity和DependencyResolver一起使用,asp.net-mvc,architecture,Asp.net Mvc,Architecture,我正在使用MVC4和Unity 2.1。我的服务需要基于从会话状态检索到的凭据的服务密钥 我注册我的服务如下: 在我的网站中,当我需要一项服务时,我会使用一个服务定位器,该定位器使用会话中的凭据自动组合服务密钥 public static T Resolve<T>(ServiceKey serviceKey = null) { if (serviceKey == null) { serviceKey = SessionM
public static T Resolve<T>(ServiceKey serviceKey = null)
{
if (serviceKey == null)
{
serviceKey = SessionManager.ServiceKey;
}
var parameterOverride = new ParameterOverride(SERVICEKEY_PARAMETERNAME, serviceKey);
return Resolve<T>(null, parameterOverride);
}
问题是MVC仍然抱怨在尝试实例化库存控制器时没有找到无参数构造函数。我想这是因为我还没有在Unity中注册服务密钥。但如果我尝试这样做,我发现MVC正在尝试在会话构建之前解析控制器,然后解析服务
我想得不对吗?每一步感觉都很合理——在服务中使用会话凭据,在控制器中使用服务,使用解析器帮助构建控制器——但我一直在竭尽全力让它发挥作用。你可以在Unity中使用InjectionFactory(Microsoft.Practices.Unity.InjectionFactory)指定一个函数来处理依赖项的解析。此函数仅在解决依赖关系时执行。在下面的示例中,“c”是作为参数传递的Unity容器,这样您就可以在函数中执行其他解析 替换:
container.RegisterType<IInventoryService, InventoryService>();
container.RegisterType();
与:
container.RegisterType(新注入工厂(c=>
新的InventoryService(SessionManager.ServiceKey));
使用Unity.Mvc4包似乎解决了这个问题,但我不清楚原因。但我决定添加一个无参数构造函数,根据需要手动解析自身,而不是使用另一个包来隐藏我的问题:
public InventoryController() : this (MvcDependencyFactory.Resolve<IInventoryService>(SessionManger.ServiceKey) { }
public InventoryController():此(MvcDependencyFactory.Resolve(SessionManger.ServiceKey){}
它仍然允许控制器的单元测试(通过注入)当调用无参数构造函数时,解析发生在何处是透明的。下面是一个自定义的IDependencyResolver,在我开始深入了解它的工作原理时,它相当直截了当,不同于IoC容器解析。您需要try/catch来捕获MVC尝试的IControl解析lerActivator(来源:)。如果无法解析IControllerActivator,则将查询您的自定义IDependencyResolver以查找控制器(它将使用您选择的IoC容器) 我将以下类添加到我的基本MVC4的App_Start文件夹中:
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
using Sample.Web.Controllers;
namespace Sample.Web.App_Start
{
public static class UnityConfig
{
public static void ConfigureContainer()
{
IUnityContainer container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
container.RegisterType<IHomeService>(new InjectionFactory( c =>
new HomeService("this string is a dependency.")));
container.RegisterType<IController, HomeController>("Home");
return container;
}
}
public class UnityDependencyResolver : IDependencyResolver
{
private readonly IUnityContainer _container;
public UnityDependencyResolver(IUnityContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
}
}
以下是我的宏伟蓝图:
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>@ViewBag.SomeData</p>
@{
ViewBag.Title=“Index”;
}
指数
@ViewBag.SomeData
很有趣。这有助于澄清问题,尽管我仍然会遇到一个错误,即即使在替换了那行代码之后也找不到无参数构造函数。这可能超出了这个问题的范围,因为会话数据现在似乎已经得到了解释。也许是我的依赖关系图中的其他内容。你不应该这样做使用无参数构造函数。您应该通过IoC容器解析对象,并让它注入依赖项(以及依赖项的依赖项等)。“container.resolve();”将返回带有服务密钥的InventoryService。如果您想要无参数构造函数,还可以注入属性值。我个人更喜欢构造函数注入,但以下链接应该有助于选择:对,这就是令人费解的地方。我的InventoryController上没有无参数构造函数——我注入服务,这反过来又需要一个服务密钥。您关于注入工厂的观点似乎解决了服务的会话问题,但MVC仍在抱怨InventoryController上没有无参数构造函数(这是真的……但考虑到Unity的使用,这不应该是个问题).无论如何,我需要为一个即将到来的项目做这件事,所以今晚我将进一步深入研究这件事。同时,看看这个实验室是否有帮助:…别忘了从Global.asax.cs=)中调用UnityConfig)
container.RegisterType<IInventoryService, InventoryService>();
container.RegisterType<IInventoryService>(new InjectionFactory(c =>
new InventoryService(SessionManager.ServiceKey)));
public InventoryController() : this (MvcDependencyFactory.Resolve<IInventoryService>(SessionManger.ServiceKey) { }
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
using Sample.Web.Controllers;
namespace Sample.Web.App_Start
{
public static class UnityConfig
{
public static void ConfigureContainer()
{
IUnityContainer container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
container.RegisterType<IHomeService>(new InjectionFactory( c =>
new HomeService("this string is a dependency.")));
container.RegisterType<IController, HomeController>("Home");
return container;
}
}
public class UnityDependencyResolver : IDependencyResolver
{
private readonly IUnityContainer _container;
public UnityDependencyResolver(IUnityContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
}
}
using System.Web.Mvc;
namespace Sample.Web.Controllers
{
public class HomeController : Controller
{
private readonly IHomeService _service;
public HomeController(IHomeService service)
{
_service = service;
}
public ActionResult Index()
{
ViewBag.SomeData = _service.GetSomeData();
return View();
}
}
public interface IHomeService
{
string GetSomeData();
}
public class HomeService : IHomeService
{
private readonly string _data;
public HomeService(string data)
{
_data = data;
}
public string GetSomeData()
{
return _data;
}
}
}
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>@ViewBag.SomeData</p>