Generate view without controller action - c#

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");

Related

How to pass a TempData to my _Layout.cshtml view

In my _Layout.cshtml I have a navbar that I would like to upload with a picture of the user logged into the system. In other parts of the code I can normally pass the data I want, however, I don't know how to pass a TempData with the photo link to the Layout.
This is the TempData that I use on my controllers and I would like to send it to _Layout.cshtml
var information = _employee.ReturnsDataFunctional (userUser);
TempData["photo"] = information[0]["photo"];
Set your data into a ViewBag variable on the ActionMethord.
public IActionResult Index()
{
var information = _employee.ReturnsDataFunctional (userUser);
var photo = information[0]["photo"];
ViewBag.photo = photo;
....
....
....
return View();
}
Then call it on your _Layout.cshtml
<div class="round avatar" id="profilepic">
<img src="#ViewBag.photo"/>
</div>

Execute a controller from view in ASP.NET MVC - Razor

I am trying to print the name of the user who executes my web app. It is written in MVC-Razor.
From the initial View, I would to execute the controller below:
[Authorize]
public ActionResult Check()
{
var check = new CheckAD();
var user = new User {Name = check.CheckSecurityWithAD()};
if (!string.IsNullOrEmpty(user.Name))
{
return View("Checked", user);
}
var errors = new ErrorsModel()
{
Messages = new List<string>(){"You don't have permission"}
};
return View("Error", errors);
}
This controller returns another view if the user is correctly authenticated:
#model UsersActivationWeb.Models.User
#{
ViewBag.Title = "Checked";
}
#{ <p> Logged come #Model.Name </p>};
How can I print the second view (I think it's a partial view) in the first one using the controller?
Thanks
Sounds to me like you need an Html.Action. This will run the controller code and display the view contents that are produced where you place the call.
Most likely you will need this overload, Html.Action(string actionName, string controllerName).
Assuming the controller is called CheckController. In your initial view call it like this
#Html.Action("Check","Check")
Since you don't want people navigating to the Check view you should give it a ChildActionOnly attribute so it looks like this
[Authorize]
[ChildActionOnly]
public ActionResult Check()
{
//rest of code
}
Finally you almost certainly don't want the layout contents to appear with the Checked view so change your Checked view to this
#model UsersActivationWeb.Models.User
#{
Layout = null;
}
#{ <p> Logged come #Model.Name </p>};
Since you are doing authorization logic in the Check action you might not need the Authorize attribute. I say that because with it a user not logged in will not get the error or their name. Maybe you want this though, I'd need to know more about your code to say for sure.
This way you will either get the name of the user or the errors as required.

ASP MVC and changing url of posted form

I have an MVC 4 app and I am using a RESTful methodology for my URLs. I have the following routes registered in my app (along with others that are not relevant to my question:
//EDIT
routes.MapRoute(alias + "_EDIT", alias + "/{id}/edit",
new { controller = controllerName, action = "edit" },
new { httpMethod = new RestfulHttpMethodConstraint(HttpVerbs.Get) });
//PUT (update)
routes.MapRoute(alias + "_PUT", alias + "/{id}",
new { controller = controllerName, action = "update" },
new { httpMethod = new RestfulHttpMethodConstraint(HttpVerbs.Put) });
I have the following methos in my controller mapping to these routes:
public override ActionResult Edit(int id)
{...}
public override ActionResult Update(RequestEditViewModel userModel)
{
if (!ModelState.IsValid)
{
//do some stuff to ensure lookups are populated
...
return View("Edit", userModel);
}
}
In my app when I perform a request to edit a request my URL looks like:
http://server/request/1/edit
it correctly calls the Edit method on my controller.
My Edit.cshtml uses the followng to ensure the Update method is called on PUT:
#using (Html.BeginForm("Update", "Request"))
{
#Html.HttpMethodOverride(HttpVerbs.Put);
...
}
My form is generated as follows:
<form action="/requests/71" method="post" autocomplete="off" novalidate="novalidate">
<input name="X-HTTP-Method-Override" type="hidden" value="PUT"/>
...
</form>
When I click the submit button it correctly calls my Update method.
OK...Now for the issue. If my model is NOT valid I want to return back the Edit model. As you can see in the above code but, the URL is the one called from the submit button:
http://server/request/1
not
http://server/requests/1/edit
I have tried an reviewed two other options but both of these redirect the request back through the Edit method again which adds additional overhead and also puts all the model values in the querystring which I do NOT want:
return RedirectToAction("Edit", userModel);
return RedirectToRoute("requests_Edit", userModel);
So, is there a way to just return the View as I have in my code but, ensure the URL changes back and include the "/edit"?
The only alternative I have come up with is to perform an AJAX call and put the update that way the URL never changes, but I was trying to avoid that for this form.
Conceptually, you want to be doing something like a Server.Transfer (that is, making on URL appear to be another.) This discussion may be of use to you:
How to simulate Server.Transfer in ASP.NET MVC?

MVC3 Model In Layout As Partial

I'm trying to utilize the MVC3 model validation in my project as of current, however I want to have a simple login section to show in the layout at all times if the user is not logged in. I have the majority of code in place, however the only thing I'm stuck on is how I can post the model back to the form for any validation messages that I produce and need to return.
Normally something like this will work:
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(LoginModel)
{
if(ModelState.IsValid())
{
//Run Further checks & functions
//Upon successful login, retuns to somewhere (Just site index in this example)
return RedirectToAction("Index", "Site");
}
return View(model);
}
Now obviously this won't work as I can't return View(model); on the partial unless I just want the login form to be displayed, however I want it to post back to the page that I have been editing from. For example: I navigate to a certain page, contact us, and want to login now. I enter my details on the form that is always available and I enter my details. An error occurs (Incorrect password, incorrect login, account doesn't exist etc...) and I should be brought back to the contact page with the form still filled in with the details that I entered (except obviously password) with validation summary working etc...
Also, any forms on the page that the layout has rendered still need to work correctly (with models etc)
I'm open to suggestions on how to get this working by other means of submission/return however it would be ideal to have the MVC model validation working.
If anyone needs me to elaborate on anything said, feel free to comment. I'll be actively responding for a while.
you should create a partial view for login and instead of using "#Html.BeginForm" use #Html.AjaxBegin which submit your page by Ajax call and it RenderHtmlString of login view.
for e.g
public ActionResult Login(LoginModel)
{
if(ModelState.IsValid())
{
//Run Further checks & functions
//Upon successful login, retuns to somewhere (Just site index in this example)
return RedirectToAction("Index", "Site");
}
return RenderPartialViewToString("Login",model);
}
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();
}
}
after adding "RenderPartialViewToString" method which will return you "RenderHtmlString" of your partial view. you must be pass viewName and Model as parameter to this Method.
in your partail View.
<div id="targetId">
</div>
#using(Ajax.BeginForm("Login",new AjaxOptions{ HttpMethod="POST", UpdateTargetId="targetId"}))
{
<input type="submit" value="save" />
}
Note: you must be pass UpdateTargetId there your result will Append.
See this question: How do I pass value to MVC3 master page ( _layout)?
There are complete guide what to do to pass your model to layout

Render MVC PartialView into SignalR response

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?

Categories