使用 Asp.Net MVC 5 框架和 IoC 容器时如何构建视图模型的实例?
How to construct an instance of a view-model when using Asp.Net MVC 5 framework and IoC container?
我正在使用 ASP.NET MVC 5 框架和 Unity-Container 编写一个项目来处理我的依赖项。
我正在寻找一种最佳实践来处理在 Asp.Net MVC 5 应用程序中使用 IoC
容器时构建视图模型。我希望这个问题不被视为基于意见并被关闭。
我有以下视图模型class
public class CategoryReportViewModel
{
public IUnitOfWork UnitOfWork { get; set; }
public IEnumerable<object> Records { get; set; }
// ....
public TasksSummaryByProductViewModel(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
public void SetFilters()
{
// Do something.....
UnitOfWork.....
}
public void SetData()
{
// Do something.....
Records = UnitOfWork.....
}
}
如您所见,我的 CategoryReportViewModel
class 需要一个 IUnitOfWork
的实例来允许我的方法执行它们的任务 "unless I manually pass the IUnitOfWork
to every method that needs it." 我想知道什么是新建 CategoryReportViewModel
实例的正确方法。是通过 IoC
容器还是通过从构造函数传递 IUnitOfWork
的实例来使用旧方法?
换句话说,使用我的视图模型的正确方法是什么?
以下是尝试处理这种情况时想到的方法,但哪种方法是正确的?也许还有其他选择?
一、老手新涨攻略
public class ReportsController : Controller
{
protected IUnitOfWork UnitOfWork { get; set; }
public ReportsController(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
[HttpGet]
public ActionResult CategoryByName()
{
var viewModel = new CategoryReportViewModel(UnitOfWork);
viewModel.SetFilters();
return View(viewModel);
}
[HttpPost, ValidateAntiForgeryToken]
public ActionResult CategoryByName(CategoryReportViewModel viewModel)
{
viewModel.UnitOfWork = UnitOfWork; // This is ugly
if (ModelState.IsValid)
{
viewModel.SetData();
}
viewModel.SetFilters();
return View(viewModel);
}
}
其次,手动新建,但将 UnitOfWork
传递给任何需要它的方法
public class ReportsController : Controller
{
protected IUnitOfWork UnitOfWork { get; set; }
public ReportsController(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
[HttpGet]
public ActionResult CategoryByName()
{
var viewModel = new CategoryReportViewModel();
viewModel.SetFilters();
return View(viewModel);
}
[HttpPost, ValidateAntiForgeryToken]
public ActionResult CategoryByName(CategoryReportViewModel viewModel)
{
if (ModelState.IsValid)
{
viewModel.SetData(UnitOfWork);
}
viewModel.SetFilters(UnitOfWork);
return View(viewModel);
}
}
三、注册CategoryReportViewModel
后使用IoC
容器。但这将需要我修改 Asp.Net MVC 5 默认行为,因为我的视图模型 may/does 没有默认构造函数。
public class ReportsController : Controller
{
[HttpGet]
public ActionResult CategoryByName()
{
var viewModel = DependencyResolver.Current.GetService<CategoryReportViewModel>();
viewModel.SetFilters();
return View(viewModel);
}
// This will now work since I my view-model does not have a default constructor
// unless I override the `DefaultModelBinder` class somehow to resolve the class
// from the IoC container
[HttpPost, ValidateAntiForgeryToken]
public ActionResult CategoryByName(CategoryReportViewModel viewModel)
{
if (ModelState.IsValid)
{
viewModel.SetData();
}
viewModel.SetFilters();
return View(viewModel);
}
}
在这方面有不同方法和意见的空间,但我发现最有效的模式是使 ViewModel 成为 "dumb" DTO,其属性由控制器创建和填充。将服务注入控制器,并在您的操作方法中包含所有业务逻辑。
换句话说,SetFilters()
和SetData()
应该是在控制器上,并以模型为参数。
public class ReportsController : Controller
{
protected IUnitOfWork UnitOfWork { get; set; }
public ReportsController(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
[HttpGet]
public ActionResult CategoryByName()
{
var viewModel = new CategoryReportViewModel();
this.SetFilters(viewModel);
return View(viewModel);
}
[HttpPost, ValidateAntiForgeryToken]
public ActionResult CategoryByName(CategoryReportViewModel viewModel)
{
if (ModelState.IsValid)
{
this.SetData(viewModel);
}
this.SetFilters(viewModel);
return View(viewModel);
}
private void SetFilters(CategoryReportViewModel viewModel)
{
// Do something.....
UnitOfWork.....
}
private void SetData(CategoryReportViewModel viewModel)
{
// Do something.....
Records = UnitOfWork.....
}
}
我正在使用 ASP.NET MVC 5 框架和 Unity-Container 编写一个项目来处理我的依赖项。
我正在寻找一种最佳实践来处理在 Asp.Net MVC 5 应用程序中使用 IoC
容器时构建视图模型。我希望这个问题不被视为基于意见并被关闭。
我有以下视图模型class
public class CategoryReportViewModel
{
public IUnitOfWork UnitOfWork { get; set; }
public IEnumerable<object> Records { get; set; }
// ....
public TasksSummaryByProductViewModel(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
public void SetFilters()
{
// Do something.....
UnitOfWork.....
}
public void SetData()
{
// Do something.....
Records = UnitOfWork.....
}
}
如您所见,我的 CategoryReportViewModel
class 需要一个 IUnitOfWork
的实例来允许我的方法执行它们的任务 "unless I manually pass the IUnitOfWork
to every method that needs it." 我想知道什么是新建 CategoryReportViewModel
实例的正确方法。是通过 IoC
容器还是通过从构造函数传递 IUnitOfWork
的实例来使用旧方法?
换句话说,使用我的视图模型的正确方法是什么?
以下是尝试处理这种情况时想到的方法,但哪种方法是正确的?也许还有其他选择?
一、老手新涨攻略
public class ReportsController : Controller
{
protected IUnitOfWork UnitOfWork { get; set; }
public ReportsController(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
[HttpGet]
public ActionResult CategoryByName()
{
var viewModel = new CategoryReportViewModel(UnitOfWork);
viewModel.SetFilters();
return View(viewModel);
}
[HttpPost, ValidateAntiForgeryToken]
public ActionResult CategoryByName(CategoryReportViewModel viewModel)
{
viewModel.UnitOfWork = UnitOfWork; // This is ugly
if (ModelState.IsValid)
{
viewModel.SetData();
}
viewModel.SetFilters();
return View(viewModel);
}
}
其次,手动新建,但将 UnitOfWork
传递给任何需要它的方法
public class ReportsController : Controller
{
protected IUnitOfWork UnitOfWork { get; set; }
public ReportsController(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
[HttpGet]
public ActionResult CategoryByName()
{
var viewModel = new CategoryReportViewModel();
viewModel.SetFilters();
return View(viewModel);
}
[HttpPost, ValidateAntiForgeryToken]
public ActionResult CategoryByName(CategoryReportViewModel viewModel)
{
if (ModelState.IsValid)
{
viewModel.SetData(UnitOfWork);
}
viewModel.SetFilters(UnitOfWork);
return View(viewModel);
}
}
三、注册CategoryReportViewModel
后使用IoC
容器。但这将需要我修改 Asp.Net MVC 5 默认行为,因为我的视图模型 may/does 没有默认构造函数。
public class ReportsController : Controller
{
[HttpGet]
public ActionResult CategoryByName()
{
var viewModel = DependencyResolver.Current.GetService<CategoryReportViewModel>();
viewModel.SetFilters();
return View(viewModel);
}
// This will now work since I my view-model does not have a default constructor
// unless I override the `DefaultModelBinder` class somehow to resolve the class
// from the IoC container
[HttpPost, ValidateAntiForgeryToken]
public ActionResult CategoryByName(CategoryReportViewModel viewModel)
{
if (ModelState.IsValid)
{
viewModel.SetData();
}
viewModel.SetFilters();
return View(viewModel);
}
}
在这方面有不同方法和意见的空间,但我发现最有效的模式是使 ViewModel 成为 "dumb" DTO,其属性由控制器创建和填充。将服务注入控制器,并在您的操作方法中包含所有业务逻辑。
换句话说,SetFilters()
和SetData()
应该是在控制器上,并以模型为参数。
public class ReportsController : Controller
{
protected IUnitOfWork UnitOfWork { get; set; }
public ReportsController(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
[HttpGet]
public ActionResult CategoryByName()
{
var viewModel = new CategoryReportViewModel();
this.SetFilters(viewModel);
return View(viewModel);
}
[HttpPost, ValidateAntiForgeryToken]
public ActionResult CategoryByName(CategoryReportViewModel viewModel)
{
if (ModelState.IsValid)
{
this.SetData(viewModel);
}
this.SetFilters(viewModel);
return View(viewModel);
}
private void SetFilters(CategoryReportViewModel viewModel)
{
// Do something.....
UnitOfWork.....
}
private void SetData(CategoryReportViewModel viewModel)
{
// Do something.....
Records = UnitOfWork.....
}
}