I've searched a lot and read a lot about the concept of MVC. But I still don't know how to connect them together. Suppose I have a controller class, view class and model class. If user did something in that view, view should notify controller the action and controller may need to communicate with model to get some data.
Now, does view hold a reference to the controller? Does the controller has a property of that model? Or they just using like "include"?
The data is saved in memory, or database? Memory means stored in variables.
More complicated case, one action from user may need many controllers and models involved. How to co-ordinate them together?
What I've done before is I create a "view controller", which has view and some actions of that view.
And sometimes there is no model. All data is passed by parameter. If there are some models, some of them are singleton so I can get it everywhere.
This is a very generic answer, depending on your system these can vary:
The Controller has a reference to the View, an IBOutlet for example. The View is not aware of the Controller, it's a dumb thing that receives info and displays it, that's it.
Depends on what you have in place, sometimes you don't need to persist the data and being on variables is enough. For persisting data, you have CoreData, plists or save them on the sandbox.
Normally you could have a parent Controller, holding references to child Controllers. Each child should be independent and the parent would be the "glue" between them.
I can point you to this repo I created, called iOS Architecture, to help you understand how the controller and the model interact.
Here are some more points:
When your Action returns a View("SomeView"), it will check first if you have a layout, if not it will look for SomeView.cshtml in the Views folder of that controller.
If you want SomeView to talk to any Action in the controller, what you can do is to do a FormMethod.Post and assign the correct model and of course the Action name. That action name should be decorated with [HttpPost] or you can do a FormMethod.Get and decorate it with [HttpGet] or just leave it blank since [HttpGet] is default.
If you want another action redirecting first to another action without going to a page, you use RedirectToAction() instead of View and change the type to ActionResult instead of ViewResult
I hope it makes sense to you :)
Related
So if there is some global state that every view of an MVC app will need to render ... for example: IsUserLoggedOn and UserName ... whats the appropriate way of getting that information to every view?
I understand that that part of the view should be in the master page or in a partial view thats added to the other views. But whats a good way to make sure the 'global' model data is passed to the view every time from all the relevant controllers and actions?
After asking this, I found this good blog post by Steve Sanderson:
http://blog.stevensanderson.com/2008/10/14/partial-requests-in-aspnet-mvc/
He suggests three different approaches:
Use a base controller class or ActionFilter to add the relevant model to the ViewData[] collection every time. I think a few people have suggested that sort of thing already.
Use Html.RenderAction() in the view ... and as he says:
If someone tells you that internal
subrequests are bad because
it “isn’t MVC”, then just bite them on
the face immediately. Also ask them
why they’re still willing to use Ajax,
and even <IMG> tags for that matter,
given that both are a form of
subrequest.
Use 'Partial Requests' (he provides the code for this on his blog) which allow one controller to nest calls to other controllers into a sortof nested ViewData structure.
codeulike - see the answer to a similar question asked at exactly the same time as this:
ASP.NET MVC displaying user name from a Profile
in a nutshell, basically create a base controller that's inherited by all your other controllers. the base controller then has an override function that carries thro' to all 'child' controllers. rather than duplicate the code, take a look at my answer above and give it a try..
cheers...
You could create base class for viewmodel which contains shared information and inherit that for each viewmodel.
public class ViewModelBase
{
// shared data
}
public class Page1ViewModel : ViewModelBase
{
// page 1 data
}
In masterpage you could use that base class
Inherits="System.Web.Mvc.ViewMasterPage<ViewModelBase>"
and in each view use those derived classes
Inherits="System.Web.Mvc.ViewPage<Page1ViewModel>"
So like the title says, I created a view model in my asp.net mvc application so it would be strongly typed to my view. My view model is a combination of two of my model classes. Now when the user hits the save button on that view, it goes to a controller. How does it know what controller to go to? I built my controller 1 - 1 so to speak with my models and views so controller A knows about Model A and controller B knows about Model B. But if I have a view model that is AB how does it know on subit to go to A or B. Do I need a controller called AB Controller?
The controller and action invoked do not depend on the viewmodel object you used to bind the page during initial view rendering. The controller (and action) invoked is determined by the URL of the request sent. (One of the routes you have defined will be matched based on the URL string of the request or a 404 not found error will be returned.)
A submit button in an HTML form (usually a POST) will have an action attribute that determines its url target, an anchor tag will have an href, etc.
In your situation where you have a custom viewmodel object you can define an action to expect and to attempt to parse that specific type of object by specifying it as the parameter to your action:
public ActionResult SaveSystemSetting(SystemAdminVM item) {
An Action Method doesn't receive a model. It receives parameters.
Anyway I think I know where you come from: One of the parameters of your action has the type of the ViewModel used in the View. That is a common layout and makes a lot of sense. In lots of projects it is so widely used that after some time you start to think that an action actually receives a model.
Just remenber that the parameters of your action can by anything that can by filled by the ModelBinder. You could pass both Models as parameters, you could pass a ViewModel that agregates Model a and b or you could pass a ViewModel that has properties of a + b.
Agregation ist the most common approach.
Generally we overload our action methods in the controller so if you have an action called edit that renders the view with your viewmodel object, you will have an overloaded edit action method with the HttpPost specified for that method.
The data to this method will be passed as form value collection values or you can bind it to your viewmodel object if you like and process it further.
I'm using the ASP.NET MVC in a RESTful resource manner and I want to be able get the current resource and controller name from the view.
I'm attempt to create a HTML page and I want to know the current resource and controller name is it possible to get this?
you can get that in a view by looking at the ViewContext.Controller property. The ViewContext property also gives access to many other useful properties such as Route Data, Application, Cache, ViewData, etc.
EDIT: To get the actual name of the controller you can go one of two ways:
1) Call GetType() on the Controller property of ViewContext and use that Name property to get the class name of the controller
2) Look at the route data and examine the values for the "controller" key, e.g. ViewContext.RouteData.Values["controller"] (this would likely be the preferred method)
This information is available in the ViewContext property of ViewPage (assuming you are using .aspx for your views).
You can always run GetType while in the controller (or just type it in if thats what you want to do) and store it in the view data. If you are using the same view from multiple controllers, you might want to make it a strongly typed view and have the controller name be part of it.
Can you be more specific with why exactly you want to do this? There might be a better way.
I would really appreciate some feedback on what I am trying to achieve:
The problem:
I would like to authorize a user of my application to a single action on the controller. For e.g.: a user can perform the "save" action on my controller class if he has the required authorization.
In the project I am working on, the creation of roles & their authorization is done by the client deployment team & not in my control. So, I program to a "control point" which can be assigned to role/user, while my application needs to only check that control point.
How do I get a control point concept into ASP.Net MVC? More specifically, how do I enable/disable buttons on the View based on the user permission on the controller?
My solution:
Ref.: http://weblogs.asp.net/fredriknormen/archive/2008/03/12/asp-net-mvc-framework-2-interception-and-creating-a-role-action-filter.aspx - as a starting point
Instead of creating a role filter as explained in the link above, I would have a ControlPointFilter class which would get the model & do the authorization check.
The trouble I have is in the View class & I am currently passing the control point collection to which the user has access in the ViewData[] collection.
In the View class, I am checking if the related control point is present in the ViewData collection (which I don't like - want to keep the code to a minimum in the View class)
The other issue is - while the actual control point name is being set in the attribute to the controller class, where/how can I pass these attributes to the view & yet keep the view clean?
Hope that helps & appreciate your time/effort to answer this!
Sunny
One possible solution to this is to translate control points into view attributes in your controller actions (perhaps these are the same things, though, it's not clear from your question). The idea would be that your control point would translate into meaningful view directions such as "AllowEdit", "AllowSave", "AllowDetailedView", etc. These would become entries in ViewData.
Use a base controller class to extend Controller and give it a ControlPoint collection. Have your filter populate this collection in the controller. Have the base controller OnActionExecuted method use this collection and, in the case of a ViewResult, populate the ViewData with the appropriate values for the collection of view directives. Individual controller actions could also use the ControlPoint collection to determine whether they need to provide data for individual views based on whether the view will render extra data or not.
In your view, rely not on the control points themselves but the view directions determined by the base controller. This way you've decoupled the views from the control point logic. Views only operate on view data in ways that are meaningful to the view, not on permission-based data that have meaning in the context of the application. The view won't care how or why the particular directive gets set, it only needs to render appropriately based on the value of the directive.
Hmm, could you not simply create a templating system, to assign roles to users? I.e. create a user template "Power User" that has the roles "CustomerService" and "ConfigurationEditor", and then use the role system as pr usual (i.e. Roles.IsUserInRole(username, rolename))?
For actions, you then use
[Authorized(Roles="CustomerService,CustomerServiceAdmin")]
public ActionResult Edit(...)
{
}
For views, you use
<% if (Roles.IsUserInRole(Context.User.Name, "CustomerService")) %>
On the main page of my site, I would like to show several views which rely on their own controllers for data retrieval. I do not want to retrieve anything from the DAL in my Home controller.
For example, I want to show view listing top 5 news, a view with random quote from the database, another view with the users shopping cart contents, etc.
After Googling around, I found RenderAction method which is almost perfect, but it's not available in RC1, only in Futures, and apparently, it has some issues.
I found RenderPartial as well, but that relies on the main controller to pass data to the view.
Additional clarification:
The main reason I do not want data access logic in the Home controller is to avoid repeating the code and logic. I will use top 5 news view in several pages/controllers. I do not want to repeat data retrieval in every one of them. I already did separate a lot of logic and validation to business layer. The solution I'm after is RenderAction or UserControls as in classic ASP. I know i can use them in MVC as well, but... whats the point? I mean, if what i'm asking is too complicated or too absurd (reusable UI components), then MVC is definitely not for me, and I'd consider it seriously inferior to classic ASP.NET, because this requirement is really simple.
What you're asking is to basically not perform data access in the HomeController, this seems like a dogmatic approach. I would consider either using RenderAction from the Futures assembly (not sure what's wrong with it, I use it in a number of projects) or SubControllers from MvcContrib.
While I can understand the desire not to replicate functionality in multiple controllers, I don't understand the reluctance to have your Home controller interact with the DAL. I think the partial view is definitely the way to go. My solution to not replicating the functionality would be to push the code that generates the data for the various views into your business or data layer. You could then reference it from each of the required controller actions that use the partial views. Putting it in the business layer could isolate the controller from your data layer, if that's what you desire, but I still think it's the proper job of the controller action to obtain and provide the data to the view.
Another potential solution would be to populate the view generated by your Home controller via Ajax callbacks to the various controller actions that generate the required view components. The drawback to this is that it doesn't fail gracefully in the absence of javascript in the browser.
EDIT
Based on your clarification, I would suggest implementing a base controller that fills the ViewData for the shared controls in ActionExecuted (so that it's done only when the action succeeds). Derive your other controllers from the base controller when you want to inherit this behavior.
If you really don't want to use RenderAction, then the only other option you have is to load the necessary data pieces with action filters. Your home controller could then look like this:
public class HomeController : Controller
{
[RequireNews]
[RequireQuotes]
[RequireCart]
public ActionResult Index()
{
return View();
}
}
These action filters could be re-used where they are needed. You might also choose to place these on the controller class itself.