首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Html.DisplayFor内核2中的ASP.NET接口视图模型

Html.DisplayFor内核2中的ASP.NET接口视图模型
EN

Stack Overflow用户
提问于 2018-07-12 09:15:31
回答 2查看 1.6K关注 0票数 1

我很难弄清楚如何为一个界面类型的视图模型呈现一个显示模板。假设我有一个视图模型,如下所示:

代码语言:javascript
复制
public class DashboardViewModel
{
    public ISelectedWalletsViewModel Wallets { get; set; }
}

public interface ISelectedWalletsViewModel
{
}

public class OneSelectedWalletViewModel : ISelectedWalletsViewModel
{
    public SelectedWalletViewModel SelectedWallet { get; set; }
    public IEnumerable<WalletViewModel> OtherWallets { get; set; }
}

public class AllSelectedWalletsViewModel : ISelectedWalletsViewModel
{
    public IEnumerable<WalletViewModel> Wallets { get; set; }
}

public interface IWalletViewModel
{
    long Id { get; set; }
    string Name { get; set; }
    string Description { get; set; }
    string CurrentBalance { get; set; }
}

public class WalletViewModel : IWalletViewModel
{
    public long Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string CurrentBalance { get; set; }
}

public class SelectedWalletViewModel : IWalletViewModel
{
    public long Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string CurrentBalance { get; set; }
}

因此,我创建了DisplayTemplates文件夹,为每个模型设置相应的.cshtml文件:

代码语言:javascript
复制
<!-- START OneSelectedWalletViewModel.cshtml -->
@using CLSoft.MyWallet.Models.Home
@model OneSelectedWalletViewModel

@Html.DisplayFor(m => m.SelectedWallet)
@Html.DisplayFor(m => m.OtherWallets)
<a asp-action="Index">Select all wallets</a>
<!-- END OneSelectedWalletViewModel.cshtml -->

<!-- START AllSelectedWalletsViewModel.cshtml -->
@using CLSoft.MyWallet.Models.Home
@model AllSelectedWalletsViewModel

@Html.DisplayFor(m => m.Wallets)
<!-- END AllSelectedWalletsViewModel.cshtml -->

<!-- START SelectedWalletViewModel.cshtml -->
@using CLSoft.MyWallet.Models.Home
@model SelectedWalletViewModel

<div class="card border-primary">
    <div class="card-body">
        <h5 class="card-title">@Model.Name</h5>
        <h6 class="card-subtitle mb-2 text-muted">@Model.CurrentBalance</h6>
        <p class="card-text">@Model.Description</p>
    </div>
</div>
<!-- END SelectedWalletViewModel.cshtml -->

<!-- START WalletViewModel.cshtml -->
@using CLSoft.MyWallet.Models.Home
@model WalletViewModel

<div class="card">
    <div class="card-body">
        <h5 class="card-title">@Model.Name</h5>
        <h6 class="card-subtitle mb-2 text-muted">@Model.CurrentBalance</h6>
        <p class="card-text">@Model.Description</p>
        <a asp-action="Index" asp-route-wallet-id="@Model.Id">select wallet</a>
    </div>
</div>
<!-- END WalletViewModel.cshtml -->

现在,我忽略了控制器操作方法:

代码语言:javascript
复制
[HttpGet]
public async Task<IActionResult> Index(long? walletId)
{
    var viewModel = await _service.GetDashboardViewModelAsync(walletId);
    return View(viewModel);
}

和Index.cshtml视图代码:

代码语言:javascript
复制
@using CLSoft.MyWallet.Models.Home
@model DashboardViewModel

@{
    ViewData["Title"] = "Index";
}

<div class="row">
    <div class="col">
        <h4>Your wallets</h4>
        @Html.DisplayFor(m => m.Wallets)
    </div>
</div>

现在我应该被安排好了。问题是没有标记被呈现。在测试期间,我尝试为接口ISelectedWalletsViewModel添加一个显示模板。

代码语言:javascript
复制
@model ISelectedWalletsViewModel
@Html.DisplayForModel()

在@Html.DisplayForModel()和- ta dah上放置一个断点!-调试器应该停止。但是,遗憾的是,没有调用具体的DisplayTemplate。我是不是遗漏了什么?

编辑1:我创建了一个github回购来显示问题。

编辑2:我也在AspNet/Mvc存储库上报道了这个问题

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-09-21 13:27:22

原来这是精心设计。我将在下面引用NTaylorMullen的答案,以防链接失效(不太可能,但仍然如此):

..。所以在这个问题上,它实际上是由设计造成的。在迁移到Core时,我们发现在遗留的ASP.NET中,我们有一个过度共享的坏习惯(使用意外的视图模型模板)。为了解决这一问题,我们删除了该功能,并要求用户在使用显示模板时显式地使用他们使用的类型。对不起,我没有更好的答案给你!

那么,应该如何重构代码以满足这些规则呢?

  1. 不是很好的,您可以将您的ViewModels重构为一个包含所有可能实现的单一ViewModels,并使用视图中的if语句来呈现所需的实现;
  2. 更好的--您可以重构控制器操作逻辑,以处理ViewModel的所有可能实现,并提供所需的视图。
票数 0
EN

Stack Overflow用户

发布于 2021-08-06 12:40:50

在迁移到ASP.NET核心时,我们遇到了同样的问题,最后使用了以下帮助方法作为解决方法:

代码语言:javascript
复制
public static IHtmlContent MagicDisplayFor<TModel, TResult>(
    this IHtmlHelper<TModel> helper,
    Expression<Func<TModel, TResult>> expression)
{
   // run the expression to get the actual object we want to render
   var targetObject = expression.Compile()(helper.ViewData.Model);

   // get the runtime type of the object (as opposed to the declared type TResult)
   var actualTargetType = targetObject.GetType();

   // render the object as usual, but override the template name using the target type
   return helper.DisplayFor(expression, templateName: actualTargetType.Name);
}

然后,我们在一个需要这种行为的地方用@Html.MagicDisplayFor替换了@Html.MagicDisplayFor

与直接使用@Html.DisplayFor相比,它增加了一些开销,我们可能还没有考虑过一些边缘情况,但它似乎对我们来说已经足够好了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51301661

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档