5

最近将 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>

视图/主页/Index.cshtml

ViewComponent LoginViewComponent/Default.cshtml只是一个显示其模型信息的类:

@model App.Components.LoginViewCompoent
<body>
    <div>@Html.DisplayFor(v=>v.LoginName)</div>
</body>

视图/共享/组件/LoginViewComponent/Default.cshtml

@model指令从Default.cshtml中删除时,它呈现良好。

ViewComponent 不是应该与包装它的父视图分离和不可知的吗?从异常看来,似乎需要在HomeViewModel类中声明LoginViewComponent ViewComponent才能呈现它。

在 asp.net core github 上找不到任何更改说明。

对此的评论和帮助将不胜感激。

4

3 回答 3

6

我遇到了同样的错误,我团队中的某个人将 Microsoft.AspNetCore.Mvc版本从 1.0.0 更新到 1.1.0,并且我在 Strongly-Type 视图中拥有的一些组件开始抛出

InvalidOperationException:传递给 ViewDataDictionary 的模型项的类型为'My.StronglyView.ObjectType',但此 ViewDataDictionary 实例需要一个'My.ViewComponent.ObjectType'类型的模型项。

我不确定这种变化是否是故意的,但这绝对不是我们所期望的。

我没有时间研究这种“破坏性”变化的原因,但我提出了一个解决方案。

问题是,如果你将一个空对象传递给你的ViewComponent.View()方法,我们就会得到这个异常。任何通过它的非空对象都会更新 ViewData.ModelExplorer,并且正确的对象类型将被注册,从而避免此异常。

使用 Tester-Doer 模式,与 .Net Framework 的某些类中使用的模式相同,我们现在可以将一个非空对象传递给ViewComponent并根据需要使用它及其包装的对象。

我所做的是,我创建了一个接口IViewComponentModel<T>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 类实现中,我返回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,它也不会从 View 中“继承”对象类型。

希望它有帮助!

于 2016-11-24T13:00:54.867 回答
1

简单的解决方案是,在 ViewComponent 类中检查视图模型是否为空,如果视图模型为空,则返回空内容结果如下:

public async Task<IViewComponentResult> InvokeAsync()
{
    var vm = some query for ViewModel;

    if(vm != null)
    {
        return View(vm);
    }

    return Content("");
}
于 2017-01-02T05:24:38.727 回答
0

默认情况下,它会尝试传入“父视图”的模型,不确定你会怎么称呼它,尝试像这样更新你的代码

 @Component.InvokeAsync("LoginViewComponent", new App.Components.LoginViewComponent())

这样局部视图就可以拥有它需要的东西,以便提供它的内容。

于 2016-11-21T15:22:36.660 回答