Reputation: 333
I'm implementing asp.net core project. I have a method in my controller that should pass a data to a viewcomponent and then I need that data to be displayed in _Layout razor view. Below is what I have tried till now:
public class AccountController : Controller {
public IActionResult Index(string str)
{
_httpContext.HttpContext.Items["Shared"] = str;
Debug.WriteLine("str:" + str);
Debug.WriteLine("HttpContext Index shared:"+_httpContext.HttpContext.Items["Shared"]);
// Use ViewData
ViewData["Shared"] = str;
Debug.WriteLine("ViewData Index shared:" + ViewData["Shared"]);
return View();
}
}
public class MySharedDataViewComponent : ViewComponent
{
private readonly IHttpContextAccessor _httpContext;
public MySharedDataViewComponent(IHttpContextAccessor context)
{
_httpContext = context;
}
public Task<IViewComponentResult> InvokeAsync()
{
Debug.WriteLine("MyShred data:" + _httpContext.HttpContext.Items["Shared"]);
return Task.FromResult<IViewComponentResult>(View(_httpContext.HttpContext.Items["Shared"]));
}
}
In index.cshtml for Account controller:
@model string
<h2>@Model</h2>
In Default.cshtml
@model dynamic
@{
var passedDataFromItems = (Model as string);
var passedDataFromViewData = (ViewData["Shared"] as string);
}
@passedDataFromItems
@passedDataFromViewData
In _Layout I added this:
<div class="col-sm-10 col-8 p-0 m-0 text-left">
@await Component.InvokeAsync("MySharedData")
</div>
And in startup I pasted what you suggested as well.
My problem is in _Layout there isn't any data from ViewComponent to be displayed.
Upvotes: 0
Views: 1002
Reputation: 713
First, you need to remove ( )
in _Layout.cshtml, just use @await ComponentAsync("SharedData")
. Because ( )
will render HTMLEncoded
string instead of HTML string.
Second, if you want to pass your shared data down from Controller, you don't need to call ViewComponent inside Controller. There are several way to pass, ex: HttpContext.Items
or ViewData
. You don't want to call render HTML from Controller. In previous .NET MVC, we have @Html.RenderAction()
to render ChildControlOnly
view in Controller. But this is removed, so there are no reason to use Controller to call ViewComponent. Let .NET Core handle that for you by Naming Convention
Third, you don't want to declare @{ Layout = null }
in ViewComponent, it is useless because ViewComponent is as PartialView.
Not sure why you try to render whole HTML page in ViewComponent and put it in <head>
tag in _Layout.cshtml.
Updated answer with sample code In your _Layout.cshtml
<html>
<head>
</head>
<body>
<!-- Use this for calling ViewComponent, Name must be prefix of VC class -->
@await ComponentAsync("SharedData")
<!-- Use this for render Body -->
@RenderBody()
</body>
</html>
Example you have HomeController
to render Home Page
public class HomeController : Controller
{
private readonly IHttpContextAccessor _httpContext;
public HomeController (IHttpContextAccessor context)
{
_httpContext = context;
}
/// <summary>
/// Define [Route] for parameterize
/// str? means Nullable Param
/// Ex: localhost/hello -> str = hello
/// </summary>
[Route("{str?}")]
public IActionResult Index(string str)
{
_httpContextAccessor.HttpContext.Items["Shared"] = str ?? "Items Empty Param";
ViewData["Shared"] = str ?? "View Data Empty Param";
return View();
}
}
Next you need to create Index.cshtml
for placing @RenderBody()
<div>This is home page</div>
Next you need to create SharedDataViewComponent
locales on ViewComponents
folder (Under root project)
public class SharedDataViewComponent : ViewComponent
{
private readonly IHttpContextAccessor _httpContext;
public SharedDataViewComponent(IHttpContextAccessor context)
{
_httpContext = context;
}
public Task<IViewComponentResult> InvokeAsync()
{
return Task.FromResult<IViewComponentResult>(View(_httpContext.HttpContext.Items["Shared"]));
}
}
In your Views\Shared\SharedData\Default.cshtml
, write with these markup
@model dynamic
@{
var passedDataFromItems = (Model as string);
var passedDataFromViewData = (ViewData["Shared"] as string);
}
@passedDataFromItems
@passedDataFromViewData
Ensure in your Configure
method in Startup.cs
should add this line
services.AddHttpContextAccessor();
Upvotes: 1