I am trying to capture the Current page Html and was wondering to see how can i set a hiddenfield using the razor syntax
Filed i want to set
#Html.Hidden("pageHtml")
i am currently using javascript to get the page html but the same thing i want to try using #Html attribute or something
var html1 = $('#wrapper').html();
var encodedString = escape(html1);
$('#pageHtml').val(encodedString);
or if someone can help me finding a way to get the current view html in the controller action
Please make some suggestions
First, create a Controller Extension method ViewToString as below:
This will extend System.Web.Mvc.Controller to have a new method called ViewToString and it will render Your views HTML into a StringReader
namespace YourProject.ControllerExtensions
{
using System;
using System.IO;
using System.Web.Mvc;
public static class ControllerExtend
{
public static StringReader ViewToString(this Controller controller, string viewName, object model)
{
#region MyRegion
ControllerContext context = controller.ControllerContext;
if (context == null)
{
throw new ArgumentNullException("context");
}
if (model != null)
{
controller.ViewData.Model = model;
}
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
var viewContext = new ViewContext(context, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(context, viewResult.View);
//return sw.GetStringBuilder().ToString();
return new StringReader(sw.ToString());
}
#endregion
}
}
}
Now, call the above method in your Controller Action to access to your Views HTML and pass Your View Name and Your Model Name ( If you have no model, pass null):
public ActionResult YourControllerAction()
{
//....
StringReader htmlView = this.ViewToString("YourViewName", YourModelObject);
//Now htmlView containing the HTML of Your View
//and you can pass it to your Email function .....
// ...
}
htmlView will contain the HTML from Your view ...
Hope this would of some help ...
So this is how we are doing it finally...(our page does not contain any secure data so we have gone for this)
Added a hidden field to hold the html
Use the javascript method to set the hidden field with the encoded page html
var html1 = $('#wrapper').html();
var encodedString = escape(html1);
Changed the controller to take the hidden field as a parameter. (to pass the encoded html)
Unescaped the html using
var html = System.Uri.UnescapeDataString(pageHtml);
Related
Lets say I have a ViewComponent named MyComponent.
As of ASP.NET Core 1.1 I can render this ViewComponent by writing this inside a razor view .cshtml page:
<vc:my-component></vc:my-component>
I want to do something like this:
#{string myHtml = "<vc:my-component></vc:my-component>";}
#(new HtmlString(myHtml))
I installed and tried RazorEngine by doing this, but this did not work:
string template = "<vc:my-component></vc:my-component>";
var result = Engine.Razor.RunCompile(template, "messageTemplateKey", null, new { Name = "some model data" });
ViewBag.result = result;
then in the .chtml file:
#(new HtmlString(ViewBag.result))
The backstory to this is that I've created a ViewComponent with some logic on how to handle image files, now I want to search and replace all img tags in some html with my ViewComponent. Before I do that I need to make sure this even works.
Check the code at this url on github:
https://gist.github.com/pauldotknopf/b424e9b8b03d31d67f3cce59f09ab17f
Code
public class HomeController : Controller {
public async Task<string> RenderViewComponent(string viewComponent, object args) {
var sp = HttpContext.RequestServices;
var helper = new DefaultViewComponentHelper(
sp.GetRequiredService<IViewComponentDescriptorCollectionProvider>(),
HtmlEncoder.Default,
sp.GetRequiredService<IViewComponentSelector>(),
sp.GetRequiredService<IViewComponentInvokerFactory>(),
sp.GetRequiredService<IViewBufferScope>());
using (var writer = new StringWriter()) {
var context = new ViewContext(ControllerContext, NullView.Instance, ViewData, TempData, writer, new HtmlHelperOptions());
helper.Contextualize(context);
var result = await helper.InvokeAsync(viewComponent, args);
result.WriteTo(writer, HtmlEncoder.Default);
await writer.FlushAsync();
return writer.ToString();
}
}}
This is what I ended up doing:
I moved the view code from the Default.cshtml for MyComponent to a partial view (_myPartial).
Then I used a IViewRenderService inspired by this post.
Then I could render and get my html string after passing in the viewmodel by doing this:
var result = ViewRenderService.RenderToString("_myPartial", viewModel);
In my ASP.NET MVC project I have a controller that one action just result view. This Action does not get any argument and just return a CSHTML page. This page could not be partial.
Does anybody know a better way to generate view - I mean can I generate view without controller action?
//Edit - sample codes
Right now in my UserPanelController i have an action ChangeSettings
[HttpGet]
public ActionResult ChangeSettings()
{
return View("Configuration");
}
So if i want to get a configuration View i have to do request to controller from for example navigation:
<nav>
<div class="nav-wrapper">
Logo
<ul id="nav-mobile" class="right hide-on-med-and-down">
<li>Sass</li>
<li>Components</li>
<li>Konrad</li>
</ul>
</div>
</nav>
Can i get a ConfigurationView without my controller action?
Maybe I'm a bit too late but what you are probably looking for is this:
#{ Html.RenderPartial("_PartialViewName"); }
Notice that you can use a model in your view as well, by passing it directly from the view that is calling the partial one.
You can render a view yourself by calling the following method
private static string RenderPartialViewToString(Controller controller, string viewName, object model)
{
controller.ViewData.Model = model;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.ToString();
}
}
This will give you html string containing your rendered view. I've used this before to render HTML for emails where the email content changed from user to user.
Hope this helps.
If it is static content, you can add an .html file inside your project. The web server will serve it.
To make sure the MVC routing will not interfer you can add something like this to your routes:
routes.IgnoreRoute("{file}.html");
I am having an issue with the controller action where I upload an image and the initial POSTed result is displayed in the view without issue. The image is shown normally.
If I refresh or change pages and return, the image will no longer display.
I have checked what the controller action is returning, and it does indeed return the content to the view.
This is the IMG tag that I'm using to call the controller action.
<img src="#Url.Action("Display", "Home")" />
This is the controller action:
public ActionResult Display()
{
var tempModel = new PartialModel();
tempModel = (PartialModel)Session["Model"];
var ImageUpload = tempModel.ProductImage;
if (ImageUpload != null)
{
byte[] content = new byte[ImageUpload.ContentLength];
ImageUpload.InputStream.Read(content, 0, ImageUpload.ContentLength);
return File(content, ImageUpload.ContentType);
}
return null;
}
This is the create action that receives the POST values:
public ActionResult Create(PartialModelStore p)
{
Session.RemoveAll();
//m.initializeModelLists(p);
Session["Model"] = p;
//return View("Index", p);
return RedirectToAction("Index");
}
I'm using the Session to store values because this is just a mock up application.
I have looked into using Data URI but I need to support older browsers, thus I'm using this method.
straight forward question , can't seem to get my viewBag value to display in a view that the user is directed to after completing a form.
Please advise..thanks
My Index ActionResult simple returns model data..
public ActionResult Index()
{
var source = _repository.GetByUserID(_applicationUser.ID);
var model = new RefModel
{
test1 = source.test1,
};
return View(model);
}
My Get Edit" ActionResult , simply uses the same model data as Index.
My Post "Edit" ActionResult, assigns the new values if any to the model and redirects to the Index page, but Index page does not display ViewBag value ??
[HttpPost]
public ActionResult Edit(RefModell model)
{
if (ModelState.IsValid)
{
var source = _repository.GetByUserID(_applicationUser.ID);
if (source == null) return View(model);
source.test1 = model.test1;
_uow.SaveChanges();
#ViewBag.Message = "Profile Updated Successfully";
return RedirectToAction("Index");
}
return View(model);
}
And in my Index view...
#if(#ViewBag.Message != null)
{
<div>
<button type="button">#ViewBag.Message</button>
</div>
}
ViewBag only lives for the current request. In your case you are redirecting, so everything you might have stored in the ViewBag will die along wit the current request. Use ViewBag, only if you render a view, not if you intend to redirect.
Use TempData instead:
TempData["Message"] = "Profile Updated Successfully";
return RedirectToAction("Index");
and then in your view:
#if (TempData["Message"] != null)
{
<div>
<button type="button">#TempData["Message"]</button>
</div>
}
Behind the scenes, TempData will use Session but it will automatically evict the record once you read from it. So it's basically used for short-living, one-redirect persistence storage.
Alternatively you could pass it as query string parameter if you don't want to rely on sessions (which is probably what I would do).
RedirectToAction causes an HTTP 302 response, which makes the client make another call to the server and request a new page.
You should be returning a view instead of redirecting.
The RedirectToAction(msdn) instructs your browser to make a new request.
So your server will be called again but it will be a new request with a blank viewbag and all
You could do a sort of internal redirect by just calling the index method, this way the viewbag will still have its data.
Edit : you'll also have to modify your index method or your View(model) line will try to render the edit. Full code below
public ActionResult Index()
{
var source = _repository.GetByUserID(_applicationUser.ID);
var model = new RefModel
{
test1 = source.test1,
};
return View("Index",model);
}
[HttpPost]
public ActionResult Edit(RefModell model)
{
if (ModelState.IsValid)
{
var source = _repository.GetByUserID(_applicationUser.ID);
if (source == null) return View(model);
source.test1 = model.test1;
_uow.SaveChanges();
#ViewBag.Message = "Profile Updated Successfully";
return Index();
}
return View(model);
}
You can try this way also
Controller
public ActionResult Test()
{
ViewBag.controllerValue= "testvalue";
..................
}
View -
define top of razor page
#{string testvalue= (string)ViewBag.controllerValue;}
$(function () {
var val= '#testvalue';
});
I would like to render a PartialView to an HTML string so I can return it to a SignalR ajax request.
Something like:
SignalR Hub (mySignalHub.cs)
public class mySignalRHub: Hub
{
public string getTableHTML()
{
return PartialView("_MyTablePartialView", GetDataItems()) // *How is it possible to do this*
}
}
Razor PartialView (_MyTablePartialView.cshtml)
#model IEnumerable<DataItem>
<table>
<tbody>
#foreach (var dataItem in Model)
{
<tr>
<td>#dataItem.Value1</td>
<td>#dataItem.Value2</td>
</tr>
}
</tbody>
</table>
HTML (MySignalRWebPage.html)
<Script>
...
//Get HTML from SignalR function call
var tableHtml = $.connection.mySignalRHub.getTableHTML();
//Inject into div
$('#tableContainer).html(tableHtml);
</Script>
<div id="tableContainer"></div>
My problem is that I can't seem to render a PartialView outside of a Controller. Is it even possible to render a PartialView outside of a Controller? It would be very nice to still be able to leverage the awesome HTML generating abilities that come with Razor.
Am I going about this all wrong? Is there another way?
Here, this is what I use in Controllers for ajax, I modified it a bit so it can be called from method instead of controller, method returnView renders your view and returns HTML string so you can insert it with JS/jQuery into your page when you recive it on client side:
public static string RenderPartialToString(string view, object model, ControllerContext Context)
{
if (string.IsNullOrEmpty(view))
{
view = Context.RouteData.GetRequiredString("action");
}
ViewDataDictionary ViewData = new ViewDataDictionary();
TempDataDictionary TempData = new TempDataDictionary();
ViewData.Model = model;
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(Context, view);
ViewContext viewContext = new ViewContext(Context, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
//"Error" should be name of the partial view, I was just testing with partial error view
//You can put whichever controller you want instead of HomeController it will be the same
//You can pass model instead of null
private string returnView()
{
var controller = new HomeController();
controller.ControllerContext = new ControllerContext(HttpContext,new System.Web.Routing.RouteData(), controller);
return RenderPartialToString("Error", null, new ControllerContext(controller.Request.RequestContext, controller));
}
I didn't test it on a Hub but it should work.
Probably the best choice is to use RazorEngine, as Wim is suggesting.
public class mySignalRHub: Hub
{
public string getTableHTML()
{
var viewModel = new[] { new DataItem { Value1 = "v1", Value2 = "v2" } };
var template = File.ReadAllText(Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
#"Views\PathToTablePartialView\_MyTablePartialView.cshtml"));
return Engine.Razor.RunCompile(template, "templateKey", null, viewModel);
}
}
Further to the answer provided by #user1010609 above, I struggled through this as well and have ended up with a function that returns the rendered PartialView given a controller name, path to the view and model.
Takes account of the fact you don't have a controller and hence none of the usual state as coming from a SignalR event.
public static string RenderPartialView(string controllerName, string partialView, object model)
{
var context = new HttpContextWrapper(System.Web.HttpContext.Current) as HttpContextBase;
var routes = new System.Web.Routing.RouteData();
routes.Values.Add("controller", controllerName);
var requestContext = new RequestContext(context, routes);
string requiredString = requestContext.RouteData.GetRequiredString("controller");
var controllerFactory = ControllerBuilder.Current.GetControllerFactory();
var controller = controllerFactory.CreateController(requestContext, requiredString) as ControllerBase;
controller.ControllerContext = new ControllerContext(context, routes, controller);
var ViewData = new ViewDataDictionary();
var TempData = new TempDataDictionary();
ViewData.Model = model;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, partialView);
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
You would call it with something similar to:
RenderPartialView("MyController", "~/Views/MyController/_partialView.cshtml", model);
Have you thought about using a razor template engine like http://razorengine.codeplex.com/ ?
You can't use it to parse partial views but you can use it to parse razor templates, which are almost similar to partial views.
How about using the RazorEngineHost and RazorTemplateEngine. I found this nice article that might be what you're looking for. It's about hosting Razor outside of ASP.NET (MVC).
Based on the answers supplied to asimilar question below, I would suggest using
Html.Partial(partialViewName)
It returns an MvcHtmlString, which you should able to use as the content of your SignalR reponse. I have not tested this, however.
Stack Overflow Question: Is it possible to render a view outside a controller?