ASP.NET MVC Razor: How to Render a Razor Partial View's HTML Inside the Controller Action

ASP.NET MVC Razor: How to render a Razor Partial View's HTML inside the controller action

@Html.Partial("nameOfPartial", Model)

Update

protected string RenderPartialViewToString(string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = ControllerContext.RouteData.GetRequiredString("action");

ViewData.Model = model;

using (StringWriter sw = new StringWriter()) {
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);

return sw.GetStringBuilder().ToString();
}
}

Getting a Partial View's HTML from inside of the controller

You have several options.

Create a MVC View User Control and action handler in your controller for the view. To render the view use

<% Html.RenderPartial("MyControl") %>

In this case your action handler will need to pass the model data to the view

public ActionResult MyControl ()
{
// get modelData

render View (modelData);
}

Your other option is to pass the model data from the parent page. In this case you do not need an action handler and the model type is the same as the parent:

<% Html.RenderPartial("MyControl", ViewData.Model) %>

If your user control has it's own data type you can also construct it within the page

In MyControl.ascx.cs:

public class MyControlViewData
{
public string Name { get; set; }
public string Email { get; set; }
}

public partial class MyControl : System.Web.Mvc.ViewUserControl <MyControlViewData>
{
}

And in your page you can initialize your control's data model:

<% Html.RenderPartial("MyControl", new MyControlViewData ()
{
Name= ViewData.Model.FirstName,
Email = ViewData.Model.Email,
});
%>

MVC: How to get controller to render partial view initiated from the view

Thanks to Stephen Muecke and Erick Cortorreal I got it to work.

This is what the controller should look like:

[ChildActionOnly]
public PartialViewResult GetMenu()
{
MenuStructuredModel menuStructuredModel = menuBusiness.GetStructuredMenu();

return PartialView("~/Views/Shared/MenuPartial", menuStructuredModel);
}

And it may called like:

@Html.Action("GetMenu", "Home")

(Hence GetMenu() is declared in the HomeController in my example).

The controller is now called (and the model is populated) prior to the partial view is rendered.

ASP.NET Core MVC - Partial view only renders on one page

You should create a seperate action method which returns HTML markup needed to render the cart section of your page and include that in all your view using Html.Action method.

You may also decorate this action method with ChildActionOnly attribute so that users's cannot directly access this action method by requesting the url /ShoppingCart/Cart.

[ChildActionOnly]
public ActionResult Cart()
{
ViewBag.ItemCount = 2; // replace hard coded value with your actual value
return PartialView();
}

and in your partial view (~/Views/Shared/Cart.cshtml), you may write the HTML code which is needed for the cart segment of the page.

<span class="mycart">
Total items in cart @ViewBag.ItemCount
</span>

Here we are using ViewBag to pass the item count numeric value from the action method to it's partial view. But you may use a view model and use the strongly typed view approach to pass data from your action method to the partial view (this is my preferred approach).

Now in other views/layout file where you want to render the cart HTML, you can call the Html.Action method

<div>
@Html.Action("Cart","ShoppingCart")
</div>
<h1>Welcome to my site</h1>

When razor execute your view, it will see this Html.Action method and that will be executed and the output of that (the HTML markup generated fro the action method), will be included in the final output generated for the current view.

I am using the PartialView method, so that it will not try to execute the Layout code. (People make this mistake and gets an infinite calls to the Cart action method.

For Asp.Net Core projects

If you want to do the same thing in asp.net core projects, you may use View components to achieve the same results.

Create a view component to render the cart.

public class CartViewComponent : ViewComponent
{
public IViewComponentResult Invoke(string name)
{
var totalItemCount = 3;
return View(totalItemCount);
}
}

Create a razor view for this view component with the name Default.cshtml inside ~/Views/Shared/Components/Cart directory and you can have your razor code/HTML markup inside that to render the desired HTML. In this example, I am using a strongly typed approach where my view is stongly typed to int type and I am passing an int value from the the Invoke method when calling the View method.

@model int
<span>
Total items : @Model
</span>

Now you can invoke this view component in other views/ layout file by calling the Component.InvokeAsync method.

<div>
@await Component.InvokeAsync("Cart")
</div>
<h1>Welcome to my site</h1>

Use a HTML code in any one of multiple partial views in Asp.net MVC 4 with Razor View Engine

Create another partial (partialview4.cshtml), use it on all the partials partialview(1-3).cshtml.
Pass on the model of the partial if its supposed to display or not :-)
The view1.cshtml will know how to control.

@Html.RenderPartial("partialview1", new yourPartialViewModel {displayHtmlSample = true});
@Html.RenderPartial("partialview2", new yourPartialViewModel {displayHtmlSample = false});
@Html.RenderPartial("partialview3", new yourPartialViewModel {displayHtmlSample = false});

Inside the partial:

    @if(Model.displayHtmlSample) { 
@Html.RenderPartial("partialview4")
}

Why are the PartialView models null in a PostBack to an Asp.Net Core Razor main page view's controller?

The problem lies with not using the for attribute on the partial view. I'll try to explain why.

A partial view can be part of a parent form, but the partial view isn't aware of the parent model.

Let's look at the code:

<partial name="@Model.ViewName" model="@Model.PartialSampleModel" />

What the model attribute on the partial tag does, is pass an instance of that model to the partial view.

In a form, only the inputs that have a (asp-) 'for' tag are posted when the form is submitted. In the example above, you are explicitly saying that partial view is not 'for' the parent's model, any inputs that it might contain, are ignored. You need to tell the form: Hey, this partial view is for our model, make sure whatever values it contains stay part of our model.

Change it like so:

<partial name="@Model.ViewName" for="PartialSampleModel" />

Rendering Partial view as a string inside SignalR Hub

I am trying to dynamically load partial view contents in one of my views via a SignalR Hub to update client side data. For this I have to render the Partial view as a string in the SignalR Hub and send this string to the client side.

If you'd like to render your view/partial view as a html string within your hub method, you can refer to this blog with example that demonstrates how to render a Partial View to string.

And I did a test with the example code RazorPartialToStringRenderer in my SignalR app, which work well for me.

private readonly IRazorPartialToStringRenderer _renderer;
public ChatHub(IRazorPartialToStringRenderer renderer)
{
_renderer = renderer;
}
public async Task SendMessage(string user, string message)
{

var view_result_mes = await _renderer.RenderPartialToStringAsync<string>("_SayHelloPartialView", null);

//...

Code referenced from above blog

public interface IRazorPartialToStringRenderer
{
Task<string> RenderPartialToStringAsync<TModel>(string partialName, TModel model);
}

public class RazorPartialToStringRenderer : IRazorPartialToStringRenderer
{
private IRazorViewEngine _viewEngine;
private ITempDataProvider _tempDataProvider;
private IServiceProvider _serviceProvider;
public RazorPartialToStringRenderer(
IRazorViewEngine viewEngine,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
{
_viewEngine = viewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
public async Task<string> RenderPartialToStringAsync<TModel>(string partialName, TModel model)
{
var actionContext = GetActionContext();
var partial = FindView(actionContext, partialName);
using (var output = new StringWriter())
{
var viewContext = new ViewContext(
actionContext,
partial,
new ViewDataDictionary<TModel>(
metadataProvider: new EmptyModelMetadataProvider(),
modelState: new ModelStateDictionary())
{
Model = model
},
new TempDataDictionary(
actionContext.HttpContext,
_tempDataProvider),
output,
new HtmlHelperOptions()
);
await partial.RenderAsync(viewContext);
return output.ToString();
}
}
private IView FindView(ActionContext actionContext, string partialName)
{
var getPartialResult = _viewEngine.GetView(null, partialName, false);
if (getPartialResult.Success)
{
return getPartialResult.View;
}
var findPartialResult = _viewEngine.FindView(actionContext, partialName, false);
if (findPartialResult.Success)
{
return findPartialResult.View;
}
var searchedLocations = getPartialResult.SearchedLocations.Concat(findPartialResult.SearchedLocations);
var errorMessage = string.Join(
Environment.NewLine,
new[] { $"Unable to find partial '{partialName}'. The following locations were searched:" }.Concat(searchedLocations)); ;
throw new InvalidOperationException(errorMessage);
}
private ActionContext GetActionContext()
{
var httpContext = new DefaultHttpContext
{
RequestServices = _serviceProvider
};
return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
}
}

Test Result

Sample Image



Related Topics



Leave a reply



Submit