My first try of MVC. Am trying to implement a simple example. Inspiration from here. Have I got this pattern (yet!)?
View: "Hey, controller, the user just told me he wants the first person"
Controller: "Hmm, having checked his credentials, he is allowed to do that... Hey, model, I want you to get me the first person"
Model: "First person... got it. Back to you, Controller."
Controller: "Here, I'll collect the new set of data. Back to you, view."
View: "Cool, I'll show the first person to the user now."
View:
namespace WinFormMVC
{
public partial class Form1 : Form
{
controller cont = new controller();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = cont.checkPermissionsAndGetFirstPerson();
}
}
}
Controller:
public class controller
{
public string checkPermissionsAndGetFirstPerson()
{
string returnValue = "";
if (checkPermissions())
{
model m = new model();
returnValue = m.getFirstPerson();
}
return returnValue;
}
public bool checkPermissions()
{
return true;
}
}
Model:
public class model
{
public string getFirstPerson()
{
return "Bill Smith";
}
}
Hmm... I am not sure if I'd call this MVC... As with ASP.NET WebForm, this form is more like an MVP pattern.
As per my understanding, in MVC, controller is the one responsible for managing all resources and flow of the code. In your example, you basically creating a Windows Form first (the view) and then attach a controller to it which is more of a MVP sort of things.
In a classical MVC pattern, the Model, once instantiated, will be linked to the View and when the model changes, the view will get notified (possibly through Observer / PubSub pattern).
Button click, etc. from the View will be routed to the controller which will coordinate those sort of stuffs.
see: this.
I would describe MVC more like this:
Request (MVC url routing, some event passed from previous UI etc)
Controller - check credentials, get data, return Model
Model - represents the data passed back from the Controller
View - render the Model returned by the Controller. Depending on the Model may display UI to initialise new Controller actions. May also pass Model back to next Controller action.
I think it can be a little confused because in many Model implementations (such as Linq) they provide data definition and access, but it's still the Controller that knows where to start (even if it's the Model that knows how to save its own changes).
So, your code should be something like:
//Controller:
public class PersonController
{
public PersonAction Detail(int personId)
{
Person returnValue;
//get person from DB and populate returnValue
return new PersonAction( returnValue );
}
}
//Model:
public class Person
{
public string FirstName {get; set;}
public string LastName {get; set;}
}
//View:
public partial class PersonDetailView : MVCForm<Person>
{
public Form1( Person model ):base(model) {
textBox1.Text = model.FirstName + " " + model.LastName;
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = model.FirstName + " " + model.LastName;
}
}
What this example is missing is the framework that makes this all possible - there are two significant parts to that:
Something that takes/parses parameters and based on that calls a controller's action method. For instance in Asp.net MVC this is the routing handlers - the call above would be the request url: ~/Person/Detail/personId
Something that takes the result from the action (PersonAction in the example above) and finds the correct view to display. In this example it would open a PersonDetailView form and pass the Person model to it.
There are lots of example frameworks for an MVC implementation for WinForms - one of them may be a good starting point.
To adopt the MVC pattern you want to implement the following:
The view hooks up to the Model and listens for changes.
The controller hooks up to the view and handles specific events i.e. button presses etc
The model processes requests made by the controller and notifies the view.
I agree with Jimmy you would want to integrate something like the Observer pattern to this type of system so its possible for the Model to inform the View when it changes so the View can then update itself accordingly.
The difference with MVP is it introduces a Presenter class which monitors the Model on behalf of the View, in other words the View doesn't know about the Model, it only knows about its Presenter. The Presenter responds to changes in the Model and updates the View accordingly.
I think there are a few corrections to be made to your narrative. Strinctly speaking the view does not contact the controller, the user contacts the controller directly. In a web app it looks like this.
User: Hey web app, can I have the resource at /people/1
Routing engine: That means you person controller. get the first user.
User controller: Model, I need you to get me user record for the authenticated user, and the person record for the first person.
User Controller: Right. I know the authenticated user is an admin, and person one does exist. So return the Admin view for person to the user.
Rendering engine: Build up the html from the view (template) and person object (data)
This is difficult to do in webforms. I guess the best way is to have a page for each controller, and have that page dynamiclly choose and display a user control. One for each view. It is important in MVC that the view is dumb. All requests are handled directly by controllers, which then select which view to use.
Your checkPermissionsAndGetFirstPerson method is probably doing too much. Authorization and fetching data should probably be separate operations.
Also, if your Form1 class is your view, it probably shouldn't be constructing the controller. That seems backwards.
Most information you'll find on MVC in .NET will be for ASP.NET MVC web applications. You might want to check out the WinFormsMVC project on CodePlex to see how someone else has tackled this problem.
http://winformsmvc.codeplex.com/
Here's another WinForms MVC implementation on CodePlex. Looks like it's got a bit more documentation.
http://koosserymvcwin.codeplex.com/
You might find this tutorial very helpful: http://nerddinnerbook.s3.amazonaws.com/Intro.htm. Written by Scott Guthrie, it explains the MVC workflow very well. Part 4 should have the basics you're looking for.
Related
This is a question about best-practices in ASP.NET MVC
I've created a website in MVC. Because every page has a menu, I thought I'd create a base controller class which all MVC Controllers in the project inherit from. In The Initialize() function of the base controller class I would then load my Menu.
In that way, I could keep my logic for loading the menu in one place and have it executed automatically.
Code (C#):
public abstract class BaseController : System.Web.Mvc.Controller
{
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
//Load the menu:
ViewBag.HeaderModel = LoadMenu();
}
}
public class HomeController : BaseController
{
public ActionResult Index()
{
//the menu is loaded by the base controller, so we can just return the view here
return View();
}
}
That works like a charm. Now here's the problem.
In my View, I present a list of the five latest Articles on the website. Since the Articles have their own logic and their own section on the website, I've created an ArticleController, which inherits from BaseController as well, with an action that displays a PartialResult with my five latest Articles.
public class ArticlesController : BaseController
{
public ActionResult DisplayLatestArticles()
{
var model = ... //abbreviated, this loads the latest articles
return PartialView("LatestArticles", model);
}
}
And the method is called like this in the View:
#Html.Action("Index", new { controller = "Articles" })
But this has one drawback: namely the Initialize() function on my Base Controller is executed twice, which loads the menu two times, which is undesirable (for performance reasons). So far I haven't been able to find a way to avoid this behavior.
What do you suggest in so far as refactoring this code? I want to make sure my logic to load my menu stays somewhere so it gets called automatically, without me or any other developers on the project having to worry about it. I prefer keeping my logic to display the latest Articles in the ArticlesController so everything to do with Articles is kept in its own Controller.
So, how best to proceed?
What you're trying to do is more suited to calling your header menu from a _Layout.cshtml page.
_Layout.cshtml:
<html>
...
<body>
...
#Html.Action("Header", "SharedStuff")
...
SharedStuffController.cs
public ActionResult Header()
{
// logic to create header, also create a view
return this.View();
}
Base controllers, I feel, are normally the wrong way to go. The above means that you keep all logic for the header nicely contained in something that describes it.
I am not expert on the MVC and landed on this page while searching for my own answer. I completely agree that Base contoller should not be used for generating menu items. However, for what so ever reason, if you wanted to continue using base controller, I would suggest the controller that returns partial views (i.e ArticlesController) should not inherit from base controller and it should inherit from Controller class.
I'm new to MVC, so please go easy on me. I was handed a project that was started in MVC and have been told to add to it. I was fine until I got to a section that needed data from two different models. Now I'm stuck and my boss wants this done yesterday. Please help if you can.
I have a view with two partial views and a submit button. Each of the partial views use a different model. The views display information on the screen which the user can change. The submit button is then clicked. In the controller, I would like to access the data from both models (the values that the user entered on the screen). Right now, I can't even get the submit button to call the controller. That is the part I need immediate help with, but I will eventually need to know how to access both model's data from the controller.
Here's the basic idea of what I want to do:
This is my view: CreateContract.cshtml
<div class="container-fluid">
#using (Html.BeginForm("CreateContract", "CreateContract", FormMethod.Post, new { #class = "form-horizontal " }))
{
<div id="PartialDiv">
#{
Html.RenderPartial("ApplicationPartialView", new CarmelFinancialWeb.Models.ModelApplication());
Html.RenderPartial("ContractPartialView");
}
</div>
<input id="btnCreateContract" type="submit" class="btn btn-primary" value="Save" name="CreateContract" />
}
</div>
This is part of the controller CreateContractController.cs. This method is hit when the view opens and is working correctly.
[AuthorizeAdmin]
public ActionResult CreateContract(string ID)
{
ModelContract obj_Contract = new ModelContract();
obj_Contract.BuyerName = "MOCS";
return View(#"~/Views/CreateContract/CreateContract.cshtml", obj_Contract);
}
This is part of the controller CreateContractController.cs. This method is not being hit when the submit button is clicked. I've tried including the string ID variable from the other method and both ModelContract and ModelApplication (and various combinations thereof), but I cannot get this method to be called.
[AuthorizeAdmin]
[HttpPost]
public ActionResult CreateContract()
{
ModelApplication obj_App = new ModelApplication();
return View(#"~/Views/CreateContract/CreateContract.cshtml", obj_App);
}
These are the methods in the controller for the partial views. These aren't getting called either.
public PartialViewResult ApplicationPartialView(string ID)
{
ModelApplication obj_App = new ModelApplication();
if (ID != null && ID != "0" && ID != null && ID != "")
{
obj_App = objBllApplication.GetApplicationByID(int.Parse(ID));
}
return PartialView("CreateContractApplicationPartialView");
}
public PartialViewResult ContractContractPartialView()
{
ModelContract obj_Contract = new ModelContract();
obj_Contract.DealerID = "MOCS";
return PartialView("CreateContractContractPartialView");
}
There's a lot going on under the hood here which is beneficial for you to know, especially since you're new to this. First, a view can only have one model. The high-level reason is that it's actually rendered via a generic class that the chosen model fills in as it's type. You can somewhat cheat, as you are here, by using partial views, but you still have to get a model instance into those. It's seems you're trying to do that by creating actions in your controller to represent those partials, but these are effectively useless. They are never being called. Html.Partial or Html.RenderPartial will just render the specified view, either with the same model as the calling view, by default, or the object passed in to those methods as the model (second parameter). It does not go back to the controller.
In MVC, there is something called "child actions" which work as you seem to want partials to here. By using Html.Action or Html.RenderAction instead, you can call this actions on your controller that return partial views. Two things there, though:
If you're going to return a partial view (instead of a full-fledged view), then you should decorate the action with [ChildActionOnly]. Otherwise, the actions are exposed to direct URL access from the browser, which would render the partial view alone, without any layout.
Child actions can only be used for GET-style requests. You can't POST to a child action.
It's actually best for things like this, to only use child actions to render separate areas of a form if those individual areas of the form will be posted to separate locations. Take for example a combo page where you have both a login or signup concept. You can use child actions to render each individual group of fields, but the login portion should POST to a login action and the signup portion should posted to a signup action. You wouldn't POST everything from both forms to the same action.
In your particular scenario, partial views are actually the way to go, but you just need to tweak the model of your main view to be a view model that contains both sub-models. For example:
public class MyAwesomeViewModel // name doesn't matter
{
public ModelApplication Application { get; set; }
public ModelContract Contract { get; set; }
}
Then, in your main view:
#model Namespace.To.MyAwesomeViewModel
...
#Html.Partial("ApplicationPartialView", Model.Application)
#Html.Partial("ContractPartialView", Model.Contract)
Finally, your POST action would take this view model as a parameter:
[HttpPost]
public ActionResult CreateContract(MyAwesomeViewModel model)
{
...
}
how can i remove the child action in asp.net mvc3. I mean i am having partial views and main views. In the url bar when i entered the child page then it should not load.
for suppose my main page is
localhost:5820/Home/Index
Then when i enter
localhost:5820/Home/Index
then it should work and the child item is
localhost:5820/Home/About
Then when i enter
localhost:5820/Home/About
then it should not open. How can i do that in asp.net mvc. I have several pages like that i have displayed the pages in how can
i rectify this issue
Looks like you are looking for ChildActionOnly attribute:
[ChildActionOnly]
public ActionResult About()
{
return View();
}
It disables direct calls to localhost:5820/Home/About - only rendering as partial view will be available.
UPDATE according to what you need - mark all actions which should return partial views with ChildActionOnly attribute:
public ActionResult Index()
{
return View();
}
[ChildActionOnly]
public ActionResult About()
{
var model = ...
return PartialView("_About", model);
}
And in index view call those actions (from Home controller and other controllers) via:
#Html.Action("About", "Home")
The fact that your ABOUT page is a link inside your HOME page does not mean it is a child action, in fact, from the point of view of MVC they are in the same level, is YOU as a programmer that give the ilussion of hiereachies by providing an order of navigation.
Now, what you can do is:
simply remove the Action Methods from your controller, or
write a simple ignore route like:
routes.IgnoreRoute("YourRuleToIgnoreActions");
this rules should be at the beginning of your RegisterRoutes method in RegisterRoutes to avoid other rules to be triggered
To build up your ignore rules, here is a nice discussion on the topic: http://ardalis.com/IgnoreRoute-in-ASP.NET-Routing-is-Order-Dependent
UPDATE:
Probably too much thinking on this one, but in my opinion, the Models CAN have properties that modify the behaviour of the View, this is because from an architectural point of view, when you are already in the View, your concern is exclusively on the presentation layer, so I think it is perfectly valid to have something like:
public class MyReportsModel{
public bool displaySection1 { get; set;}
//other data
}
and in your views, you can change the presentation in the following way:
#{
if(#Model.displaySection1){
//display as normal
}
}
Of course, when you populate the model you should set that property in each controller according to your needs:
MyReporstModel thisView = new MyReportsModel();
thisView.displaySection1 = true;
// set all properties necessary to display
// if the controller knows that this partial view won't be displayed then
thisView.displaySection1 = false;
But that is no longer a technical issue but an architectural one.
hope it helps,
I find myself creating Add/Edit/Delete/List GUI's so often that I'm sick and tired of it.
There must be some free package that solves this, right?
What I would like is something like this:
{
MyApplicationUser user = MyApplication.GetUserByID(1234);
EditForm form = new EditForm("Title: Edit User"); //this is the magic object
form.addFieldsFromObject(user);
}
function onFormSubmit(eventArgs e){
MyApplicationUser user = form.GetSubmittedData();
MyApplication.SaveUser(user);
}
AddFieldsFromObject would automatically create a html form with fields mathing the datatype of the public properties of the object I feed it with.
There are a number of frameworks that try to solve this problem. ASP.NET Dynamic Data may be a good place to start. It uses a template-based system to provide basic CRUD (Create, Retrieve, Update, Delete) user interfaces with very minimal custom code.
ASP.NET MVC also does a pretty good job with its editor models:
// View code
#using(Html.BeginForm(...)) {
#Html.EditorForModel()
}
// Action code
public ActionResult ShowForm(int userId)
{
var model = // get model from user ID;
return View(model);
}
public ActionResult SaveForm(Model model)
{
if(ModelState.IsValid)
{
// Save model
}
}
LightSwitch tries to solve this same problem by auto-generating basic scaffolding code for you to produce an experience similar to Microsoft Access. But since it's using actual C# code, you can alter the code to provide more functionality if you find that your needs have grown beyond the original scope of the project.
I'm trying to understand the MVC pattern and I get the general idea that the Model is responsible for maintaining the state, the View is responsible for displaying the Model and the Controller is responsible for modifying the Model and calling the appropriate View(s). I wanted to try and implement a simple ASP.NET MVC login page that uses OpenID in order to get some understanding of how it all works.
I've downloaded DotNetOpenAuth-3.4.6 and I was looking through the samples, specifically their MVC sample. Unfortunately, the sample doesn't actually have a model, only a controller:
namespace OpenIdRelyingPartyMvc.Controllers
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.RelyingParty;
public class UserController : Controller
{
private static OpenIdRelyingParty openid = new OpenIdRelyingParty();
public ActionResult Index()
{
if (!User.Identity.IsAuthenticated)
{
Response.Redirect("~/User/Login?ReturnUrl=Index");
}
return View("Index");
}
public ActionResult Logout()
{
FormsAuthentication.SignOut();
return Redirect("~/Home");
}
public ActionResult Login()
{
// Stage 1: display login form to user
return View("Login");
}
[ValidateInput(false)]
public ActionResult Authenticate(string returnUrl)
{
var response = openid.GetResponse();
if (response == null)
{
// Stage 2: user submitting Identifier
Identifier id;
if (Identifier.TryParse(Request.Form["openid_identifier"], out id))
{
try
{
return openid.CreateRequest(Request.Form["openid_identifier"]).RedirectingResponse.AsActionResult();
}
catch (ProtocolException ex)
{
ViewData["Message"] = ex.Message;
return View("Login");
}
}
else
{
ViewData["Message"] = "Invalid identifier";
return View("Login");
}
}
else
{
// Stage 3: OpenID Provider sending assertion response
switch (response.Status)
{
case AuthenticationStatus.Authenticated:
Session["FriendlyIdentifier"] = response.FriendlyIdentifierForDisplay;
FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, false);
if (!string.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
case AuthenticationStatus.Canceled:
ViewData["Message"] = "Canceled at provider";
return View("Login");
case AuthenticationStatus.Failed:
ViewData["Message"] = response.Exception.Message;
return View("Login");
}
}
return new EmptyResult();
}
}
}
Perhaps the sample is too simple to actually involve a model, since all of the state information is contained within the Cookie. Subsequently, I've implemented a simple database which has a single Users table:
Users
+ user_id
+ open_id
+ last_login
I presume that I would need a LoginModel:
public class LogInModel
{
[Required]
[DisplayName("OpenID")]
public string OpenID { get; set; }
}
A DisplayModel:
public class DisplayModel
{
[DisplayName("User ID")]
public string UserID{ get; set; }
[DisplayName("OpenID")]
public string OpenID { get; set; }
[DisplayName("Last Login")]
public DateTime LastLogin{ get; set; }
}
Additionally, I may need a ModifyModel, but the DisplayModel can be reused and possibly renamed to UserModel (to properly reflect the use of the model).
So now I have several questions:
Is the controller responsible for verifying user input or is that done when the input is passed to the model (i.e. calling Identifier.TryParse on the openid_identifier)?
I want to allow the user login, change their information (i.e. the user_id) and view their information (i.e. user_id, open_id and last_login). How many models do I need (ModifyModel, DisplayModel and LogInModel)?
What is the lifetime of a model? Does the model exist somewhere statically or is it just created by the controller and passed to the view?
Would it be better to add the database as a model instead of making the above models?
1) It could be yes, but a better approach would be to use Data Annotations on the ViewModel.
2) One model will do. A model should represent an overall object, in this case a "User". If the information required for each View differs greatly, then seperate them out into View Models.
3) Not sure what you mean. MVC (and ASP.NET in general) is based on the HTTP protocol, and is thus stateless. So when you hit a URL, a Controller is assigned, then objects are newed up as the code requires it - this includes a database connection. Then when the request is finished, everything is gone (managed resources anyway). Try not to get confused with the word "model". It's not a physical entity, rather an area of your programming model.
4) Generally, your "model" is your Repository/DAL/ORM, which wraps your underlying database, and represents your domain model. Your View's shouldn't be concerned with the domain. That is the job of your Controller/Model. Your View should work with what it needs, and no more. This is why as a rule of thumb, never bind directly to an ORM model, use a ViewModel.
Edit - in response to questions in comments:
I'm sorry... for 1, Data Annotations suggest the validation is performed on the model, but OpenId.Identifier also provides some functions that can validate input (e.g. TryParse), so would it be more consistent to do all of the validation on the model or is the "place" of validation usually not that strict?
Put the Data Annotations on the ViewModel which are representations of the Model created to make life easier for the View. Data Annotations should not be put on your actual model entities (Entity Framework, L2SQL, etc). Data Annotations should be used for input validation (password comparing, length of characters, phone numbers, email addresses, etc). Business Validation should be done in the domain. I would say that OpenId is a service and not part of the domain. If they have some validation functions, you could wrap those calls in custom data annotations and place them on your ViewModel. That would be a clean and consistent approach.
For 3, I agree that the HTTP protocol is stateless, but if I understand correctly cookies are one way to maintain a state and the model provides an alternate way.
Your right, cookies are one way to maintain state. A common use for this is the Forms Authentication ticket. Another one is session. TempData uses Session (in a smart way - automatic ejection). The model is not an "alternate way" - it does not maintain state. Will talk more about that below.
In application programming a state (i.e. an object) is usually persistent throughout the lifetime of the application, so if I were to create a Model in a console app it would exist for as long as there is a reference to it. So when you say that the "objects are newed," does that mean that the Model object is already instantiated (like in a console app) and I just "update" it or does that mean that I construct a new Model?
In a console app - your right. As long as the console application is running, the objects are alive. But in a ASP.NET MVC Web Application, the "parent" is a ASP.NET Worker Thread, assigned when a request comes in. All of the required objects (controller, database connection, repository, domain objects) are "children" of this thread, if that makes sense. Once that thread is gone, so is all the related objects.
There is no "magic instantiation" of the model, again - the Model is an overall view/representation of your domain, which usually consists of the domain model (entities, business logic) and the repository.
The one exception is "model-binding". When you submit a Form to an [HttpPost] action that is strongly-typed to a "model" (should be a ViewModel). ASP.NET MVC (via reflection) will construct this "model" based on the fields in the HTTP POST.
When you do things like "UpdateModel", all that is doing is updating an object you supply with what came into the action method via the model binding. No actual database is being updated.
Don't know what else i can say. You seem to be having confusion about the "model". May i suggest you grab a copy of Steven Sanderson's Pro ASP.NET MVC 2 Framework book. It's fantastic, explains everything from the ground up - in simple terms, then ramps up the pace so your an expert by the end of the book.