asp.net核心视图组件已执行但标记未呈现

时间:2017-06-29 19:05:17

标签: asp.net-core asp.net-core-mvc asp.net-core-viewcomponent

我有一个用VS.2017开发的ASP.NET Core 1.1 Web应用程序,我决定将一些视图功能放在一个视图组件中(以前做过其他的)。

此视图组件获取与用户ID关联的字典集合,并将其显示在一个漂亮的表中。当我把它作为页面的一部分(而不是VC)时,它可以工作。但是,当我将它用作视图组件时,组件的HTML永远不会被渲染。

我在视图组件中放置了一个断点并触发,我看到View(已授予)返回语句返回一个填充列表,直到按预期执行为止。

然后我在ViewComponent的default.cshtml代码部分的@ {some code here}顶部放置了一个断点,并且该断点也会触发,因此视图组件的Default.cshtml文件是找到。这个Default.cshtml有一些标记来呈现一个表,在表格中我有一个@foreach()语句,当做一个" Run to cursor"到那个精确的位置 - 迭代的循环 - 它也会触发,因此它会遍历集合。

但毕竟主视图看起来好像视图组件不在那里,即使找到并执行了Default.cshtml中的HTML也没有呈现。我在这里错过了什么?到目前为止,我的印象是VS.2017(及其所有更新)不是很稳定。

Default.cshtml

@using ACME.AspNetCore.Permissions.Infrastructure.Authorization
@model Dictionary<Permission, string>
@{ 
    ViewBag.UserName = "xxx";
    Model.Add(Permission.Permission1, "test");
}

<h1>Component Output</h1>
<div class="well well-lg">
<table class="table table-hover">
    <thead>
        <tr>
            <th>Permission</th>
            <th>Description</th>
            <th class="text-center">Status</th>
            <th class="text-center">Revoke it!</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var dictentry in Model)
        {
            <tr>
                <td>@dictentry.Key.ToString()</td>
                <td>@dictentry.Value</td>
                <td class="text-center"><span class="glyphicon glyphicon-ok" style="color:green;"></span></td>
                <td class="text-center"><a asp-action="RevokePermission" asp-route-id="@ViewBag.UserName" asp-route-pid="@dictentry.Key.ToString()"><span class="glyphicon glyphicon-thumbs-down" style="color:red;"></span></a></td>
            </tr>
        }
    </tbody>
    <tfoot><p class="alert alert-success"><span class="glyphicon glyphicon-eye-open"></span> Granted permissions</p></tfoot>
</table>
</div>

GrantedPermissionsViewComponent.cs

 [ViewComponent(Name = "GrantedPermissions")]
 public class GrantedPermissionsViewComponent : ViewComponent {
     private readonly ApplicationDbContext _context;
     public GrantedPermissionsViewComponent(ApplicationDbContext context) : base()
    {
        _context = context;
    }

    public async Task<IViewComponentResult> InvokeAsync(string emailOrUserId)
    {
        string id;
        Guid UID;
        if (Guid.TryParse(emailOrUserId, out UID))
        {   // THE PARAMETER WAS A GUID, THUS A USER ID FROM IDENTITY DATABASE
            id = emailOrUserId;
        }
        else
        {   // THE PARAMETER IS ASSUMED TO BE AN EMAIL/USERNAME FROM WHICH WE CAN DERIVE THE USER ID
            id = _context.Users.Where(u => u.Email == emailOrUserId.Trim()).Select(s => s.Id).FirstOrDefault();
        }

        Dictionary<Permission, string> granted = GetOwnerPermissions(id);
        return View(granted);            
    }

    private Dictionary<Permission, string> GetOwnerPermissions(string userId) 
    {
        Dictionary<Permission, string> granted;
        granted = _context.UserPermissions.Where(u => u.ApplicationUserId == userId)
                                                .Select(t => new { t.Permission })
                                                .AsEnumerable() // to clients memory
                                                .Select(o => new KeyValuePair<Permission, string>(o.Permission, o.Permission.Description()))
                                                .ToList()
                                                .ToDictionary(x => x.Key, x => x.Value);

        return granted;
    }
 }

那么为什么它本身会触发组件的代码以及组件的视图(default.cshtml),但它不会呈现其中的HTML代码?

主视图中的组件调用:

@{await Component.InvokeAsync<GrantedPermissionsViewComponent>(
    new { emailOrUserId = ViewBag.UserName });
}

请注意

  • InvokeAsync实际上是同步执行的(每个警告),因为我找不到让GetOwnerPermissions等待任何事情的方法......但这不是问题。

2 个答案:

答案 0 :(得分:12)

问题在于如何调用ViewComponent。

如果使用@{ ... },则意味着您要执行代码而不是渲染输出。

如果使用括号而不是括号,则结果将呈现为输出。 @( ... )

在您的情况下,您甚至不需要括号。 尝试调用它具有以下内容:

@await Component.InvokeAsync("GrantedPermissions", new { emailOrUserId = ViewBag.UserName })

更多信息here

答案 1 :(得分:1)

试试这个,你的里程可能会有所不同。 :)

@if (User.Identity.IsAuthenticated)
{

    <div>User: @User.Identity.Name</div>
    @(await Component.InvokeAsync("DefaultNavbar"));

    @RenderBody()
}
else
{
    <div> show public pages</div>
    @RenderBody()
}