InvalidOperationException 在强类型视图中渲染 ViewComponent
InvalidOperationException rendering ViewComponent in Strongly-Typed View
最近将 dotnet core 1.0.1 更新为 1.1,MVC 中的 ViewComponent 开始失败,出现以下异常:
InvalidOperationException: One or more errors occurred. (The model item passed into the ViewDataDictionary is of type 'App.Models.HomeViewModel', but this ViewDataDictionary instance requires a model item of type 'App.Components.LoginViewComponent'.)
Index.cshtml 呈现 LoginViewComponent:
@model App.Models.HomeViewModel
<html>
@Component.InvokeAsync("LoginViewComponent")
</html>
Views/Home/Index.cshtml
ViewComponent LoginViewComponent/Default.cshtml 只是一个显示模型信息的 class:
@model App.Components.LoginViewCompoent
<body>
<div>@Html.DisplayFor(v=>v.LoginName)</div>
</body>
视图/共享/组件/LoginViewComponent/Default.cshtml
当从 Default.cshtml.
中删除 @model 指令时,它呈现得很好
难道 ViewComponent 不应该与包装它的父视图分离且不可知吗?从异常来看,似乎需要在 HomeViewModel class 中声明 LoginViewComponent ViewComponent 才能呈现它。
在 asp.net 核心 github 上找不到关于此的任何更改说明。
对此发表评论和提供帮助将不胜感激。
默认情况下它会尝试传入 "Parent View" 的模型,不知道你会怎么称呼它,尝试像这样更新你的代码
@Component.InvokeAsync("LoginViewComponent", new App.Components.LoginViewComponent())
以便部分视图可以拥有它需要的内容,以便提供它的内容。
我遇到了同样的错误,我团队中有人将 Microsoft.AspNetCore.Mvc
版本从 1.0.0 更新到 1.1.0,我在强类型视图中的一些组件开始抛出
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'My.StronglyView.ObjectType', but this ViewDataDictionary instance requires a model item of type 'My.ViewComponent.ObjectType'.
我不确定此更改是否是有意的,但这绝对不是我们所期望的。
我没有时间研究这个 'breaking' 变化的原因,但我想出了一个解决方案。
事实是,如果您将 null 对象传递给 ViewComponent.View()
方法,我们会得到此异常。任何通过它的非空对象都会更新 ViewData.ModelExplorer 并且正确的 object-type 会被注册,避免这个异常。
使用 Tester-Doer 模式,与 .Net Framework 的某些 classes 中使用的相同模式,我们现在可以将非空对象传递给 ViewComponent
并使用它及其包装的对象正如我们所需要的。
我所做的是,我创建了一个接口 IViewComponentModel<T>
作为 class ViewComponentModel<T>
如下:
// Interface for ViewComponentModel
public interface IViewComponentModel<T>
where T : class
{
T Data { get; }
bool HasData();
}
// ViewComponentModel class for the Strongly-Type View Component
public class ViewComponentModel<T> : IViewComponentModel<T>
where T : class
{
public T Data { get; private set; }
public ViewComponentModel(T data)
{
Data = data;
}
public bool HasData() => Data != null;
}
在我的 ViewComponent class 实现中,我 return View(new ViewComponentModel<AnyReferenceType>(myModel));
public async Task<IViewComponentResult> InvokeAsync()
{
var myViewData = _myService.GetSomeObjectForMyViewComponent();
var model = new ViewComponentModel<MyViewDataType>(myViewData);
return await Task.FromResult(View(model));
}
最后,在我的组件视图 (.cshtml) 中,我有以下代码:
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@model ViewComponentModel<MyViewDataType>
现在您可以在视图中使用此对象做任何您想做的事情,并使用您的真实模型,只需调用 @Model.Data
即可。
这样,我们将永远不会将空对象传递给 ViewComponent,也不会 'inherit' 来自 View 的对象类型。
希望对您有所帮助!
简单的解决方案是,在ViewComponent中class检查视图模型是否为空,如果视图模型为空,则return空内容结果如下:
public async Task<IViewComponentResult> InvokeAsync()
{
var vm = some query for ViewModel;
if(vm != null)
{
return View(vm);
}
return Content("");
}
最近将 dotnet core 1.0.1 更新为 1.1,MVC 中的 ViewComponent 开始失败,出现以下异常:
InvalidOperationException: One or more errors occurred. (The model item passed into the ViewDataDictionary is of type 'App.Models.HomeViewModel', but this ViewDataDictionary instance requires a model item of type 'App.Components.LoginViewComponent'.)
Index.cshtml 呈现 LoginViewComponent:
@model App.Models.HomeViewModel
<html>
@Component.InvokeAsync("LoginViewComponent")
</html>
Views/Home/Index.cshtml
ViewComponent LoginViewComponent/Default.cshtml 只是一个显示模型信息的 class:
@model App.Components.LoginViewCompoent
<body>
<div>@Html.DisplayFor(v=>v.LoginName)</div>
</body>
视图/共享/组件/LoginViewComponent/Default.cshtml
当从 Default.cshtml.
中删除 @model 指令时,它呈现得很好难道 ViewComponent 不应该与包装它的父视图分离且不可知吗?从异常来看,似乎需要在 HomeViewModel class 中声明 LoginViewComponent ViewComponent 才能呈现它。
在 asp.net 核心 github 上找不到关于此的任何更改说明。
对此发表评论和提供帮助将不胜感激。
默认情况下它会尝试传入 "Parent View" 的模型,不知道你会怎么称呼它,尝试像这样更新你的代码
@Component.InvokeAsync("LoginViewComponent", new App.Components.LoginViewComponent())
以便部分视图可以拥有它需要的内容,以便提供它的内容。
我遇到了同样的错误,我团队中有人将 Microsoft.AspNetCore.Mvc
版本从 1.0.0 更新到 1.1.0,我在强类型视图中的一些组件开始抛出
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'My.StronglyView.ObjectType', but this ViewDataDictionary instance requires a model item of type 'My.ViewComponent.ObjectType'.
我不确定此更改是否是有意的,但这绝对不是我们所期望的。
我没有时间研究这个 'breaking' 变化的原因,但我想出了一个解决方案。
事实是,如果您将 null 对象传递给 ViewComponent.View()
方法,我们会得到此异常。任何通过它的非空对象都会更新 ViewData.ModelExplorer 并且正确的 object-type 会被注册,避免这个异常。
使用 Tester-Doer 模式,与 .Net Framework 的某些 classes 中使用的相同模式,我们现在可以将非空对象传递给 ViewComponent
并使用它及其包装的对象正如我们所需要的。
我所做的是,我创建了一个接口 IViewComponentModel<T>
作为 class ViewComponentModel<T>
如下:
// Interface for ViewComponentModel
public interface IViewComponentModel<T>
where T : class
{
T Data { get; }
bool HasData();
}
// ViewComponentModel class for the Strongly-Type View Component
public class ViewComponentModel<T> : IViewComponentModel<T>
where T : class
{
public T Data { get; private set; }
public ViewComponentModel(T data)
{
Data = data;
}
public bool HasData() => Data != null;
}
在我的 ViewComponent class 实现中,我 return View(new ViewComponentModel<AnyReferenceType>(myModel));
public async Task<IViewComponentResult> InvokeAsync()
{
var myViewData = _myService.GetSomeObjectForMyViewComponent();
var model = new ViewComponentModel<MyViewDataType>(myViewData);
return await Task.FromResult(View(model));
}
最后,在我的组件视图 (.cshtml) 中,我有以下代码:
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@model ViewComponentModel<MyViewDataType>
现在您可以在视图中使用此对象做任何您想做的事情,并使用您的真实模型,只需调用 @Model.Data
即可。
这样,我们将永远不会将空对象传递给 ViewComponent,也不会 'inherit' 来自 View 的对象类型。
希望对您有所帮助!
简单的解决方案是,在ViewComponent中class检查视图模型是否为空,如果视图模型为空,则return空内容结果如下:
public async Task<IViewComponentResult> InvokeAsync()
{
var vm = some query for ViewModel;
if(vm != null)
{
return View(vm);
}
return Content("");
}