我找到了一种方法来实现我的 ViewData / ViewModel 方法,而不会过多地使用 ASP.NET MVC。
我是这样做的:
这是我的ViewPage2
类,它将强类型的 ViewData 对象公开给视图。不幸的是,您确实需要使用反射来避免 ViewPage 创建全新 ViewDataDictionary 的行为,但是对于静态缓存的 FieldInfo 对象,它并不比 MVC 在路由中的动态控制器/动作查找更昂贵。
public class ViewPage2<TModel,TData> : ViewPage<TModel> where TData : ViewDataDictionary<TModel> {
public ViewPage2() : base() {
}
private Boolean _dataPresent;
private TData _data;
public new TData ViewData {
get {
if( _dataPresent && _data == null ) {
_data = (TData)base.ViewData;
}
return _data;
}
}
// Cached in static class state for performance.
private static readonly FieldInfo _viewPage1ViewData;
private static readonly FieldInfo _viewPage2ViewData;
static ViewPage2() {
Type viewPage1 = typeof(ViewPage<TModel>);
_viewPage1ViewData = viewPage1.GetField("_viewData", BindingFlags.Instance | BindingFlags.NonPublic );
Type viewPage2 = typeof(ViewPage);
_viewPage2ViewData = viewPage2.GetField("_viewData", BindingFlags.Instance | BindingFlags.NonPublic );
}
protected override void SetViewData(ViewDataDictionary viewData) {
// ViewPage<TModel> creates a new ViewDataDictionary<TModel> when this method is called, even if viewData is of the correct type.
// The trick is to reimplement SetViewData and set base._viewData and basebase._viewData
if( viewData is TData ) {
_viewPage1ViewData.SetValue( this, viewData );
_viewPage2ViewData.SetValue( this, viewData );
_dataPresent = true;
} else {
base.SetViewData( viewData );
}
}
}
然后对于每个 *.aspx 文件(我使用 WebFormViewEngine),我只需更改@Page
指令:
<%@ Page Language="C#" MasterPageFile="~/Site.Master" Inherits="Me.ViewPage2<Me.FormModel,Me.FormData>" %>
我承认这两个泛型类型说明符使它有点繁琐,但你只需要设置一次。
然后在每个控制器中,只需这样做:
public ActionResult Edit() {
FormData data = new FormData();
data.SomeStronglyTypedField = "foo";
this.ViewData = data;
}
在每个视图中,您现在都可以从强类型视图数据中受益:
<p><%= ViewData.SomeStronglyTypedField %></p>
由于 ViewData 不是模型的一部分,因此在处理 POST 提交的数据时关注点分离以及自动绑定的好处:
[HttpPost]
public ActionResult Edit(EditModel model) {
if( !ModelState.IsValid ) {
// See how I can return the model object without modifying it. All I need to do is re-create the View data.
FormData data = new FormData();
data.SomeStronglyTypedField = "foo";
this.ViewData = data;
return View( model );
}
// persist to DB here
return RedirectToAction("View");
}
在实践中,我使用一个通用的 BaseController 类来处理 ViewData 对象的自动创建和设置,因此我不需要FormData data...
在每个操作中使用这三行(等)。