【问题标题】:.NET Core: ViewModel attributes are not rendered.NET Core:不呈现 ViewModel 属性
【发布时间】:2018-05-09 19:04:34
【问题描述】:

我正在使用 Razor 视图引擎开发一个 ASP.NET Core 2.0 Web 应用程序。首先,我尝试通过互联网和 StackOverFlow 寻找解决方案,但其中任何一个都可以解决我的问题。让我们看看我们面临什么:

我有一个相对简单的客户视图模型:

namespace MokaKukaMap.Application.Customers.ViewModels.Models
{
    public class CustomerViewModel
    {
        public long Id { get; set; }

        [Display(Name = "Név")]
        [Required]
        public string Name { get; set; }

        [Display(Name = "Telefonszám")]
        [Required]
        public string PhoneNumber { get; set; }
    }
}

如您所见,NamePhoneNumber 属性具有指定的属性 Display。 我对应的部分视图(_NewCustomer.cshtml)如下:

@model MokaKukaMap.Application.Customers.ViewModels.Models.CustomerViewModel

<div class="col-lg-5 basic-surronder">
    <form asp-controller="NewCustomer" asp-action="NewCustomer" class="well">
        <div id="form-horizontal">
            <div class="form-group">
                <label asp-for="@Model.Name" class=""></label>
                <div class="">
                    <input asp-for="@Model.Name" class="form-control">
                    <span asp-validation-for="@Model.Name" class="text-danger"> </span>
                </div>
            </div>

            <div class="form-group">
                <label asp-for="@Model.PhoneNumber" class=""></label>
                <div class="">
                    <input asp-for="@Model.PhoneNumber" class="form-control">
                    <span asp-validation-for="@Model.PhoneNumber" class="text-danger"> </span>
                </div>
            </div>
        </div>
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <div class="">
                <input type="submit" formnovalidate="formnovalidate" value="Új ügyfél hozzáadása" class="btn btn-primary" />
            </div>
        </div>
    </form>
</div>

到目前为止一切顺利。正如我已经提到的,我将此视图用作部分视图,因此我将她包含在 NewCustomer.cshtml 主视图中,并带有以下行:

@Html.Partial("_NewCustomer")

_NewCustomer.cshtml 位于标准 Views/Shared 文件夹中。我想做的是将此部分视图放入特定文件夹,即Customers/Views 文件夹。为了解决这个问题,我做了一个CustomerViewLocationExpander,如下所示:

public class CustomViewLocationExpander : IViewLocationExpander
{
    public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
    {
        var viewLocationFormats = new[]
        {
            "~/Customers/Views/{0}.cshtml", 
            "~/Views/Shared/{0}.cshtml",
            "~/Views/{0}.cshtml",
        };
        return viewLocationFormats;
    }

    public void PopulateValues(ViewLocationExpanderContext context)
    {
        context.Values["customviewlocation"] = nameof(CustomViewLocationExpander);
    }
}

在 Startup.cs 中配置:

    services.Configure<RazorViewEngineOptions>(options => options.ViewLocationExpanders.Add(new CustomViewLocationExpander()));

我的问题如下:如果_NewCustomer.cshtml 位于 Views/Shared 文件夹中,则一切正常。但是,如果我将它放在我的自定义客户/视图文件夹中,则不会显示/呈现属性的名称,并且验证属性也根本不起作用。呈现两个输入字段是因为我看到以下表单:

我已经尝试解决我的问题,(但他们都没有帮助):

  • 在启动时配置视图位置

    services.Configure<RazorViewEngineOptions>(o => o.ViewLocationFormats.Add("/Customers/Views/{0}" + RazorViewEngine.ViewExtension));
    
  • 包含局部视图时使用绝对路径:

    @Html.Partial("~/Customers/Views/_NewCustomer.cshtml")
    
  • 在我的“客户”文件夹中创建一个名为“共享”的文件夹并将我的部分视图放在那里:客户/视图/共享

  • 删除所有“bin”和“obj”文件夹,清理然后重建解决方案

此外,我意识到如果部分视图位于自定义文件夹中,则 VS2017 (IntelliSense) 无法识别 asp-net-core 特定的 html 标签,例如&lt;form asp-controller= 没有以绿色突出显示,只有如果视图位于 Shared 文件夹中。

附加信息:

我的文件夹结构如下所示:

您认为问题出在哪里?感谢您的帮助!

【问题讨论】:

  • 你能发布你的文件夹结构吗?我可以毫无问题地做到这一点,但我使用了不同的文件夹结构..不确定你是否可以改变你的结构。
  • 另外,您是否在ConfigureServices 方法中配置了您的CustomViewLocationExpander
  • @jpgrassi 感谢您的 cmets! CustomViewLocationExpander 在服务中配置。至于文件夹结构,我添加了它的图像。是的,我可以灵活地更改文件夹结构,但我想将部分视图放入问题中描述的自定义文件夹(客户/视图)中。或者你有什么更好的想法?
  • 我明白了.. 我设法将视图文件夹“重命名”为“功能”之类的东西。将尝试在您的结构中重现,看看它是否也有效。
  • 检查我的答案.. 它对我有用,但它有点超出您当前的设置。如果你想试试,我可以把它放在 github 上。请告诉我。

标签: c# razor asp.net-core


【解决方案1】:

不确定这是否会帮助您解决实际问题,因为您可能需要更改很多东西。但我发现这种结构比您现有的结构更“干净”。我立即看到的问题是:

  • 很难区分实际功能和设置/基础代码。 Containers 是一个特性还是与 Docker 有关?不知道,必须打开它。
  • 现在的情况是,在您的 IViewLocationExpander 中,您必须对每个功能名称进行“硬编码”,因为它们都散布在各处……不太酷。

我的建议是将结构更改为:

  • 功能(将视图重命名为功能,正常保留共享文件夹。)
    • 客户
      • 控制器
      • 观看次数

然后,你像这样配置你的ViewLocationExpander

public class ViewLocationExpander : IViewLocationExpander
{

   public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
    {
        // {1} is Controller, {0} is View Name
        return new [] 
        {
            "/Features/{1}/Views/{0}.cshtml", // Finds the Customer View folders
            "/Features/{1}/{0}.cshtml", // finds the Home views.. they are in root of the folder.. so no need for Views
            "/Features/Shared/{0}.cshtml" // Layouts
        };
    }

    public void PopulateValues(ViewLocationExpanderContext context)
    {

    }
}

这样,您可以添加新功能,例如Product,使用它自己的Views 文件夹,它会自动被拾取。这是我在设置中使用的结构的图像:

编辑:这是我在 Github 上的解决方案joaopgrassi/custom-razorview-location

另外,我真的不明白将 ViewModel 放在一个单独的项目中。 ViewModel 的全部目的是为 UI 服务。 ViewModel 上没有任何 DDD,带有公共设置器。也许我误解了你..但我肯定会更深入地研究。 DDD 是丰富的,通常是不可变的实体。而 ViewModel 只是 poco 类,只是为了传输数据。

【讨论】:

    猜你喜欢
    • 2019-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-22
    • 1970-01-01
    • 2011-03-25
    • 2012-12-25
    • 2022-12-01
    相关资源
    最近更新 更多