如何在 WPF 中使用 DI 来拥有一个新实例而不询问容器
How to use DI in WPF to having a new istance without ask to container
我正在尝试使用 Simpleinjector 作为 IOC 容器从头开发 WPF 应用程序。
我是这个话题的新手,我有一些关于对象生命周期和正确热使用它们的问题。
我按照 simpleinjector 手册上的 WPF 集成指南启动了该应用程序。
但是我不明白每次服务需要时如何接收新实例
As i ask in my previous post 每次服务需要时,我都需要接收一个新的 unitOfWork。
正如@Steven 在我之前所说的 post
Do note that transient means "allways a new instance is resolved when it is requested from the container." If you're not requesting it again, you will be operating on the same instance, which might explain the ObjectDisposedException.
在 the other post 中,我找到了一个解决方案,但我认为它有点过于复杂,它是创建一个工厂并注入它而不是实例,因为我只想调用 container.getInstance通过将容器作为依赖项传递给启动方法而不是服务
这是我必须实现此目标的唯一方法,或者我不了解如何以 DI 方式开发?
代码示例:
public class HeaderViewModelFactory : IWpfRadDispenserViewModelFactory<HeaderviewModel>
{
private readonly ProductionService _service;
public HeaderViewModelFactory(ProductionService service)
{
_service = service;
}
public HeaderviewModel CreateViewModel()
{
return new HeaderviewModel(_service);
}
}
public class HeaderviewModel : ViewModelBase
{
private readonly ProductionService _service;
public HeaderviewModel(ProductionService service)
{
_service = service;
CreateData();
}
private void CreateData()
{
_service.CreateTestCycle();
}
}
public class CycleService : GenericDataService<Cycle>
{
private readonly IUnitOfWork<WpfRadDispenserDbContext> _uowContext;
public CycleService(IUnitOfWork<WpfRadDispenserDbContext> uowContext)
: base(uowContext)
{
_uowContext = uowContext;
}
public void CreateTestCycle()
{
var cycleDataService = new GenericDataService<Cycle>(_uowContext);
var vialDataService = new GenericDataService<Vial>(_uowContext);
Cycle c = new Cycle();
c.BatchName = "test";
Vial v = new Vial();
v.Name = "Test Vial";
c.Vials.Add(v);
_uowContext.CreateTransaction(IsolationLevel.ReadCommitted);
try
{
vialDataService.Create(v);
_uowContext.Persist();
var list = vialDataService.GetAll();
cycleDataService.Create(c);
_uowContext.Persist();
_uowContext.Commit();
}
catch (Exception e)
{
Console.WriteLine(e);
_uowContext.RollBack();
throw;
}
finally
{
_uowContext.Dispose();
}
}
}
private static Container Bootstrap()
{
// Create the container as usual.
var container = new Container();
// Register your types:
// Register your windows and view models:
container.Register<WpfRadDispenserDbContextFactory>(Lifestyle.Transient);
container.Register<IUnitOfWork<WpfRadDispenserDbContext>,WpfRadDispenserUOW>();
container.Register(typeof(CycleService));
container.Register<IWpfRadDispenserViewModelFactory<ProductionViewModel>,
ProductionViewModelFactory>(Lifestyle.Transient);
container.Register<IWpfRadDispenserViewModelFactory<AnagraphicViewModel>,
AnagraphicsViewModelFactory>(Lifestyle.Transient);
container.Register<IWpfRadDispenserViewModelFactory<HeaderviewModel>,
HeaderViewModelFactory>(Lifestyle.Transient);
container.Register<IViewModelAbstractFactory,
ViewModelAbstractFactory>(Lifestyle.Transient);
container.Register<INavigator, Navigator>(Lifestyle.Transient);
container.Register<MainWindowViewModel>();
container.Register<MainWindow>();
//container.Options.EnableAutoVerification = false;
//container.Verify();
return container;
}
以这种方式,每次我创建一个新的视图模型时,我都会收到相同的服务,而且很明显,dbcontext 不再存在,因为已处理。
这不是 rela 代码,只是我为了理解 DI 的工作原理而做的一个例子。
使用抽象工厂模式是最常见和推荐的方法。直接在应用程序中使用容器被广泛认为是 anti-pattern,就像服务定位器 (Service Locator is an Anti-Pattern) 一样,这是有充分理由的。
抽象工厂允许实例化对象,而无需引入与知道如何创建特定实例的实际实现的紧密耦合。
大多数 IoC 框架本身就支持这种模式。大多数时候,它们为工厂提供通用接口。您向容器注册实例(产品),框架将为您导出一个 ready-to 使用工厂。您将此框架接口的依赖项添加到您的对象,例如构造函数。然后注册通用工厂接口。该框架将自动创建工厂实例并将其注入相关实例,例如通过构造函数。
我对Simple Injector不是很熟悉,但是这个框架确实让事情变得简单了。没有这样的代码生成。
但是模式非常简单(这就是为什么它很容易自动化)而且一点也不复杂。
例子
动态创建类型实例所需的接口TInstance
:
interface IFactory<TInstance>
{
TInstance Create();
}
这个工厂的实现:
class SaveItemFactory : IFactory<ISaveItem>
{
ISaveItem Create() => new SaveItem();
}
需要动态创建依赖的类型:
interface IItemManager {}
class ItemManager : IItemManager
{
IFactory<ISaveItem> SaveItemFactory { get; }
public ItemManager(IFactory<ISaveItem> itemFactory) => this.SaveItemFactory = itemFactory;
public void SaveData(object data)
{
ISaveItem saveItem = this.SaveItemFactory.Create();
saveItem.SetData(data);
}
}
配置容器:
public void Run()
{
var container = new SimpleInjector.Container();
container.Register<IFactory<ISaveItem>, SaveItemFactory>(Lifestyle.Singleton);
container.Register<IItemManager, ItemManager>(Lifestyle.Singleton);
IItemManager itemManager = container.GetInstance<IItemManager>();
itemManager.SaveData("Some Data");
}
我正在尝试使用 Simpleinjector 作为 IOC 容器从头开发 WPF 应用程序。 我是这个话题的新手,我有一些关于对象生命周期和正确热使用它们的问题。
我按照 simpleinjector 手册上的 WPF 集成指南启动了该应用程序。 但是我不明白每次服务需要时如何接收新实例
As i ask in my previous post 每次服务需要时,我都需要接收一个新的 unitOfWork。
正如@Steven 在我之前所说的 post
Do note that transient means "allways a new instance is resolved when it is requested from the container." If you're not requesting it again, you will be operating on the same instance, which might explain the ObjectDisposedException.
在 the other post 中,我找到了一个解决方案,但我认为它有点过于复杂,它是创建一个工厂并注入它而不是实例,因为我只想调用 container.getInstance通过将容器作为依赖项传递给启动方法而不是服务
这是我必须实现此目标的唯一方法,或者我不了解如何以 DI 方式开发?
代码示例:
public class HeaderViewModelFactory : IWpfRadDispenserViewModelFactory<HeaderviewModel>
{
private readonly ProductionService _service;
public HeaderViewModelFactory(ProductionService service)
{
_service = service;
}
public HeaderviewModel CreateViewModel()
{
return new HeaderviewModel(_service);
}
}
public class HeaderviewModel : ViewModelBase
{
private readonly ProductionService _service;
public HeaderviewModel(ProductionService service)
{
_service = service;
CreateData();
}
private void CreateData()
{
_service.CreateTestCycle();
}
}
public class CycleService : GenericDataService<Cycle>
{
private readonly IUnitOfWork<WpfRadDispenserDbContext> _uowContext;
public CycleService(IUnitOfWork<WpfRadDispenserDbContext> uowContext)
: base(uowContext)
{
_uowContext = uowContext;
}
public void CreateTestCycle()
{
var cycleDataService = new GenericDataService<Cycle>(_uowContext);
var vialDataService = new GenericDataService<Vial>(_uowContext);
Cycle c = new Cycle();
c.BatchName = "test";
Vial v = new Vial();
v.Name = "Test Vial";
c.Vials.Add(v);
_uowContext.CreateTransaction(IsolationLevel.ReadCommitted);
try
{
vialDataService.Create(v);
_uowContext.Persist();
var list = vialDataService.GetAll();
cycleDataService.Create(c);
_uowContext.Persist();
_uowContext.Commit();
}
catch (Exception e)
{
Console.WriteLine(e);
_uowContext.RollBack();
throw;
}
finally
{
_uowContext.Dispose();
}
}
}
private static Container Bootstrap()
{
// Create the container as usual.
var container = new Container();
// Register your types:
// Register your windows and view models:
container.Register<WpfRadDispenserDbContextFactory>(Lifestyle.Transient);
container.Register<IUnitOfWork<WpfRadDispenserDbContext>,WpfRadDispenserUOW>();
container.Register(typeof(CycleService));
container.Register<IWpfRadDispenserViewModelFactory<ProductionViewModel>,
ProductionViewModelFactory>(Lifestyle.Transient);
container.Register<IWpfRadDispenserViewModelFactory<AnagraphicViewModel>,
AnagraphicsViewModelFactory>(Lifestyle.Transient);
container.Register<IWpfRadDispenserViewModelFactory<HeaderviewModel>,
HeaderViewModelFactory>(Lifestyle.Transient);
container.Register<IViewModelAbstractFactory,
ViewModelAbstractFactory>(Lifestyle.Transient);
container.Register<INavigator, Navigator>(Lifestyle.Transient);
container.Register<MainWindowViewModel>();
container.Register<MainWindow>();
//container.Options.EnableAutoVerification = false;
//container.Verify();
return container;
}
以这种方式,每次我创建一个新的视图模型时,我都会收到相同的服务,而且很明显,dbcontext 不再存在,因为已处理。
这不是 rela 代码,只是我为了理解 DI 的工作原理而做的一个例子。
使用抽象工厂模式是最常见和推荐的方法。直接在应用程序中使用容器被广泛认为是 anti-pattern,就像服务定位器 (Service Locator is an Anti-Pattern) 一样,这是有充分理由的。
抽象工厂允许实例化对象,而无需引入与知道如何创建特定实例的实际实现的紧密耦合。
大多数 IoC 框架本身就支持这种模式。大多数时候,它们为工厂提供通用接口。您向容器注册实例(产品),框架将为您导出一个 ready-to 使用工厂。您将此框架接口的依赖项添加到您的对象,例如构造函数。然后注册通用工厂接口。该框架将自动创建工厂实例并将其注入相关实例,例如通过构造函数。
我对Simple Injector不是很熟悉,但是这个框架确实让事情变得简单了。没有这样的代码生成。
但是模式非常简单(这就是为什么它很容易自动化)而且一点也不复杂。
例子
动态创建类型实例所需的接口TInstance
:
interface IFactory<TInstance>
{
TInstance Create();
}
这个工厂的实现:
class SaveItemFactory : IFactory<ISaveItem>
{
ISaveItem Create() => new SaveItem();
}
需要动态创建依赖的类型:
interface IItemManager {}
class ItemManager : IItemManager
{
IFactory<ISaveItem> SaveItemFactory { get; }
public ItemManager(IFactory<ISaveItem> itemFactory) => this.SaveItemFactory = itemFactory;
public void SaveData(object data)
{
ISaveItem saveItem = this.SaveItemFactory.Create();
saveItem.SetData(data);
}
}
配置容器:
public void Run()
{
var container = new SimpleInjector.Container();
container.Register<IFactory<ISaveItem>, SaveItemFactory>(Lifestyle.Singleton);
container.Register<IItemManager, ItemManager>(Lifestyle.Singleton);
IItemManager itemManager = container.GetInstance<IItemManager>();
itemManager.SaveData("Some Data");
}