I have an ASP.NET Core 1.1 web application developed with VS.2017 and I decided to put some of the view functionality in a view component (have done others before).
This view component fetches a Dictionary collection of permissions associated to a user ID and displays them in a nice table. When I put it as part of the page (not VC) it works. But when I use it as a view component the component's HTML is never rendered.
I placed a breakpoint in the view component and it triggers, I see the View(granted) return statement return a populated list so up until there execution is as expected.
Then I placed a breakpoint in the ViewComponent's default.cshtml code section at the top the @{ some code here } and that breakpoint triggers as well, so the view component's Default.cshtml file is found. This Default.cshtml has some markup to render a table, therein within the table I have a @foreach() statement and when do a "Run to cursor" to that precise location -the loop that iterates- it triggers as well so it is iterating through the collection.
But after all that the main view looks as if the view component isn't there, none of the HTML found in the Default.cshtml is rendered even though it was found and executed. What am I missing here? so far my impression has been that VS.2017 (with all its updates) is not very stable.
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;
}
}
So why on earth is it triggering on the component's code as well as on the component's view (default.cshtml) and yet it does not render the HTML code found therein?
Component invokation in the main view:
@{await Component.InvokeAsync<GrantedPermissionsViewComponent>(
new { emailOrUserId = ViewBag.UserName });
}
NOTE
In this article, you will learn about ViewComponent in ASP.NET Core. What is a ViewComponent? ViewComponent was introduced in ASP.NET Core MVC. It can do everything that a partial view can and can do even more.
ASP.NET Core is a cross-platform, high-performance, open-source framework for building modern web, cloud and internet based applications. Also, we can develop Web APIs, mobile apps and client site single page applications using our favourite development tools on Windows, macOS and Linux.
Create a new ASP.NET Core MVC application and run that application. You can see an empty page like the following, We have to display data dynamically. In real scenarios dynamic data mostly comes from the database but for our application we do not use a database and we will create a class to generate fome data.
ViewComponents are completely self-contained objects that consistently render html from a razor view. ViewComponents are very powerful UI building blocks of the areas of application which are not directly accessible for controller actions. Let's suppose we have a page of social icons and we display icons dynamically.
The problem lies in how you are invoking the ViewComponent.
If you use @{ ... }
it means you want to execute code and not render to output.
If you use parenthesis instead of brackets, the result gets rendered to output. @( ... )
In your case, you don't even need the parenthesis. Try invoking it has following:
@await Component.InvokeAsync("GrantedPermissions", new { emailOrUserId = ViewBag.UserName })
More info here
try this, your mileage might vary. :)
@if (User.Identity.IsAuthenticated)
{
<div>User: @User.Identity.Name</div>
@(await Component.InvokeAsync("DefaultNavbar"));
@RenderBody()
}
else
{
<div> show public pages</div>
@RenderBody()
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With