C# ASP.NET MVC自动模型实例化(如果未提供模型)
我试图在视图模型未给定时(当它们为空时)实现视图模型的自动实例化 控制器动作 SomeView.cshtmlC# ASP.NET MVC自动模型实例化(如果未提供模型),c#,asp.net,asp.net-mvc,view,model,C#,Asp.net,Asp.net Mvc,View,Model,我试图在视图模型未给定时(当它们为空时)实现视图模型的自动实例化 控制器动作 SomeView.cshtml @model Models.SomeModel//根据此类型。。。 @模型名称 //…当@Model为空时自动实例化它 我试图覆盖RazorViewEngine,但在ViewEngine时,我似乎(可能是错的)无法访问模型类型,它始终为null,即使提供了它。我应该能够了解空模型的类型,因为我们正在尝试实例化它,所以应该有另一个元数据,让我们获得视图的模型类型 我尝试过扩展Defaul
@model Models.SomeModel//根据此类型。。。
@模型名称
//…当@Model为空时自动实例化它
我试图覆盖RazorViewEngine,但在ViewEngine时,我似乎(可能是错的)无法访问模型类型,它始终为null,即使提供了它。我应该能够了解空模型的类型,因为我们正在尝试实例化它,所以应该有另一个元数据,让我们获得视图的模型类型
我尝试过扩展DefaultModelBinder,但它似乎只用于从Http请求绑定模型,在手动创建视图时没有触发
我没有主意了。我希望这是可行的。在BorysG的帮助下,我们已经解决了这个问题,我还改进了它,使之能够与Partials一起工作 讨论: 在此处复制代码:
public class CustomViewEngine : RazorViewEngine
{
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
var view = base.CreatePartialView(controllerContext, partialPath);
return new ViewWrapper(view);
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
var view = base.CreateView(controllerContext, viewPath, masterPath);
return new ViewWrapper(view);
}
}
public class ViewWrapper : IView
{
protected IView View;
public ViewWrapper(IView view)
{
View = view;
}
public void Render(ViewContext viewContext, TextWriter writer)
{
//Type modelType = BuildManager.GetCompiledType(razorView.ViewPath);
var razorView = View as RazorView;
if (razorView != null)
{
//if we could not get the model object - try to get it from what is declared in view
var compiledViewType = BuildManager.GetCompiledType(razorView.ViewPath);
var model = viewContext.ViewData.Model;
Type baseType = compiledViewType.BaseType;
//model is passed as generic parameter, like this MyView1 : WebViewPage<MyModel1>
if (baseType != null && baseType.IsGenericType)
{
//and here the trick begins - extract type of model from generic arguments
var modelType = baseType.GetGenericArguments()[0]; //the same as typeof(MyModel1)
// ReSharper disable UseMethodIsInstanceOfType
//If model is null, or model is not type of the given model (for partials)
if (model == null || !modelType.IsAssignableFrom(model.GetType()))
// ReSharper restore UseMethodIsInstanceOfType
{
//Set @model and render the view
viewContext.ViewData.Model = Activator.CreateInstance(modelType);
}
}
}
View.Render(viewContext, writer);
}
}
为什么?这似乎是为了避免使用几次击键而付出的巨大努力。你假设这是几次击键,我的朋友,可能有数百个理由说明为什么有人需要这样做。如果我们问“为什么不敲几下键盘呢?”我们今天就不会有ASP.NET MVC了。然而,如果你真的想知道:我有很多局部视图,所有的HTML都被划分在项目中。我不想通过Html.Partial('x.cshtml',new Model())在视图文件中实例化几十个视图模型。我不想在模型中混用它们,因为它们在很多地方都有使用。我还将通过Html.Partial添加自动视图包含,并且我希望摆脱模型实例化。您在问题中没有提到任何关于Partials的内容。分部的工作方式与视图的工作方式非常不同。任何适用于视图的解决方案都不适用于局部视图。在任何情况下,您如何期望某些代码神奇地知道实例化视图模型所需的内容?您当然可以编写一个函数来解析视图,并查找@model语句,然后动态实例化它,但这只适用于不需要额外设置的简单模型。几乎不值得为只使用10%代码的东西付出努力。此外,您通常不需要实例化默认模型,因为Html助手函数在大多数情况下为您处理空模型,而在它们不处理空模型的情况下,你必须使用无法自动实例化的自定义配置。我不喜欢你“它不工作/不值得/需要”的人。我们解决了它,请参见下面的答案。
@model Models.SomeModel //According to this type...
<h2>@Model.Title</h2>
//...auto instantiate @Model when it is null
public class CustomViewEngine : RazorViewEngine
{
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
var view = base.CreatePartialView(controllerContext, partialPath);
return new ViewWrapper(view);
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
var view = base.CreateView(controllerContext, viewPath, masterPath);
return new ViewWrapper(view);
}
}
public class ViewWrapper : IView
{
protected IView View;
public ViewWrapper(IView view)
{
View = view;
}
public void Render(ViewContext viewContext, TextWriter writer)
{
//Type modelType = BuildManager.GetCompiledType(razorView.ViewPath);
var razorView = View as RazorView;
if (razorView != null)
{
//if we could not get the model object - try to get it from what is declared in view
var compiledViewType = BuildManager.GetCompiledType(razorView.ViewPath);
var model = viewContext.ViewData.Model;
Type baseType = compiledViewType.BaseType;
//model is passed as generic parameter, like this MyView1 : WebViewPage<MyModel1>
if (baseType != null && baseType.IsGenericType)
{
//and here the trick begins - extract type of model from generic arguments
var modelType = baseType.GetGenericArguments()[0]; //the same as typeof(MyModel1)
// ReSharper disable UseMethodIsInstanceOfType
//If model is null, or model is not type of the given model (for partials)
if (model == null || !modelType.IsAssignableFrom(model.GetType()))
// ReSharper restore UseMethodIsInstanceOfType
{
//Set @model and render the view
viewContext.ViewData.Model = Activator.CreateInstance(modelType);
}
}
}
View.Render(viewContext, writer);
}
}
//remove default Razor and WebForm view engines
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomViewEngine());