尝试在局部视图上使用 ViewModel

Leo*_*ues 5 c# asp.net-core-mvc

因此,我正在使用身份验证模板编辑默认的 ASP.NET MVC,并且我正在尝试为其创建一个 ViewModel _PartialLogin.cshtml,以便显示名称而不是用户的电子邮件。我搜索了很多东西,但它们已经过时了,所以我希望有人能提供帮助。我什至不知道创建 ViewModel 是否是最佳选择。

这是LoginPartialViewModel

namespace AplicacaoRoles2.Models.SharedViewModels
{
    public class PartialLoginViewModel
    {
        [Required]
        public string Nome { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

_LoginPartial.cshtml

@using Microsoft.AspNetCore.Identity
@using AplicacaoRoles2.Models

@model AplicacaoRoles2.Models.SharedViewModels.PartialLoginViewModel

@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager

@if (SignInManager.IsSignedIn(User))
{
    <form asp-area="" asp-controller="Account" asp-action="Logout" method="post" id="logoutForm" class="navbar-right">
        <ul class="nav navbar-nav navbar-right">
            <li>
                <a asp-area="" asp-controller="Manage" asp-action="Index" title="Manage">Hello @Html.DisplayFor(model => model.Nome) !</a>
            </li>
Run Code Online (Sandbox Code Playgroud)

(...) HomeController

public class HomeController : Controller
{
    private readonly ApplicationDbContext _context;

    public HomeController(ApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<IActionResult> Index()
    {
        PartialLoginViewModel model = new PartialLoginViewModel();
        var userName = User.Identity.Name;
        var applicationUser = await _context.ApplicationUser.SingleOrDefaultAsync(m => m.UserName == userName);

        model.Nome = applicationUser.Nome;

        return View(model);
    }
Run Code Online (Sandbox Code Playgroud)

_Layout.cshtml有这一部分有用:

@Html.Partial("_LoginPartial")
Run Code Online (Sandbox Code Playgroud)

(代码被简化为缩短了这个)

所以这在我打开时工作正常,Home/index因为它没有模型,但是一旦我进入一个带有模型的页面,它就会显示一个模型错误的东西。

我可以替换:

@Html.Partial("_LoginPartial")
Run Code Online (Sandbox Code Playgroud)

为了

@Html.Partial("_LoginPartial", new AplicacaoRoles2.Models.SharedViewModels.PartialLoginViewModel())
Run Code Online (Sandbox Code Playgroud)

但问题是我通过创建一个新实例丢失了信息......谢谢。

**像“Nome”这样的词没有拼错,它们是葡萄牙语

Cod*_*shi 3

让我们首先看看您遇到的问题是什么,然后我们将应用修复程序。

问题/问题

The_LoginPartial.cshtml是从 the 调用的Shared/_Layout.cshtml,除非你改变了它;看来您没有更改它,因此它使用默认值。没关系,您不必更改它。当您访问时Home/Index,您创建一个实例PartialLoginViewModel并将其传递给Home/Index.cshtml。默认情况下,所有.cshtml文件都使用Shared/_Layout.cshtml本质上这就是您的PartialLoginViewModel传递方式:

Home/Index(控制器)=> Home/Index.cshtml => Shared/_Layout.cshtml => _LoginPartial.cshtml

因此,在上面,很明显_LoginPartial.cshtml最终会得到控制PartialLoginViewModel,这就是为什么当您访问 时它会起作用Home/Index。一切都好,花花公子:)

现在让我们看看当您访问另一个页面时会发生什么;说SomeController.SomeAction。让我们进一步想象另一个页面有一个类型为 的模型SomeModel。以下是SomeModel遗嘱的传递方式:

Some/SomeAction(控制器)=> Some/SomeAction.cshtml => Shared/_Layout.cshtml => _LoginPartial.cshtml

它失败了,因为_LoginPartial.cshtml期望一个具有 属性的模型PartialLoginViewModel,但你已经给出了它SomeModel

不是解决办法

这是行不通的:

@Html.Partial("_LoginPartial", new AplicacaoRoles2.Models.SharedViewModels.PartialLoginViewModel())
Run Code Online (Sandbox Code Playgroud)

因为您正在向 发送正确的模型 (PartialLoginViewModel),但_LoginPartial它是一个新实例并且尚未设置属性。因此,Name(你拼写的Nome)将为空。

这也行不通:

@Html.Partial("_LoginPartial", Model)
Run Code Online (Sandbox Code Playgroud)

因为您从主视图向其发送不同类型的模型。

使固定

解决问题的一种方法是继承视图(视图模型)的所有模型,PartialLoginViewModel以便部分保持满意。

public class PartialLoginViewModel
{
    [Required]
    public string Nome { get; set; }
}

public class SomeModel : PartialLoginViewModel
{
    // Code ...
}
Run Code Online (Sandbox Code Playgroud)

您还需要Name在所有控制器操作中填充该属性。因此,只需创建一个基类并从中继承所有控制器即可。像这样:

public class CustomController : Controller
{
    protected virtual async Task<TModel> CreateModel<TModel>() where TModel : PartialLoginViewModel, new()
    {
        TModel model = new TModel();
        var userName = User.Identity.Name;
        var applicationUser = await _context.ApplicationUser.SingleOrDefaultAsync(m => m.UserName == userName);

        // Set common properties
        model.Nome = applicationUser.Nome;

        return model;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后从上述控制器继承所有控制器,并始终调用上述控制器的CreateModel方法,以便它可以填充公共属性,如下所示:

public class EveryoneOfYourControllers : CustomController
{
    public async Task<IActionResult> Index()
    {
        var model = await base.CreateModel<SomeModel>();

        // Set other properties on your model

        return View();
    }
}
Run Code Online (Sandbox Code Playgroud)

所有代码都位于一处。将来,如果您决定向 中添加另一个属性PartialLoginViewModel,您只需在一个位置更改代码即可设置附加属性。

既然您知道了问题所在,您就可以提出不同的解决方案。