Asp.net MVC way to pass data to _layout.cshtml? - asp.net-mvc

I keep reading that the MVC way to pass data from a controller to the view is done via a ViewModel, but what about passing data to _Layout.cshtml, like page title, meta description, article author, etc...
What's the MVC way to pass this kind of data? Should I just use ViewBag for them?

You have few ways:
ViewBag
ViewData
View Components
Injections (example below)
ViewBag and ViewData are quite easy to use, however not always convenient.
There is one big plus - you could set/read them in one place of view and read in another - for example, you could set them in your main view and read/display them in _lauout.cshtml.
View Components are the most interesting new feature in MVC Core (in my opinion) which allows you to create UI widgets.
There is a little bit more coding for ViewComponent (you need to create controller and view), but it's flexible feature (I like it) and easy to call in a place where you need it, just
#await Component.InvokeAsync("NameOfCOmponent").
Injections not my favorite, but sometime usfull - for example if you want display user name, you could just put the following code directly into your layout/view file:
#using System.Security.Claims
#using Microsoft.AspNetCore.Identity
#inject UserManager<ApplicationUser> userManager
#{
var userInfo = ((await userManager?.GetUserAsync(User))?.xxx);
// where 'xxx' is any property of ApplicationUser model
}
then you can use #userInfo in the same view to display that info.
More information:
Views Overview
Passing Data to Views
View Components

Related

Asp.Net MVC View function and ViewData

I have a small confusion in Asp.Net MVC
How rendering works in Asp.net MVC? We invoke View function - > Which will find the view and ask ViewEngine to parse it. Because of ViewEngine final outcome is HTML.
1)Whatever ViewData we create its available inside View. My understanding is ViewData and View function both are part of controller base class which makes ViewData available inside View function. Is it correct?
2)Finally Whats the point with WebViewPage class. ViewData keyword we use inside View(.cshtml) page is coming from the WebViewPage class. What role WebViewPage plays here.
I will really appreciate If you can point me with some good resource to understand the same
1) ViewData is merely a dictionary of objects that you can fill in the Controller and retrieve within the view. Since it is a dictionary of objects you need to cast the data back into the type it was to make full use of it.
2) WebViewPage is the base type of a razor page. It is the defined class which razor pages are compiled into at runtime. The web.config inside the views folder specifies the pageBaseType of the razor pages specifically to WebViewPage. These are two good resources regarding why its use and how you can extend it. Link1 and Link2.
Go peek inside he source code that renders the views
visit msdn

Developing ASP.NET MVC web applications the right way

I'm starting to develop a new ASP.NET MVC application, and I'd like to make sure that my understanding about the way of developing applications under MVC pattern is correct.
Question 1: Suppose that I have some main views (MainView1, MainView2, ...) with some partial views in it (PartialView1, PartialView2, PartialView3, ...). From what I have understood about MVC, I should define a Model for each view. e.g. I have to define PartialModel, PartialModel2, ... and also define my main models which are containers of the partial models which have been used in them:
public class MainModel1
{
public PartialModel1 Partial1 {get;set}
public PartialModel2 Partial2 {get;set}
public PartialModel3 Partial3 {get;set}
}
This way when I want to redirect to MainView, I can initialize the models used in that view by using this Model. Is my understanding of MVC correct? Or should communication between Views and Models be in another form in MVC?
Question 2: If the above is correct, Then suppose I have a partial view in some of my main view pages. This partial view has a submit button which calls an action method. This action method should somehow return the main page's view with the right viewmodels for views. Is there any recommendation about how to get/set viewmodels of other views in a partial view's action?
Thanks.
You understanding is correct. Each view (no matter whether it is main or partial) should have a corresponding view model (unless in the very rare case where this view contains only static html of course). And following this logic a main view that has to render other partial views will have a view model which itself will have reference (maybe as properties) to view models that are required by those partial views.
There is another technique which is using the Html.Action helper. In this case the partial is rendered through another controller/action than the main one. So you don't need to reference the partial view model in the main view model. They will be completely distinct. Take a look at the following blog post to learn more about Html.Action.
Your understanding is perfectly fine. This is what you can also refer to ViewModel in Asp.net MVC.
So, What basically is an Asp.net MVC ViewModel ?
In ASP.NET MVC, ViewModels allow you to shape multiple entities from one or more data models or sources into a single object, optimized for consumption and rendering by the view. The below image illustrates the concept of a ViewModel:
The purpose of a ViewModel is for the view to have a single object to render, alleviating the need for UI logic code in the view that would otherwise be necessary. This means the only responsibility, or concern, of the view is to render that single ViewModel object, aiding in a cleaner separation of concerns (SoC). Concerns are distinct aspects of the application that have a particular purpose (i.e., concern), and keeping these aspects apart means your application is more organized, and the code more focused. Putting data manipulation code in its own location away from the view and controller, enforces SoC.
Using ViewModels in MVC for finer granularity and better SoC leads to more easily maintainable and testable code. Remember, unit testing is about testing small units.
Along with better coding practices, there are many business reasons demonstrating why you might consider using ViewModels:
Incorporating dropdown lists of lookup data into a related entity
Master-detail records view
Pagination: combining actual data and paging information
Components like a shopping cart or user profile widget
Dashboards, with multiple sources of disparate data
Reports, often with aggregate data

Populating the model for a shared view, embedding a shared view within another view

I'm trying to embed a small view snippet that steps through a model fragment that works fine when I embed it in a single controller and pass it to a view like so;
Controller:
return View(_entities.formTemplate.ToList());
View:
http://www.pastie.org/666366
The thing is that I want to be able to embed this particular select box in more than just this single action / view, from the googling I've been doing this appears that it should go into a shared view, but I'm not clear then on how I could populate the model within that view from the controller? (or maybe I'm completely missing the purpose for shared views?)
In the other MVC framework I'm accustomed to working with there is the concept of a filter where you can call code before or after any action and mod the model as it passes the controller and goes to the view, is such a thing possible in .net mvc?
Any assistance appreciated.
You'll want to use the HtmlHelper method DropDownList() in order to create a input:
<%= Html.DropDownList("id", new SelectList(formBuilder, "ID", "Name")) %>
You probably want to use a ViewUserControl here.
You have a couple of options if you go that route. If it's model data that is easily available, recreate it at the call site of your RenderPartial like so:
<%=Html.RenderPartial("ViewName", new ModelData())%>
If it's data that is dependent on the current model data, then you'll need to pass that data somehow to your partial view.
ASP.Net MVC also has the concept of before/after controller actions. You decorate your controller method with an Attribute that derives from ActionFilterAttribute. In there, you have access to OnActionExecuting and OnActionExecuted.

ModelFactory in ASP.NET MVC to solve 'RenderPartial' issue

The 'RenderPartial()' method in ASP.NET MVC offeres a very low level of functionality. It does not provide, nor attempt to provide a true 'sub-controller' model *.
I have an increasing number of controls being rendered via 'RenderPartial()'. They fall into 3 main categories :
1) Controls that are direct
descendants of a specific page that
use that page's model
2) Controls that are direct
descendants of a specific page that
use that page's model with an
additional key of some type.
Think implementation of
'DataRepeater'.
3) Controls that represent unrelated
functionality to the page they appear
on. This could be anything from a
banner rotator, to a feedback form,
store locator, mailing list signup.
The key point being it doesn't care
what page it is put on.
Because of the way the ViewData model works there only exists one model object per request - thats to say anything the subcontrols need must be present in the page model.
Ultimately the MVC team will hopefully come out with a true 'subcontroller' model, but until then I'm just adding anything to the main page model that the child controls also need.
In the case of (3) above this means my model for 'ProductModel' may have to contain a field for 'MailingListSignup' model. Obviously that is not ideal, but i've accepted this at the best compromise with the current framework - and least likely to 'close any doors' to a future subcontroller model.
The controller should be responsible for getting the data for a model because the model should really just be a dumb data structure that doesn't know where it gets its data from. But I don't want the controller to have to create the model in several different places.
What I have begun doing is creating a factory to create me the model. This factory is called by the controller (the model doesn't know about the factory).
public static class JoinMailingListModelFactory {
public static JoinMailingListModel CreateJoinMailingListModel() {
return new JoinMailingListModel()
{
MailingLists = MailingListCache.GetPartnerMailingLists();
};
}
}
So my actual question is how are other people with this same issue actually creating the models. What is going to be the best approach for future compatibility with new MVC features?
NB: There are issues with RenderAction() that I won't go into here - not least that its only in MVCContrib and not going to be in the RTM version of ASP.NET-MVC. Other issues caused sufficent problems that I elected not to use it. So lets pretend for now that only RenderPartial() exists - or at least that thats what I've decided to use.
Instead of adding things like MailingListSignup as a property of your ProductModel, encapsulate both at the same level in a class like ProductViewModel that looks like:
public class ProductViewModel() {
public ProductModel productModel;
public MailingListSignup signup;
}
Then get your View to be strongly-typed to the ProductViewModel class. You can access the ProductModel by calling Model.productModel, and you can access the signup class using Model.signup.
This is a loose interpretation of Fowler's 'Presentation Model' (http://martinfowler.com/eaaDev/PresentationModel.html), but I've seen it used by some Microsoft devs, such as Rob Conery and Stephen Walther.
One approach I've seen for this scenario is to use an action-filter to populate the data for the partial view - i.e. subclass ActionFilterAttribute. In the OnActionExecuting, add the data into the ViewData. Then you just have to decorate the different actions that use that partial view with the filter.
There's a RenderPartial overload I use that let's you specify a new ViewData and Model:
RenderPartial code
If you look at the previous link of the MVC source code, as well as the following (look for RenderPartialInternal method):
RenderPartialInternal code
you can see that if basically copies the viewdata you pass creating a new Dictionary and sets the Model to be used in the control. So the page can have a Model, but then pass a different Model to the sub-control.
If the sub-controls aren't referred directly from the main View Model, you could do the trick Marc Gravell mentions to add your custom logic.
One method I tried was to use a strongly typed partial view with an interface. In most situations an agregated ViewModel is the better way, but I still want to share this.
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IMailingListSignup>" %>
The Viewmodel implements the interface
public class ProductViewModel:IMailingListSignup
Thats not perfect at all but solves some issues: You can still easily map properties from your route to the model. I am not shure if you can have a route parameter map to the properties of MailingListSignup otherwise.
You still have the problem of filling the Model. If its not to late I prefer to do it in OnActionExecuted. I dont see how you can fill a Model in OnActionExecuting.

Where to put master page's code in an MVC application?

I'm using a few (2 or 3) master pages in my ASP.NET MVC application and they must each display bits of information from the database. Such as a list of sponsors, current fundings status etc.
So my question was, where should I put these master-page database calling code?
Normally, these should goes into its own controller class right? But then that'd mean I'd have to wire them up manually (e.g. passing ViewDatas) since it is out of the normal routing framework provided by the MVC framework.
Is there a way to this cleanly without wiring ViewData passing/Action calls to master pages manually or subclassing the frameworks'?
The amount of documentation is very low... and I'm very new to all this including the concepts of MVC itself so please share your tips/techniques on this.
One way to do this is to put in the masterpage view the hook for the ViewData and then you define a BaseController : Controller (or multiple base classes) where you do all the db calls you need.
What you wanna do is quite the same thing described in this articles.
I hope this helps!
Regards
Great question. You have several options available to you.
Have a jQuery call on your masterpage that grabs the data you need from a controller and then populate your fields using jQuery again.
Your second option is to create user controls that make their own calls to the controller to populate their information.
I think the best choice is creating controls for the region of your masterpage that has data that needs to be populated. Thus leaving your masterpage to strictly contain design elements. Good luck.
If you don't mind strongly typed view data, you can put all the master page data in a common base class for viewData. You can set this data in the base class's constructor. All your views requiring additional data will then need strongly typed viewdata that inherits from this base class.
To allow a call to View() in your controllers without any explicit viewdata you can override View in your ControllerBase:
protected override ViewResult View(string viewName, string masterName, object model)
{
if (model == null)
{
model = new ViewDataBase();
}
return base.View(viewName, masterName, model);
}

Resources