dav*_*ser 10 asp.net-mvc viewmodel automapper drop-down-menu
在阅读了ASP.NET MVC 2 in Action并观看Jimmy Bogard的MvcConf演讲(强烈推荐!)之后,我开始实现他们的一些想法.
他们做的很酷的事情之一,不仅是使用AutoMapper将您的实体映射到某个视图模型,而且还使用AutoMapViewResult自动执行此操作:
public class EventsController : BaseController
{
public ActionResult Show(Event id) // EntityModelBinder gets Event from repository
{
return AutoMapView<EventsShowModel>(id); // AutoMapView<T>(model) is a helper method on the BaseController, that calls AutoMapViewResult<T>(...)
}
}
// not exactly what you'll find in the book, but it also works :-)
public class AutoMapViewResult<TDestination> : ViewResult
{
public AutoMapViewResult(string viewName, string masterName, object model)
{
ViewName = viewName;
MasterName = masterName;
ViewData.Model = Mapper.Map(model, model.GetType(), typeof(TDestination));
}
}
Run Code Online (Sandbox Code Playgroud)
这一切都很好,但现在有一个Edit
动作EventsEditModel
:
public class EventsEditModel
{
// ... some properties ...
public int LocationId { get; set; }
public IList<SelectListItem> Locations { get; set; }
}
public class EventsController : BaseController
{
public ActionResult Edit(Event id)
{
return AutoMapView<EventsEditModel>(id);
}
}
Run Code Online (Sandbox Code Playgroud)
现在(最后)问题:
你觉得,是要得到某种数据源的位置,最好的办法,如仓库到EventsEditModel
的Locations
财产?
请记住,我想使用AutoMapViewResult
和许多不同的实体 - 视图模型组合.
更新:
我选择了Necros的想法并创建了一个自定义属性.您可以查看代码并将其下载到我的博客ASP.NET MVC:使用属性将选择列表的数据加载到编辑模型中.
我的解决方案是引入模型丰富器的概念,简单的类在将模型传递给View()之前"丰富"模型:
public class SiteSettingsModelEnricher : IModelEnricher<SiteSettingsModel>
{
private readonly IThemeProvider themeProvider;
public SiteSettingsModelEnricher(IThemeProvider themeProvider) {
this.themeProvider = themeProvider;
}
public SiteSettingsModel Enrich(SiteSettingsModel model) {
var themes = from t in themeProvider.GetThemes()
select new SelectListItem { Text = t, Value = t };
model.Themes = themes;
return model;
}
}
Run Code Online (Sandbox Code Playgroud)
我的AutoMapperViewResult ExecuteResult
方法看起来像:
public override void ExecuteResult(ControllerContext context) {
var model = Mapper.Map(this.Model, typeof(TSource), typeof(TDestination)) as TDestination;
// enrichers
var enricher = DependencyResolver.Current.GetService<IModelEnricher<TDestination>>();
if (enricher != null) {
model = enricher.Enrich(model);
}
this.ViewData.Model = model;
base.ExecuteResult(context);
}
Run Code Online (Sandbox Code Playgroud)
由于我还使用了Jimmy演示文稿中的FormActionResult,我还在返回Failure结果之前使用了richr.这意味着像选择列表这样的东西被重新绑定并保持超级干燥.
我在这里发布了一个基于上述内容的改进解决方案.
当我需要时,我还没有达到这一点(因为我看到了谈话),但我有一个可能的解决方案.我认为它可以创建一个属性,指定需要加载此属性.我将从一个抽象类开始:
public abstract class LoadDataAttribute : Attribute
{
public Type Type { get; set; }
protected LoadDataAttribute(Type type)
{
Type = type;
}
public abstract object LoadData();
}
Run Code Online (Sandbox Code Playgroud)
然后为要加载的每种类型创建特定版本(在您的案例中为位置)
public class LoadLocationsAttribute : LoadDataAttribute
{
public LoadLocationsAttribute() : base(typeof(IList<SelectListItem>))
public override object LoadData()
{
// get locations and return IList<SelectListItem>
}
}
Run Code Online (Sandbox Code Playgroud)
在你ExecuteResult
的AutoMappViewResult
,你会发现所有的属性LoadDataAttribute
,调用LoadData()
,投它在属性类型规定,并将其分配给属性.
我的情况你只想用这种方式加载选择列表,你可以只返回IList<SelectListItem>
而不是object
,并节省自己一些麻烦铸造.
您的视图模型显然会使用该属性.
public class EventsEditModel
{
// ... some properties ...
public int LocationId { get; set; }
[LoadLocations]
public IList<SelectListItem> Locations { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2433 次 |
最近记录: |