I have an ASP.NET MVC application that I need to add content management pages to. Since it's CMS the path of the pages are going to be variable. I am trying to figure out how to get ASP.NET to display a view that is variable. What does the controller look like?
The code would be something like this:
Dim MyView As New System.Web.Mvc.ViewResult()
Return MyView
But that doesn't let me define the content of the view, which I'm not sure how to do. The view does not physically exist; I need to dynamically generate it from data within my database. I am storing the HTML in the database.
You can create your content "by hand", without Razor views and return Content with the generated HTML instead of View in your action method.
EDIT:
Or, create a master view with all the common elements that accepts generated content as a string:
#model string
<html>
<!-- all the common stuff here -->
#Html.Raw(Model)
<!-- more common stuff -->
</html>
Your controllers would generate the HTML and pass it to this view:
public ActionResult Index()
{
var html = GenerateContent(); // or whatever
return ActionResult("MasterView", (object)html);
}
It's important to cast the second parameter to an object as otherwise it would be interpreted as layout location.
If you need to insert the generated content between common components you can pass a dictionary of strings as a model and render just the part you like, eg. Html.Raw(Model["footer"])
What does the controller look like?
public ActionResult Index()
{
string dynamicViewName = "~/Views/Shared/FooBar.cshtml";
return View(dynamicViewName);
}
You could also specify a Layout if you wish:
public ActionResult Index()
{
string dynamicViewName = "~/Views/Shared/FooBar.cshtml";
string dynamicLayout = "~/Views/Shared/_SomeLayout.cshtml";
return View(dynamicViewName, dynamicLayout);
}
Related
We are working on an MVC application. As per requirement, we need to populate a VIEW using a method. I have created a sample application. You can see the method which is using to generate control in Helper.cs class under “Controller” folder. When we directly placing the #Html.TextBox("SampleTextBox") code in the view it is rendering correctly. But when we generate the same code using a method, it is not rendering properly and it is showing as a plain string.
If anybody has any idea regarding this please let us know, it would be very helpful.
Sample code
Instead of adding the following code directly to view, we need to populate it using a method.
#Html.TextBox("SampleTextBox")
That is some thing like
#Html.Raw(Helper.GetStringCode())
Method:
public static string GetStringCode()
{
return "#Html.TextBox(\"SampleTextBox\")";
}
You could add a partial view for the Kendo Grid in the Shared folder and add an Html helper extension that returns your partial view:
Partial view Shared/_KendoGrid.cshtml:
#model CustomViewModel
#(Html.Kendo().Grid()...)
Html helper method:
public static MvcHtmlString KendoGrid(this HtmlHelper helper, string header)
{
return helper.Partial("Shared/_KendoGrid", new CustomViewModel { Header = header });
}
In your .cshtml:
#Html.KendoGrid("Custom header")
i have layout of 4 pages and at header i need to access name of logged in admin. how to access that database model in admin in starting of layout i have added
#model ProjectName.Models.Admin
and while accessing name from admin i am writing
#Model.Name
it gives error how to do it in proper way to access that attribute in Layout and it cant be partial view it should be layout so kindly help
As #Stephen Muecke stated in his comment on your question, there are more ways how you can do that. I would recommend you to keep your Layout view without model. Otherwise as #Stephen Muecke mentions, you would have to make types of models for each view that uses that layout of either the same or derived type, which would add unnecessary complexity to your code.
So the other way is to call HtmlHelper.Action(...) or HtmlHelper.RenderAction() in your layout view at the place when you'd like to render user's name. Example:
Layout page:
...
<div class="admin-name">
#{ Html.RenderAction("AdminName", "Partial"); }
</div>
...
Add a controller:
public class PartialController : Controller {
[ChildActionOnly] // action cannot be requested directly via URL
public ActionResult AdminName() {
string adminName = ...; // assign value to adminName variable
return Content(adminName);
}
}
You need logged in user details in so many pages in application, so better to store logged in user details in Session and you can retrieve session value in any view/partial view.
Other Solution:
Make your header partial view and call from Layout
Html.RenderAction("actionName", "controllerName")
Create an action method in your controller which returns partial view
Controller Action Method
[HttpGet]
public ActionResult Header()
{
HeaderModel HM = new HeaderModel()
// Your user information in HeaderModel
return PartialView("Header", HM)
}
_layout.cshtml
<body>
<div>
#{Html.RenderAction("Header", "ControllerName");}
</div>
</body>
I hope this will resolve your problem.
Is there a way by which I can do somethin like this inside a Razor view:
<h1>Normal razor code</h2>
#Html.Action("NormalRazorCode")
#Eval(" #Html.Action(\"RuntimeEval\") ")
Basically a text-to-razor compiler at runtime (that doesnt create a whole new view like RazorEngine does for example).
I think you could assume that the views exist at compile time, and create the actual files at runtime, this way the ViewEngine will work the way it does by default
basically you could create a Html.Eval helper that will create the .cshtml file and after Render it using Html.Action or Html.Partial
I wanted to do something similar; I have model data (under my control) stored in a database, and it would simplify my life if I was able to include HTML helpers in those strings that could be "expanded" when included in a page.
Main motivation was to allow me to re-use existing partial views.
There's no eval function, but you can easily write an extension method that will evaluate methods that you choose to allow in advance. In my case, I want to evaluate calls to #Html.Partial(). The example here is pretty simple - it looks specifically for #Html.Partial("somePartialView") calls and replaces it with the actual partial:
public static IHtmlString ExpandHtmlString(
this HtmlHelper htmlHelper,
String html)
{
if (String.IsNullOrEmpty(html))
return new HtmlString(html);
const String IDENTIFY_PARTIAL = #"#Html.Partial\(""([a-zA-Z0-9\-_]*)""\)";
var partialFinder = new Regex(IDENTIFY_PARTIAL);
var matches = partialFinder.Matches(html);
foreach (Match m in matches) {
var matchedStr = m.Value;
var viewName = m.Groups[1].Value;
var partial = htmlHelper.Partial(viewName);
html = html.Replace(matchedStr, partial.ToHtmlString());
}
return new HtmlString(html);
}
And you call it from your Razor page as so:
#Html.ExpandHtmlString((String)Model.SomeStringField)
You could easily expand on this to to evaluate a set of methods or operators that you decide in advance you will accept.
I have one page that will contain a lot data.
Outline of the page is on the image.
For output I have used "razor" engine.
Now I wonder will I get something if I refactor my code so each section
which data comes from database will be partial view?
On this page I need about 20 value objects to display all needed data.
I have made one "ViewModel" class that contains all data I need and set that
viewModel class as razor page model. Is this the right way how I should do this or
there is some smarter way?
public class MyViewModelClass{
public ValueObjectx x;
public ValueObjecty y;
public ValueObjectz z;
public List<ValueObjectT> tList;
public List<ValueObjectG> gList;
public List<ValueObjectS> sList;
}
In a scenario like this I would typically have each section as a partial view. Each section is responsible for it's own layout and ViewModel. This prevents the tendency to have a super view which has to know about too many things in order to render.
I would not use one ViewModel for all the data. I would only use the ViewModel for the data that might actually be posted back to the server. For all the other data, like lists, I would put it on the ViewBag. Like:
public ViewResult SomeAction()
{
var model = GetYourModelData();
ViewBag.TList = GetTList();
ViewBag.GList = GetGList();
ViewBag.SList = SList();
return View(model);
}
You could put all the lists in a separate helper object if you use them a lot.
Note that this is not a "this is how you should do it answer", it is more a description of what works for me. But as I see it the model of the view is one thing and the actual data, as data in drop downs etc., on the view is another thing and should be put in the ViewData property, but the ViewBag is just a dynamic wrapper around the ViewData property. You can then use the properties on the ViewBag as input to your partial views that should make up each of your sections.
Is it possible to detect a route value in a view?
Such as /pages/create/1 and I want to check to see if 1 is there?
Basically, I want to render a different partial view based on this value though I'm fairly sure this is probably not the best way to go about what I'm trying to achieve.
On a side note, instead of doing the above is it possible for me to be able to change what partial views are rendered in a view based on a value from within my controller?
ViewContext.RouteData.Values["whatever"]
You can inspect a RouteData object through ViewPage.ViewContext.RouteData. Then check for values using something like
string areaname = routeData.Values["area"] as string;
string controllername = routeData.Values["controller"] as string;
string actionname = routeData.Values["action"] as string;
string id = routeData.Values["id"] as string;
If you find that you want to inspect these values in the controller instead, you can access them using ControllerBase.ControllerContext.RouteData. Something similar applies for action filters etc.
Other answers are correct, but thought i'd address your last sentence:
On a side note, instead of doing the above is it possible for me to be able to change what partial views are rendered in a view based on a value from within my controller?
Well partial view's are rendered in the View itself (unless calling from JavaScript and binding directly to DOM) with the following code:
<%: Html.RenderPartial("SomePartial") %>
So to prevent "code soup" (if statements) in your view, you use a HTML helper which calls through to RenderPartial after inspecting the ViewContext:
public static string RenderCustomPartial(this HtmlHelper helper, RouteData rd)
{
string partialName;
if (rd.Values["SomeParam"] == 1)
partialName = "PartialOneName";
else
partialName = "PartialTwoName";
return helper.RenderPartial(partialName);
}
And then in the View:
<%: Html.RenderCustomPartial(ViewContext.RouteData) %>
You could make some mods to the above - like access the route data directly in the extension, pass through the model to bind in the partial, etc - but you get the idea.
Alternatively you could do the above IF statement in your controller, and stuff the partial view name in the ViewData, then use that in the regular RenderPartial call in your View.
Whatever floats your boat. :)