This is the sixth part of building line of business application using MVC 5, you can read the previous parts through the following links
- Building a LOB application with MVC 5 – Part 0
- Building a LOB application with MVC 5 – Part 1
- Building a LOB application with MVC 5 – Part 2 – Models and Generic Repository
- Building a LOB application with MVC 5 – Part 3 – EntityFramework
- Building a LOB application with MVC 5 – Part 4 – Controllers, Routes and Areas
In the previous part, we introduced controllers, routes and areas and we created the needed controllers and areas.
In this part, we will introduce views, so by the end of this post, we will finally have something that we can see.
What are Views?
We talked about the M and C, so we have the V from MVC remaining, in web forms, we mainly have the logic and view in one place (aspx), but in MVC, the presentation of the your data is the responsibility of the View, your controller intercept the request, call the business logic, and select how it wants to display the data.
You can display it as a text, Image, Chart, HTML or a downloadable file, in web forms you would have to create a separate web form for each view, but in MVC, you only have to duplicate the view part.
So, for now, lets just say that Views are this pieces that we see the system through it, it used to display the information passed to it from the controller to the users and capture information from the users and forward it to the controller for updates
What is View Engine?
When MVC was released, the views were aspx pages and you had to write these annoying opening and closing tags from web forms era, but later you had the option to either use web forms rendering or the new views engine called Razor.
Razor is much more clean way of writing your views, basically it is all HTML unless you started with @ symbol, this is where the compiler assumes that you want to have a server side code
The View Engine is responsible for translating the written code either in aspx or Razor syntax and produce the final HTML, you can access the list of installed view engines by calling the ViewEngines.Engines property, you can also add a new custom engine to this list by implementing the interface IViewEngine.
As you can see below, MVC 5 is shipped with 2 view engines
- WebFormViewEngine which renders the ASPX pages into HTML
- RazorViewEngine which renders the .cshtml files used in razor to HTML
When you expand the RazorViewEngine, you will see the following:
As you can see above and as we stated in previous posts, MVC uses conventions over configuration, so by default the controller action will search for a view with the same action name inside a folder with the same controller name without the word Controller inside the Views folder, you can change these conventions by editing the corresponding property in the view engine and make sure to add this code in the Global.asax to make sure it is executed first thing when the application starts.
Layout Page (Master Page)
MVC has the same concept of Master page in web forms, only it is called Layout page here, by default the layout is set for any view unless you set the property Layout to null as below
if you didn’t do that, then the view will inherit the default Layout which is by convention again resides in Views\Shared\_Layout.cshtml
You can have more than one layout in your project, and you can set the layout for the view by setting the Layout property to the custom layout path, ex:
Layout = "~/Views/Shared/_CustomLayoutPage.cshtml";
Razor syntax is very similar to normal HTML unless when it starts with @ symbol, to have more details about it, please read more from microsoft site Razor Syntax
Passing data from Controllers to views
Since the view will be displaying data to the end users, we nee to pass this data from the controllers into the view, this happens in 2 ways
Strongly Typed Views
With strongly typed views, the view knows what is the data type of the model and you can reference the properties of the model inside your view code by using the Model property, visual studio supports intellisense for this.
you can set the model type for the view by adding the following lines at the begenning of the view
To see it in action, you can open the file \Views\Manage\AddPhoneNumber.cshtml and examine the code
You can pass the data from your action to the view by adding the model object into the View method as below, if you used View() without any value and tried to access the Model object inside the view, it will throw a null exception
Weakly Typed Views
In this type, you don’t specify the type of the model, you just pass the data you need to the view using 3 predefined properties:
- ViewBag, this is a dynamic object, so you can simply write ViewBag.Message = “Hello” in your action and in the view you can read it by adding @ViewBag.Message, the ViewBag variables are available only for the current view, so if you have an action called Index and you set a message variable inside it, you can access it only in the Index view, if you navigated to another action, then you can’t access it from there
- ViewData, this is the same as the ViewBag except it is a dictionay, so to add a key to it from your controller you either use ViewData.Add(“Key”,”Value”), or you can simply write ViewData[“Key”]=”value” and in your view just write @ViewData[“Key”]
- TempData, this is the same as teh ViewBag except that its lifecycle is a little bit longer, you can access it from the next action, so if you set the value of a variable called Message in your Create action that is called when the user post a form then you redirected to the Index action, you can then call teh Message variable from the Index action, this can be used to show a confirmation message when the user is redirected fom a page to another, note that after the redirection, the variable will be lost, so you can’t use it again.
To create a view, you can go select the folder inside the Views folder where you want to add your view, right click and select Add -> View
Or you can go to your controller, put the cursor inside the action that you wants to generate view for it, and right click then select Add View.
Lets do that together.
Expand Areas, then Admin, right click Controllers and add an Empty Controller named ServiceTypes, this will be used to administer service types.
Add a project reference to the following projects inside the web project
Right Click inside the Index action and choose Add View, leave the view name as is to avoid writing the name explicitly inside the action, choose the template as List, this will create a listing page, you can find the rest of templates for CRUD operations, select the model class that VS will use to generate the view using scaffolding technique, you can choose the Layout page then click Add
Once done, the generated view file will be opened in VS and you can inspect the code, the first thing you will notice is the word @Html is mentioned a lot
If you have a form that accepts a username and password, you can write it as below
<input type="text" name="username" id="username" value="" />
<input type="password" name="password" id="password" value="" />
And if the model property was changed then you have to revist your HTML and update it to be the same as your model, also this is a lot of code to be written, so MVC offrers HTML helpers to save your time, the above code can be replaced by:
@Html.TextBoxFor(m => m.Email)
@Html.LabelFor(m => m.Password)
The above code will generate the same code and you can add more properties like css classes and other attributes.
To read more about HTML helpers and how you can create your own helpers, please visit this link
Now, the user browsed to your application, clicked register, and he is redirected now to the /Account/Register which means the account controller and register action, we have a register view which draws some input fields to capture the user information, the user adds the required information and clicked Submit.
In web forms, we used to do a lot of person.Name = txtName.Text
But in MVC, we don’t have to do that as MVC does it for us using something called Model Binding
When your action accepts a parameter and the user submit an request to this action, MVC automatically create an instance of this object and start to fill its properties from the request body, query string, route values, all these sources called Value Providers, you can add a custom value provider by going through the following post
MVC fill the object properties with request parameters that has the same name, so, if you have a class called Customer, and inside it you have FirstName and LastName, then MVC inspect the request for a query string or form values with the same names.
If the default model binder doesn’t meet your expectations, you can create your own, to read more please see MVC Model Binders
Remember when we added a view and chose the template type as List and the model type as ServiceType and suddenly we have a listing screen? this is called Scaffolding and it happens using T4 Templates that visual studio runs.
To customize these templates, you have to do the following:
- Open C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates
- Create a folder called CodeTemplates in the web project root directory
- Copy the template you want into this folder and customize it, ex: MvcControllerEmpty, open it and customize it the way you want.
After that, create a new item from this template by following the same normal procedure, Right Click the project file-> Add -> New
You will see the updates you made applied to the newly created file, VS is smart enough to override the template with the one in your project.
Annotations and Validations
HTML Helpers can use any annotation attributes defined for each class property and it will use it generate the correct input control and add the right validation.
Ex: When we add the Required, MaxLength and Display attribute to the Name property inside the Country class, it will generate an extra validation for the textbox generated in the view, it will make the field required and has a max length of 50 charactres, it will also change the label from Name to Country Name
Not only this, but it will also impact the EntityFramework code first, when you run the application, EF will compare the model with the database and finds that the Name property has been changed and ti will ask you to add another migration in order to mark the Name column as Required and has a max length of 50
The same will apply when the ViewState.IsValid property is called in the Controller Action, this will make your validation consistent from the UI layer up to the data access layer.
Imagine if you followed the first way of adding just plain HTML code like the example above, you would have to add all the validation yourself, but now HTML helpers removed all this burden
You can now go ahead and generate views and add annotations for all the entities and controllers, if you have any questions, please leave a commant