How to call Html.Raw and Html.Partial outside a razor page? - razor

I have this requirements. I need to be able to write this code in my razor views:
#Filters.Render(Filters.DateRangeFilter, new DateRangeFilterParameters { });
The alternative is:
#Html.Partial("/Views/Shared/DateRangeFilter.cshtml", new DateRangeFilterParameters { });
In other words, I want Filters class to wrap Html.Partial. For that reason, I thought of this code:
public class Filters {
public const string DateRangeFilter = "/Views/Shared/DateRangeFilter.cshtml";
public static HtmlString Render(string filterPath, object parameters)
{
// Here I need to call Html.Partail, how?
}
}

To use Html.Raw within the controller you can request the injected IHtmlHelper service. E.g.:
HttpContext.RequestServices.GetService(typeof(IHtmlHelper)) as IHtmlHelper;
Or you can do your own implementation for the helper. And in order to use Html.Partial you need to use IRazorViewEngine, ViewContext, and other stuff. So basically you need to implement a service for that, and here is a good example Render Partial View To String Outside Controller Context.
I don't know if there is an easier way to achieve those, but that is what on my mind.

Related

ASP .Net Core Razor: Can't return ViewComponent from my PageModel

I am trying to use Ajax to call a handler in my Razor page that returns the result of a ViewComponent, however when I try the code below, it says:
Non-invocable member "ViewComponent" cannot be used like a method.
public IActionResult OnGetPriceist()
{
return ViewComponent("PriceList", new { id= 5 });
}
When using MVC, the Controller base class includes a ViewComponent method, which is just a helper method that creates a ViewComponentResult for you. This method does not yet exist in the Razor Pages world, where instead you use PageModel as the base class.
One option to work around this is to create an extension method on the PageModel class, that would look something like this:
public static class PageModelExtensions
{
public static ViewComponentResult ViewComponent(this PageModel pageModel, string componentName, object arguments)
{
return new ViewComponentResult
{
ViewComponentName = componentName,
Arguments = arguments,
ViewData = pageModel.ViewData,
TempData = pageModel.TempData
};
}
}
Apart from it being an extension method, the code above is just ripped out of Controller. In order to use it, you can call it from your existing OnGetPriceList (typo fixed) method, like this:
public IActionResult OnGetPriceList()
{
return this.ViewComponent("PriceList", new { id = 5 });
}
The key to making it work here is to use this, which will resolve it to the extension method, rather than trying to invoke the constructor as a method.
If you're only going to use this once, you could forego the extension method and just embed the code itself inside of your handler. That's entirely up to you - some people might prefer the extension method for the whole separation-of-concerns argument.

MVC, How to read rendered HTML in a controller?

Maybe it´s a strange question, but imagine this:
//We all know that View is a method...
public ActionResult Something()
{
return View("index");
}
But what if I step before this method to perform some stats
public ActionResult Something()
{
return PerformStats(View("index"));
}
I will have a private method like this:
private ActionResult PerformStats(ViewResult viewResult)
{
//THIS IS WHAT I WANT TO ACCHIEVE:
//*********************************
var contentSent = viewResult.InnerHtml.Lengh; <<-- I wish!
return viewResult;
}
And latter, what i want to do, is to save that ammount of content sent to the client.
It doesn´t matter if it is the exactly quantity of html, even if I get the .count() of a json it will do the trick.
Is any way to know the rendered content on the controller?
Thanks!
OnActionExecuting: Called before action method executes. You can put stats related logic in there.
http://msdn.microsoft.com/en-us/library/system.web.mvc.iactionfilter.onactionexecuting(v=vs.98).aspx
OnActionExecuted: Called after action method executed.
http://msdn.microsoft.com/en-us/library/system.web.mvc.iactionfilter.onactionexecuted(v=vs.98).aspx
Within these methods you can access ActionExecuting and ActionExecutedContext
If you want to get a size of rendered HTML (partial or complete view), then you probably need to:
Find the view that you want to render
Store it in the string builder
Get its length
There is a question that explains how to render view as a string within the action method: In MVC3 Razor, how do I get the html of a rendered view inside an action?

MVC Razor syntax: # followed by HTML

I came across this code today and don't really understand it. Please could someone tell me what this means and how to interpret it? I have simplified it but it's basically the # symbol followed by some HTML.
The call is:
#Html.Tmpl(#<p>text to display</p>)
The function is:
public static HelperResult Tmpl<TModel>( this HtmlHelper<TModel> html, Func<HtmlHelper<TModel>, HelperResult> template )
{
return new HelperResult( writer => template( html ).WriteTo( writer ) );
}
Please enlighten me. Thank you.
This is an example of what is known as a Templated Razor Delegate. Quite simply, it is a type of HTML helper which accepts a block of Razor template code which can be used to compose the result of a complex operation.
A simple use case might be an Html.List(data, template) method which accepts a list of records and a template for each row of data. The template markup is a delegate which can be invoked and passed a model within the helper's logic.
public static HelperResult List<T>(this IEnumerable<T> items,
Func<T, HelperResult> template) {
return new HelperResult(writer => {
foreach (var item in items) {
template(item).WriteTo(writer);
}
});
}
Phil Haacked goes into more detail here: http://haacked.com/archive/2011/02/27/templated-razor-delegates.aspx.

How do I use content containing razor markup as a parameter for a method?

What I am trying to do is to be able to write javascript blended with razor styled markup and methods inside .cshtml file and send this to a separate method for usage later on.
My .cshtml looks something like this:
#{SomeClass.SaveForLater(#<script type="text/javascript">window.alert('#Model.SomeParamter')}</script>);
And inside the class SomeClass:
public static void SaveForLater(HtmlString str) {
// will be using str.ToString() here and save the string output for use later on.
}
But what I receive is this error message:
CS1660: Cannot convert lambda expression to type 'System.Web.HtmlString' because it is not a delegate type
Am I using the wrong type for the argument or do I need to rethink the whole concept?
Solution
Thanks to SLaks below I ended up doing this:
public static void SaveForLater<T>(Func<T, HelperResult> template, dynamic model)
{
// template(model).ToHtmlString()
}
Using it like this:
#{SomeClass.SaveForLater<SomeModel>(
#<script type="text/javascript">window.alert('#Model.SomeParamter')</script>,
Model
);
You're trying to take an inline helper.
You need to accept a Func<Something, HelperResult>.

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

I have developed a simple mechanism for my mvc website to pull in html via jquery which then populates a specified div. All is well and it looks cool.
My problem is that i'm now creating html markup inside of my controller (Which is very easy to do in VB.net btw) I'd rather not mix up the sepparation of concerns.
Is it possible to use a custom 'MVC View User Control' to suit this need? Can I create an instance of a control, pass in the model data and render to html? It would then be a simple matter of rendering and passing back to the calling browser.
This is a solution that is working with ASP.Net MVC 1.0 (many that claim to work with beta 3 don't work with 1.0), doesn't suffer of the 'Server cannot set content type after HTTP headers have been sent' problem and can be called from within a controller (not only a view):
/// <summary>
/// Render a view into a string. It's a hack, it may fail badly.
/// </summary>
/// <param name="name">Name of the view, that is, its path.</param>
/// <param name="data">Data to pass to the view, a model or something like that.</param>
/// <returns>A string with the (HTML of) view.</returns>
public static string RenderPartialToString(string controlName, object viewData) {
ViewPage viewPage = new ViewPage() { ViewContext = new ViewContext() };
viewPage.Url = GetBogusUrlHelper();
viewPage.ViewData = new ViewDataDictionary(viewData);
viewPage.Controls.Add(viewPage.LoadControl(controlName));
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb)) {
using (HtmlTextWriter tw = new HtmlTextWriter(sw)) {
viewPage.RenderControl(tw);
}
}
return sb.ToString();
}
public static UrlHelper GetBogusUrlHelper() {
var httpContext = HttpContext.Current;
if (httpContext == null) {
var request = new HttpRequest("/", Config.Url.ToString(), "");
var response = new HttpResponse(new StringWriter());
httpContext = new HttpContext(request, response);
}
var httpContextBase = new HttpContextWrapper(httpContext);
var routeData = new RouteData();
var requestContext = new RequestContext(httpContextBase, routeData);
return new UrlHelper(requestContext);
}
It's a static method you can drop somewhere you find it convenient. You can call it this way:
string view = RenderPartialToString("~/Views/Controller/AView.ascx", someModelObject);
I put together a rough framework which allows you to render views to a string from a controller method in MVC Beta. This should help solve this limitation for now.
Additionally, I also put together a Rails-like RJS javascript generating framework for MVC Beta.
Check it out at http://www.brightmix.com/blog/how-to-renderpartial-to-string-in-asp-net-mvc and let me know what you think.
You would create your action like this:
public PartialViewResult LoginForm()
{
var model = // get model data from somewhere
return PartialView(model);
}
And the action would return the rendered partial view to your jquery response.
Your jquery could look something like this:
$('#targetdiv').load('/MyController/LoginForm',function(){alert('complete!');});
You should use jquery to populate your divs (and create new html elements if needed), and Json serialization for ActionResult.
Other way is to use jquery to call some controller/action, but instead json use regular View (aspx or ascx, webforms view engine) for rendering content, and with jquery just inject that html to some div. This is half way to UpdatePanels from asp.net ajax...
I would probably go with first method, with json, where you have little more job to do, but it's much more "optimized", because you don't transfer whole html over the wire, there are just serialized objects. It's the way that "big ones" (gmail, g docs, hotmail,..) do it - lot of JS code that manipulates with UI.
If you don't need ajax, then you basically have two ways of calling partial views:
html.renderpartial("name of ascx")
html.RenderAction(x=>x.ActionName) from Microsoft.web.mvc (mvc futures)
After much digging in google i have found the answer.
You can not get easy access to the html outputted by the view.
http://ayende.com/Blog/archive/2008/11/11/another-asp.net-mvc-bug-rendering-views-to-different-output-source.aspx
I've done something similar for an app I'm working on. I have partial views returning rendered content can be called using their REST path or using:
<% Html.RenderAction("Action", "Controller"); %>
Then in my actual display HTML I have a DIV which is filled from jQuery:
<div class="onload">/controller/action</div>
The jQuery looks like this:
<script type="text/javascript">
$.ajaxSetup({ cache: false });
$(document).ready(function () {
$('div.onload').each(function () {
var source = $(this).html();
if (source != "") {
$(this).load(source);
}
});
});
</script>
This scans for all DIV that match the "onload" class and reads the REST path from their content. It then does a jQuery.load on that REST path and populates the DIV with the result.
Sorry gotta go catch my ride home. Let me know if you want me to elaborate more.
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,
});
%>
In rails this is called rendering a partial view, and you do it with render :partial => 'yourfilename'. I believe ASP.NET MVC has a similar RenderPartial method, but I can't find the official docs for MVC to confirm or deny such a thing.
it is very simple you just have to create a strongly typed partial view(or user control) then in your cotroller something like this:
public PartialViewResult yourpartialviewresult()
{
var yourModel
return PartialView("yourPartialView", yourModel);
}
then you can use JQuery to perform the request whener you want:
$.ajax({
type: 'GET',
url: '/home/yourpartialviewresult',
dataType: 'html', //be sure to use html dataType
contentType: 'application/json; charset=utf-8',
success: function(data){
$(container).html(data);
},
complete: function(){ }
});
I found this one line code to work perfectly. orderModel being my model object. In my case I had a helper method in which I had to merge a partial view's html.
System.Web.Mvc.Html.PartialExtensions.Partial(html, "~/Views/Orders/OrdersPartialView.cshtml", orderModel).ToString();