The Microsoft team is very intensively developing its products and tools for developers. On this topic, the comic
exhausts were already about the release of new versions of the frameworks. Developers who work in large companies are tied into large projects, in general, without much enthusiasm, they look at it, since such engines cannot be transferred to a new version in a short time. It may be fraught with the emergence of bugs, and a change in the entire structure of the project, which is not always easy to do. The above, unfortunately (or fortunately), does not concern me, and it gives me the opportunity to use all the newest things without regard to background. Projects are pretty obvious, they are often transferred to the new version painlessly, and I begin to introduce new features when implementing the next task in the project. At the time of implementation, this, of course, introduces some chaos in the code, since different pieces of code use different principles (for example, LINQ implementation), but subsequent refactoring of the code leads to a single form and everything returns to normal.
Why all this?
One of such innovations is
ASP.NET MVC - implementation of the
Model-View-Controller template for the .NET platform. Let's try to figure out what it is, why it is needed, and apply our knowledge in a simple but real application.
MVC working principle
The architectural template Model-View-Controller implies the division of an application into three main components: Model, View and Controller, is it strange true? :) Each of these components is responsible for its own tasks. If in general terms, then:
- Model is, in general, the whole business logic of our application. It contains classes that are responsible for our data (entities), manipulate them, write to the database and read from there, as well as for the interaction between the entities themselves. If our application is small, then most likely we will work right here with the data. If the project is larger, contains a lot of logic, then it is better to take out the logic, and work with the data in separate projects (assemblies). And when we face a very large application, you will have to physically transfer it to other servers (Application Server).
- View is responsible for user interaction (UI). Through it, we will display our data to the client, implement the interface for editing them, and much more. But only what is associated with the display. No logic!
- The controller is our link between the first two components. Controller Receives data about our request to the server, somehow it processes this data (for example, it receives values ​​from the submitted form) and sends them to the Model. After processing or receiving data, he chooses exactly how we display data to the client (the desired View).
')
What does it give us useful? We have complete control over the output HTML. More "light" applications. Proponents of
TDD (Test-Driven Development) will be delighted, MVC allows you to use this approach to its fullest and test almost everything. We also get a complete separation of logic from data presentation. Someone will simply say “well, finally everything is for people”, while for some it will be disciplined so that the code for working with data is not written in the handler for pressing the button. By the way, did I mention the handlers? Forget it. This is no more. No event handlers, no ViewState, no Drag'n'Drop controls on the form. Yes, my hands will have more hardcoding, someone may even learn and learn how it all really works. At the same time, if we lost the features that simply contradict the idea of ​​MVC, we did not lose the main one. We have Masterpages, UserControls, Membership at our disposal. In general, everything is not so bad as it may seem at first glance. Has MVC replaced WebForms? No, WebForms will also live and develop. MVC just makes it possible to write applications differently. If you have an application for working with a bunch of data, editing in a GridView, etc., then WebForms will remain the right solution for you. Even with MVC, you will forget about all the problems with URL-Rewriting, perhaps this is not so much a problem in WebForms, of course, but for MVC it ​​is a native feature.
From theory to practice?
The other day I got a project from a good friend. Need a new site for a service center for portable electronics. Old is, but a little uncomfortable. In fact, nothing complicated: heels of information pages, a catalog of available accessories with prices and integration with 1C. For the sake of the latter, the question was raised. The entire database is maintained at 1C, I want the client to, by going to the site and entering his receipt number, to see the status of the repair: not ready, whether everything was repaired under warranty or will have to be paid for something.
Preparation for work
First, you must have
Microsoft Visual Studio 2008 installed (if I'm not mistaken, then the Express edition should come up), the
.NET Framework 3.5 , as well as
ASP.NET MVC itself (at the time of this writing, Preview 3 is available). After successful installation of all the good create our project. File -> New -> Project ... In the opened window, select in Project Types the language in which you write and the type of Web project, among the proposed templates we need the ASP.NET MVC Web Application. My project is called “ITService”.
Next, we will offer to create a Unit Test Project for our application, while we manage without it.
As a result, we got our clean project in this form:
Along with the usual directories appeared and unfamiliar to us. Let's go through the order:
/ Properties - standard directory for Web Application, contains project settings.
/ References - links to other assemblies, projects, etc.
/ App_Data - a special directory for data storage
/ Content - in this directory we will store images, styles and the like. In general, all the static content of the site
/ Controllers - classes responsible for Controller components
/ Models - classes with our logic
/ Views - directly the UI of our application. In this directory, directories are created for each controller (/ Views / Home in our case). And already in them on the aspx page for each of the methods of the controller.
/ View / Shared - contains something that can be useful for all controllers, for example MasterPages and UserControls.
What, we try to start? Voila! Got the result:
Click on the links in the top menu and see how URLs are organized in MVC by default. The About page has the address
localhost : 55515 / Home / About (your port may be different). It turns out we have such a structure
mysite {controller} / {action}. Well, quite good.
What do we need
As I said, I need a site with several information pages, a catalog of accessories and a special page that will receive and display data from 1C. OK, we will try to implement our static pages first, let's lay out MasterPage, write down the necessary styles and achieve their work. Of course, in a more complex application, you should start with developing a business logic, think about how we will store the data, write all this, and only then proceed to the interface. But in our case, the project is small, so this sequence can be neglected.
Making life easier when writing code
If you look at our Site.master, then we will see that the path to the css, for example, there is registered relative, i.e. ../../Content/Site.css. It does not suit us, since the nesting of our pages will be different, and the link will be lost, we need to fix it on the way from the root. For CSS, it would be possible, of course, to register with pens, but looking ahead to say that we also have pictures on the site. Each time, writing a long way to them is boring, so we’ll make a Helper. Create a folder Helpers, add the class AppHelper to it with the following code:
using System.Web;
public static class AppHelper
{
public static string ContentRoot
{
get
{
string contentVirtualRoot = "~ / Content" ;
return VirtualPathUtility.ToAbsolute (contentVirtualRoot);
}
}
public static string ImageRoot
{
get { return string .Format ( "{0} / {1}" , ContentRoot, "Images" ); }
}
public static string CssRoot
{
get { return string .Format ( "{0} / {1}" , ContentRoot, “Css” ); }
}
public static string ImageUrl ( string imageFile)
{
string result = string .Format ( "{0} / {1}" , ImageRoot, imageFile);
return result;
}
public static string CssUrl ( string cssFile)
{
string result = string .Format ( "{0} / {1}" , CssRoot, cssFile);
return result;
}
}
In it, we declared the static ContentRoot property — the path to our content, the paths to the directories with images and css files, as well as 2 static methods, ImageUrl and CssUrl, which take the file name and return the corresponding path to it in our application. To use our class, we will change the link tag connecting the styles in Site.Master to the following:
< link href = "<% = AppHelper. CssUrl (" Site . css ")%>" rel = "stylesheet" type = "text / css" />
And do not forget to move Site.css to the created directory / Content / Css, separate the static content by its type. Now if we recompile our project, the path will be written quite correctly:
< link href = "/ Content / css / Site.css" rel = "stylesheet" type = "text / css" />
At this stage, we wrote our Helper to prescribe the correct path to the images and style sheets. Next, we look at how we can work with HTML and what is offered to us.
Work with HTML
Microsoft to facilitate writing code offers HtmlHelper. This is a class with a set of static methods that allows you to render the necessary HTML tags. For example, to display a picture, just write
<% = Html.Image ( "image.png" , "Alt text" ) %>
On the page it will look like
< img src = "logo.png" alt = "Alt text" />
If we use our AppHelper to calculate the path to the picture, we will write this:
<% = Html.Image (AppHelper.ImageUrl ( "logo.png" ), "Alt text" ) %>
This code will already generate the correct image and prescribe the desired path:
< img src = "/ Content / Images / logo.png" alt = "Alt text" />
Another interesting method is Html.ActionLink:
<% = Html.ActionLink ( “About Us” , “About” , “Home” ) %>
This method will generate a link to the “About” controller's “About” method with the text “About Us”
It is possible to write the same code using more “modern” means using Lambda Expressions:
<% = Html.ActionLink <ITService.Controllers.HomeController> (x => x.About (), "About Us" ) %>
What is happening here, I think it is clear from the syntax.
Small hint: in order not to write the ITService.Controllers namespace each time, we will write it in the web.config in the < system.web > < pages > < namespaces > section:
< add namespace = "ITService.Controllers" />
Now similar links can be written shorter:
<% = Html.ActionLink <HomeController> (x => x.About (), “About Us” ) %>
We should also mention the form. Now we will have to work with them explicitly enough (no Postback, remember?). The simplest form will look like this:
<% using (Html.Form <HomeController> (x => x.Index ())) { %>
<% = Html.TextBox ( "name" ) %>
<% = Html.SubmitButton ( "cmdSend" , "Send" ) %>
<% } %>
To work with the from tag, we need to use the using directive and in the area of ​​its action register all fields of the form. This will provide us with a closing tag. The Html.Form declaration (x => x.Index ()) also indicates that the form will be sent to the Index method of the HomeController controller. I think that pretty well come up. I first, when I saw this mixture of html and server parts of the code, I was horrified, I think everyone sailed. Hello again classic ASP, where this vermicelli was full. But still not so scary. This is not at all what it seems at first glance when you start working with it. All these tools are really powerful.
ASP.NET Routing
What are routers? Routers allow us to work with URLs that do not point to physical files on our server; instead, the path is broken down into parameters that we already use in our application. We can also compare a certain part of the path with a specific controller and its method. This model is used by default, but we can set matches that are convenient to us. On the one hand, it looks like the good old URL-Rewriting, which has already been written in detail on the article in the article, but this is only on one side. In fact, these are different things. If we use UrlRewriting, then a query of the form
mysite.com/products/product1 is converted when executed to
mysite.com/products.aspx?id=product1 . Natively, we cannot generate URLs that comply with our URL rewriting rules. Therefore, if we change the logic somewhere and change the address patterns, we will have to edit all the places where these URLs are pens. In MVC, no transformations take place, since it itself without any problems parses the path that is transmitted to it.
All work with routers in MVC is organized in Global.asax.cs. Let's look there in our project and see the following:
routes.MapRoute (
"Default" , // Route name
"{controller} / {action} / {id}" , // URL with parameters
new {controller = "Home" , action = "Index" , id = "" } // Parameter defaults
);
As we see, we add our own to the collection of routers with which our application operates. With the name Default, prescribe the URL mask and create an anonymous type, in which we write the default parameters. Changes we will make here when we proceed directly to the implementation. At the same time, if you are satisfied with such an addressing scheme, then why not? You can leave it as it is and it will work too.
End of beginning
Well, it was the introductory part, in which I tried to reveal the most basic concepts about the ASP.NET MVC platform. How I did it, to judge you. I myself am not an expert in this field, it just became interesting to myself, but at the same time I decided to share it with people, since there is very little information in RuNet on this topic.
I want to note that your opinion about everything is important to me, so any review will be by the way. If criticism, then I, of course, am confident that it will be constructive;)
In the next articles I will go directly to the implementation of the conceived application. Most likely, there will be more code. And it does not please me with such formatting, as in Habré :)
* All the code in the article was highlighted, as far as it was possible, with the help of Source Code Highlighter .