How to load a Razor view and render it on the fly? - asp.net-mvc-3

I have a custom CMS built with ASP.NET WebForms (you can see it in action at Thought Results). Now I want to build it using ASP.NET MVC 3 (or even 4). I don't want to change the architecture that much, therefore, I need to dynamically load a Razor View, and dynamically run a Model Loader method, and give the model to the view dynamically, then render the view, and return the result rendered string, all done in server.
In ASP.NET WebForms, my code is:
string renderedString = "LatestArticles.ascx".LoadControl().GetReneredString();
Now, I'd like to be able to write a code line like:
string renderedString =
"LatestArticles.cshtml".LoadView().BindModel("ModelBinderMethodName").Render();
I know about many questions about rendering a view (view to string), but I didn't find what I want.

You may checkout RazorEngine.

Related

How to set global viewmodels in ASP .NET Core 3.1?

I am new to ASP.NET Core and have some trouble with binding global models and viewmodels to razor views. My application is a mixture of Web API and MVC with razor views.
My goal
When I open an ASP.NET MVC page, I need to instantiate a model by loading it from the database (DbContext service) based on an id received in a cookie. I want to use this model object globally in every view or partial view.
Current Implementation
I can access the cookies in action methods of page controllers, so that I have to load the model from the DbContext in every action method and bind it as viewmodel to target view. This is not practical, because I have to do this in every page controller, because I need that model object on all pages in my navigation pane.
Idea
I think it should be possible to access to Cookies and dbcontext within Startup.cs and bind the model object to _ViewStart.cshtml, so that it is accessible globally in every view or partial view. Even this approach were correct, I do not have any idea how the code would look like. Because I am learning Web-Apps with .NET Core by learning by doing and try and error at the moment. :(
UPDATE
I have a layout page _Layout.cshtml, which includes partial views like the _NavPane.cshtml. My goal is to pass a Model object to the _Layout, which is instantiated via loading from the database (I have a service IMandantRepository for this purpose) and dependent on a cookie.
That model object is needed on every page request. That's why it would be a better practice to load the model object outside the MVC page controllers and pass it to them (what I can not implement technically).
I tried to find a solution by myself and ended up in following interim ugly solution. Following is the content of the _ViewStart file. On the bottom I assign the needed global variables, which I can use in every view or partial view.
This solution has at least two disadvantages:
The model object is possibly loaded redundantly.
Too many program logic in a view file.
#inject MyProject.Data.IMandantRepository mandantRepo
#{
// Main layout template
Layout = "_Layout";
// Define default values
bool showAdminSection = false;
string src = "/images/logos/nologo.png";
// Read cookie value
string currentMandantUid;
Context.Request.Cookies.TryGetValue("currentMandant", out currentMandantUid);
// Load mandant from the database
var thisMandant = mandantRepo.GetMandantByUid(currentMandantUid);
if(thisMandant is Mandant){
src = "data:image/*;base64," + thisMandant.GetBase64Logo();
showAdminSection = thisMandant.Abbr == "AdminMandant";
}
// Assing global variables to ViewData
ViewData["CurrentMandant"] = thisMandant;
ViewData["logoSrc"] = src;
ViewData["showAdminSection"] = showAdminSection;
}
This is an example code in ConfigureService() of Startup.cs. You can register your dbContext class in this way.
services.AddDbContext<BookStoreContext>( options =>
options.UseSqlServer(_configuration.GetConnectionString("DefaultConnection")));

mvc3 - set focus to control from Controller

Can I set focus to a control from a Controller when calling a View?
(I understand the typical best practice is to use jQuery to set focus to a control when the page is loaded.)
The controller's job (one of them) is to set up a view model which gives the view enough information to render correctly. In other words, the controller and the view should only be loosely coupled.
Here's one way to do it. This is somewhat decoupled though it could be done more elegantly. You still need JavaScript to perform the client-side scripting, but the script is generated based on a value in the view model.
Controller
public ActionResult Foo(){
var model = new MyViewModel();
model.SelectedItem = "FirstName";
return View( model );
}
View
#model MyViewModel
#Html.TextBoxFor( o => o.FirstName )
#if( Model.SelectedItem != default( string ) ){
<script>$("##(Model.SelectedItem)").focus();</script>
}
One thing you have to learn about web development is that you can have all the technologies in the world on the server, but in the end, those technologies have to generate standard (or what passes for it) Html, CSS, and JavaScript.
That means there is no special magic that can be done on the server to automatically do things on the client. Some frameworks can automatically generate code to do this for you, but it still must be done as standard html/css/js in the end.
MVC only renders standard, plain HTML. Webforms will do a lot of things for you, but in the end Webforms has to generate standard HTML as well. It does this by auto generating javacript that gets included in the page that, on load sets the focus.
MVC doesn't do any of those things for you, so you would basically have to do the same thing, but you would have to write it. It's relatively simple using some simple jquery.

Knockout JS, MVC 3 and View Model Server Side Data as JSON

So I have a problem...I am separating concerns in my web app: HTML in razor pages and JS in js files. My problem lies in the fact that I want to use data from my controller passed down in the view model from the server as the options of a select list. The problem lies in the fact that I have separated my js from my HTML and I can't access Razor inside the js files.
I have a list of items coming down into my view model...
public List Stuffs { get; set; }
I json encode it server side and make sure to take care of circular refrences, so it looks like this
[{"id":1,"name":"blah"},{"id":2,"name":"blah2"},{"id":3,"name":"blah3"},{"id":4,"name":"blah4"}]
The problem is, I want to keep my separation of concerns, so how do I get that array into my js file so I can bind it to a select list using knockout? I definitely don't want to do another round trip to the server.
So lets say you have some view that looks like this:
<div> (Some stuff) </div>
<script type="text/javascript">
var initialData = //Your JSON
<script>
And then in your javascript (which you have linked below your view, so that it loads after it), you have something like this:
var data = initialData || {} //Or some other default value, in case initialData wasn't set
This will load in the initialData if it was set, or use nothing (or a default your define) if it wasn't. Loosely coupled.
Of course, more complex data will require you to standardize the strucure, but this is essentially one method that allows you to pull in data from the razor generated View without tightly coupling it to your javascript file.
Does your Javascript file contain a view model in the form of an instantiable function, e.g. something like:
function MasterVM(data)
or an object literal, e.g.
var masterVM = { ...
? I tend to go for instantiable view models (partly because they chain down through a hierarchy of view models using the mapping plugin - the top level one builds its children) and that being the case I think it's nice for the Razor view to instantiate the view model with the JSON rendered from the MVC view model, e.g.:
var masterVM = new MasterVM(#(Html.Raw(JsonConvert.SerializeObject(Model.ProductViewModel))));
Or even have the Knockout view model "owned" by a revealing module and initialise it like:
productModule.init(#(Html.Raw(JsonConvert.SerializeObject(Model.ProductViewModel))));
Then productModule is also responsible for other things like mediating between your view model(s) and the server, watching for dirty state, etc.
Also, doing another round trip to the server is not necessarily bad if you are sourcing a massive set of reusable options which you'd like the browser to cache. If you are, you might want to have an MVC controller which emits a big object literal containing all of your commonly used options, which you can then use as the "options" property across multiple selects. But if your options are specific to the particular view model, then I guess they have to be part of your view model.

MVC3 Finding a control by its Name

I have a C#.Net web app and I am trying to access one of the HTML/ASP Text Boxes in the Controller for the Edit View of my Proposal model. In a non-MVC app, I was able to do this using Control.ControlCollection.Find(). Is there an equivalent for a MVC3 project?
You ask for an equivalent of Control.ControlCollection.Find() in MVC?
In MVC your controller is not aware of controls.
The controller just receives data via parameters and returns data via the function result.
What do you want to do with the control in your controller code?
If you want to access the value, you should bind it to a parameter:
View:
<input name="MyControl" type="text" />
Controller:
public ActionResult MyAction(string MyControl) {
// MyControl contains the value of the input with name MyControl
}
The MVC pattern was designed to keep things separated.
The View has no knowledge of the controller at all
The Controller only knows that a view exists and what kind of data that it needs. It do not know how the data is render.
Hence, you can never get information about controls/tags in the view from the controller. You need to use javascript/jQuery in the view and invoke the proper action in the controller.
In an MVC-application you don't have controls like in a webform-application.
In MVC you collect your required data in the controller and pass it to the view.
Typicaly the view is a HTML-page with embedded code.
In opposite to controls in webforms which produce HTML and handles the post-backs in MVC you have to do all this manually. So you don't have controls with properties and events wich you can access easily in the controller and you have to handle all your posts with your own code.
Thats sounds as it is a lot of more work - and indeed it could be if you implement the behaviour of complex controls - but MVC applications are much better to maintain and you have 100% influence to the produced HTML.
Well probably i am late for this but it should help others in future...u can store ur value in hidden field in view and then access that value in controller by following code..
Request.Form["hfAnswerOrder"].ToString();
Point - hfAnswerOrder is the ID of the hidden field
My Control in cshtml page..
#Html.Hidden("hfAnswerOrder", Model.Answers.ToList()[0].AnswerOrder)

How does ASP.NET MVC arbitrate between two identically named views (aspx and razor)?

Using ASP.NET MVC3 I created a new Razor view and gave it the same name as the existing .aspx view that I had been using. I noticed that controller continued to pick up the .aspx view (which has the same name as the action) which is pretty much what I expected. I then renamed the .aspx view and action picked up the razor .cshtml view.
So if I have two views called myview.aspx and myview.cshtml and an Action called MyView() that does a return View(), it will pick up the myview.aspx view and return that.
How does MVC3 decided which view-type to default to?
Is there a way to change this default behavior to prefer a razor view over an .aspx view?
Everything stems down to the order of view engines in the ViewEngines.Engines collection. Here's how the ViewEngines static constructor looks like (as seen with Reflector in ASP.NET MVC 3 RTM):
static ViewEngines()
{
ViewEngineCollection engines = new ViewEngineCollection();
engines.Add(new WebFormViewEngine());
engines.Add(new RazorViewEngine());
_engines = engines;
}
which explains why WebForms is the preferred view engine.
So you could perform the following grotesque hack in Application_Start to inverse the preference towards Razor :-)
var aspxVe = ViewEngines.Engines[0];
var razorVe = ViewEngines.Engines[1];
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(razorVe);
ViewEngines.Engines.Add(aspxVe);
I would imagine its down to the order in which view engines are registered. Earlier registered view engines will be queried first. If you want to change the order:
ViewEngines.Engines.Insert(0, ...);

Resources