使用Unity创建视图和视图模型
使用Unity作为依赖注入容器与使用MEF类似,并且支持基于属性和基于构造函数的注入.主要区别在于通常不会在运行时隐式发现类型; 相反,他们必须在容器中注册.
通常,您在视图模型上定义接口,以便视图模型的特定具体类型可以与视图分离.例如,视图可以通过构造函数参数定义其对视图模型的依赖性,如此处所示.C#
Run Code Online (Sandbox Code Playgroud)public QuestionnaireView() { InitializeComponent(); } public QuestionnaireView(QuestionnaireViewModel viewModel) : this() { this.DataContext = viewModel; }默认的无参数构造函数是允许视图在设计时工具(如Visual Studio和Expression Blend)中工作所必需的.
或者,您可以在视图上定义只写视图模型属性,如此处所示.Unity将实例化所需的视图模型,并在实例化视图后调用属性setter.C#
Run Code Online (Sandbox Code Playgroud)public QuestionnaireView() { InitializeComponent(); } [Dependency] public QuestionnaireViewModel ViewModel { set { this.DataContext = value; } }视图模型类型已在Unity容器中注册,如此处所示.C#
Run Code Online (Sandbox Code Playgroud)IUnityContainer container; container.RegisterType<QuestionnaireViewModel>();然后可以通过容器实例化视图,如此处所示.C#
Run Code Online (Sandbox Code Playgroud)IUnityContainer container; var view = container.Resolve<QuestionnaireView>();
如果我省略了有关注册ViewModel和实例化View的代码的最后部分,并且只使用将ViewModel挂钩到View的两种方法中的任何一种(使用构造函数或使用属性),那么看起来是ViewModel和View似乎一切都运转良好.那么注册ViewModel并实例化View的代码需要什么?
第一个例子,使用构造函数挂钩View和ViewModel,没有提到所有的Unity,所以Unity实际上在这里使用了吗?
使用基于属性的注射比使用基于construtor的注射有任何优势还是它们完全相同?
文本的第一部分说"*通常,您在视图模型上定义一个接口,以便视图模型的特定具体类型可以与视图分离",然后给出一个示例.然而,这个例子根本没有提到接口.这里发生了什么,我错过了什么吗?
嗨,我一直在努力告诉Unity,如果它有多个实现,我希望它将它们注入不同的类中.这就是我的意思:
比方说,我有一个接口IProductCatalogService和两个实现
ProductCatalog : IProductCatalogService和ProductCatalogService : IProductCatalogService.
我如何告诉Unity,对于类AI,我希望在我的构造函数中传递一个类型的实例,ProductCatalog而对于Class B我想要一个实例ProductCatalogService.
我在ASP.NET Web API项目中使用Unity,并在中设置了解析器GLobalConfiguration.
对于简单的1对1注册,一切正常.
这是我尝试过但它似乎不起作用:
public class DependencyServiceModel
{
public Type From { get; set; }
public Type To { get; set; }
public IEnumerable<Type> ForClasses { get; set; }
}
public void RegisterTypeForSpecificClasses(DependencyServiceModel dependencyService)
{
foreach (var forClass in dependencyService.ForClasses)
{
string uniquename = Guid.NewGuid().ToString();
Container.RegisterType(dependencyService.From,
dependencyService.To, uniquename);
Container.RegisterType(forClass, uniquename,
new InjectionConstructor(
new ResolvedParameter(dependencyService.To)));
}
}
Run Code Online (Sandbox Code Playgroud)
在DependencyServiceModel …
我正在尝试使用Unity容器来更轻松地对我的控制器进行单元测试.我的控制器使用一个接受Repository接口的构造函数.在global.asax文件中,我实例化一个UnityContainerFactory并将其注册到MVC框架,然后注册存储库及其实现.我将[Dependency]属性添加到控制器的CTOR Repository参数中.这一切似乎都可以正常工作,除了有时工厂的GetControllerInstance(Type controllerType)被多次调用并传递一个null参数作为controllerType.
对工厂的第一次调用是正确的,并且controllerType"ProductsController"作为参数传入.但有时候,在视图显示为控制器的空值后,工厂被调用了几次,我不知道为什么.当传递控制器类型的正确值时,"Call Stack"对我有意义,但是当传递null时,我不确定为什么或谁在进行调用.有任何想法吗?
该示例的代码和调用堆栈如下所示.
有效时调用堆栈
Test.DLL!Test.UnityHelpers.UnityControllerFactory.GetControllerInstance(System.Type controllerType = {Name ="ProductsController"FullName ="Test.Controllers.ProductsController"})第23行C#Test.DLL!Test._Default.Page_Load(object sender = {ASP.default_aspx},System.EventArgs e = {System.EventArgs})第18行+ 0x1a字节C#
在controllerType传递NULL时调用Stack
Test.DLL!Test.UnityHelpers.UnityControllerFactory.GetControllerInstance(System.Type controllerType = null)第27行C#
首先,我创建了一个UnityControllerFactory
public class UnityControllerFactory : DefaultControllerFactory
{
UnityContainer container;
public UnityControllerFactory(UnityContainer container)
{
this.container = container;
}
protected override IController GetControllerInstance(Type controllerType)
{
if (controllerType != null)
{
return container.Resolve(controllerType) as IController;
}
else
{
return null; // I never expect to get here, but I do sometimes, the callstack does not show the caller …Run Code Online (Sandbox Code Playgroud) 我非常熟悉Autofac,我非常喜欢Autofac的一个功能是注册模块.有谁知道我怎么能用Unity做到这一点?如果有的话,我很难找到在Google中使用哪些术语来提出相等的统一值.
public class Global : HttpApplication, IContainerProviderAccessor
{
private static IContainerProvider _containerProvider;
protected void Application_Start(object sender, EventArgs e)
{
var builder = new ContainerBuilder();
builder.RegisterModule(new MyWebModule());
_containerProvider = new ContainerProvider(builder.Build());
}
[...]
public IContainerProvider ContainerProvider
{
get { return _containerProvider; }
}
}
public class MyWebModule: Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterModule(new ApplicationModule());
builder.RegisterModule(new DomainModule());
}
}
public class ApplicationModule: Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(c => new ProductPresenter(c.Resolve<IProductView>()))
.As<ProductPresenter>()
.ContainerScoped();
}
}
我有一个问题,EF没有返回3层WPF应用程序中的最新数据,我怀疑它与我如何处理我的上下文的生命周期有关.这是场景:
UnitOfWork中包含几个存储库.还有一个服务(MyService),它使用UnitOfWork.还必须直接从UI调用此UnitOfWork,而不通过服务.
在我的主窗口的ViewModel中,我创建了一个新窗口(首先使用ViewModel):
var dialog = new DialogViewModel(_eventAggregator, _unitOfWork, Container.Resolve<CarService>());
Run Code Online (Sandbox Code Playgroud)
这个主窗口ViewModel有一个UnitOfWork,它已经在构造函数中注入,并传递给DialogViewModel.
CarService的构造函数也需要一个UnitOfWork,它也在它的构造函数中注入:
public CarService(IUnitOfWork unitOfWork){
_unitOfWork = unitOfWork;
}
Run Code Online (Sandbox Code Playgroud)
当在DialogViewModel中使用CarService进行查询以检索某些数据并进行一些更新时,它第一次正常工作.但是,当下次检索该数据时进行相同的查询,而不是返回最新的修改后的数据,它将返回旧的/缓存的数据.使用UnitOfWork(在CarService内部)的查询如下所示:
var values = _unitOfWork.GarageRepository.GetSomeValues();
_unitOfWork.GarageRepository.MakeSomeChangesToTheValuesUsingStoredProcedure();
Run Code Online (Sandbox Code Playgroud)
第二次调用它时,值不包含最新版本的数据; 但它已在DB中成功更新.
我正在使用Unity进行DI,这就是我的容器的样子:
public class Container
{
public static UnityContainer Container = new UnityContainer();
// Called once in the AppBoostraper, as soon as the GUI application starts
public void BuildUp()
{
Container.RegisterType<IUnitOfWork, UnitOfWork>();
Container.RegisterType<ICarService, CarService>();
}
}
Run Code Online (Sandbox Code Playgroud)
为什么不返回正确的数据,我该如何解决?
c# entity-framework dependency-injection unity-container unit-of-work
假设我有一个Simple Factory(SimpleProductFactory),它使用条件参数来确定如何创建Product如下:
public static class SimpleProductFactory
{
public static Product MakeProduct(Condition condition)
{
Product product;
switch(condition)
{
case Condition.caseA:
product = new ProductA();
// Other product setup code
break;
case Condition.caseA2:
product = new ProductA();
// Yet other product setup code
break;
case Condition.caseB:
product = new ProductB();
// Other product setup code
break;
}
return product;
}
}
Run Code Online (Sandbox Code Playgroud)
某个客户端使用此工厂来处理包含以下条件的运行时数据:
public class SomeClient
{
// ...
public void HandleRuntimeData(RuntimeData runtimeData)
{
Product product …Run Code Online (Sandbox Code Playgroud) 我想找到PerRequestLifetimeManager.在MSDN中,它表示它是Unity 3程序集的一部分.
我通过Nuget安装了Unity.Mvc4.package.config说我正在使用Unity 3.0:

该Microsoft.Practices.Unity.dll说我使用Unity 3.0

我使用对象浏览器查看了DLL内部,并且没有找到PerRequestLifetimeManager.
我在这里错过了什么吗?
如果有人会建议另一个类,我打算使用这里找到的自定义PerRequestLifetimeManager (如果我找不到该类).
编辑:
我已经卸载了Unity.Mvc4并直接在包控制台中安装了Unity3.0,这是我得到的:
PM> Install-Package Unity -version 3.0.1304.1
'Unity 3.0.1304.1' already installed.
Successfully added 'Unity 3.0.1304.1' to RedLions.Presentation.Web.
Run Code Online (Sandbox Code Playgroud)
我仍然找不到PerRequestLifetimeManager类,即使在官方库中也是如此.
尝试使用Unity.Mvc5和使用Identity 2.0和Identity 2.0 Samples样板的MVC 5应用程序配置Unity时,我得到以下异常.我已经阅读了这个SO 配置Unity DI的ASP.NET身份,我仍然不清楚我错过了什么.我在这做错了什么?
当前类型System.Data.Common.DbConnection是一个抽象类,无法构造.你错过了类型映射吗?
[ResolutionFailedException:依赖项的解析失败,type ="myApp.Web.Controllers.AccountController",name ="(none)".在解决时发生异常:
在例外时,容器是:
解析myApp.Web.Controllers.AccountController,(无)解析构造函数myApp.Web.Controllers.AccountController(myApp.Web.Models.ApplicationUserManager userManager)的参数"userManager"解析myApp.Web.Models.ApplicationUserManager,(无)解析参数构造函数myApp.Web.Models.ApplicationUserManager的"store"(Microsoft.AspNet.Identity.IUserStore 1[[myApp.Web.DAL.Profiles.ApplicationUser, myApp.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] store)
Resolving Microsoft.AspNet.Identity.EntityFramework.UserStore1 [myApp.Web.DAL.Profiles.ApplicationUser],(无)(从Microsoft.AspNet.Identity.IUserStore 1[myApp.Web.DAL.Profiles.ApplicationUser], (none))
Resolving parameter "context" of constructor Microsoft.AspNet.Identity.EntityFramework.UserStore1 [[myApp ]映射).Web.DAL.Profiles.ApplicationUser,myApp.Web,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]](System.Data.Entity.DbContext context)Resolving System.Data.Entity.DbContext,(none)解析构造函数System.Data.Entity.DbContext的参数"existingConnection"(System.Data.Common.DbConnection existingConnection,System.Data.Entity.Infrastructure.DbCompiledModel model,System.Boolean contextOwnsConnection)Resolving System.Data.Common.DbConnection,(没有)
帐户控制器,因为我已修改它
public AccountController(ApplicationUserManager userManager)
{
_userManager = userManager;
}
private ApplicationUserManager _userManager;
Run Code Online (Sandbox Code Playgroud)
我已注册的容器
container.RegisterType<ApplicationUserManager>(new HierarchicalLifetimeManager());
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new HierarchicalLifetimeManager());
Run Code Online (Sandbox Code Playgroud) asp.net-mvc dependency-injection unity-container asp.net-identity asp.net-identity-2
使用结构图,您可以注册一个约定,它不仅可以调整类型,还可以在对象创建期间进行干预.我怎么能用Unity做到这一点.
public class SettingsRegistration : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
if (!type.IsAbstract && typeof(ISettings).IsAssignableFrom(type))
{
registry.For(type).Use(x =>
{
var svc = x.GetInstance<ISettingService>();
return svc.LoadSetting(type);
});
}
}
}
Run Code Online (Sandbox Code Playgroud) 我可以使用此语句自动注册实现接口的所有类型
IUnityContainer container = new UnityContainer();
container.RegisterTypes(
AllClasses.FromAssembliesInBasePath(),
WithMappings.FromMatchingInterface,
WithName.Default,
WithLifetime.Transient);
ICustomer result = container.Resolve<ICustomer>();
Run Code Online (Sandbox Code Playgroud)
如何为接口和实现指定命名空间?
即:只有接口Framework.RepositoryInterfaces才能通过类型解析Framework.RepositoryImplementations.
unity-container ×10
c# ×8
.net ×2
asp.net-mvc ×2
conventions ×1
factory ×1
mvvm ×1
prism ×1
unit-of-work ×1
wpf ×1