MVC




                                             ASP.NET MVC

The Model-View-Controller (MVC) design pattern is an architectural design patterns for any standard development that separates the components of an application. This allows application to handle very flexible and extensible and easy to handle. ASP.NET MVC Framework is also one of the standard web development frameworks which separate the components of web development application different components.
ASP.NET MVC Framework having three main components
  1. Model
  2. View
  3. Controller



Model:  The model manages the behavior and data of the application domain, responds to requests for information about its state from the view, and responds to instructions to change state (usually from the controller).
View: This represent the presentation layer of the web application. The view manages the display of information based on the data of model that is requested by controller.
Controller: Controller handles the user interaction with the web application.  User request comes through controller to model and manipulate the records from it and then render the data using View to UI.
Below diagram showing the overview of these three components



Request Flow for ASP.NET MVC Framework

  1. Request comes from User to Controller
  2. Controller processes request and forms a data Model
  3. Model is passed to View
  4. View transforms Model into appropriate output format
  5. Response is rendered to Browser


Above picture showing you the actual flow of ASP.NET MVP Framework.  Request comes from client to Controller and controller decided which model to used and based on that data rendered into browser.
Now, just have a closer look into to the MVC Flow,





Getting Started 

Start by running Visual Studio Express 2012  or Visual Web Developer 2010 Express. Most of the screen shots in this series use Visual Studio Express 2012, but you can complete this tutorial with Visual Studio 2010/SP1, Visual Studio 2012, Visual Studio Express 2012  or Visual Web Developer 2010 Express. Select New Project from the Startpage.
Visual Studio is an IDE, or integrated development environment. Just like you use Microsoft Word to write documents, you'll use an IDE to create applications. In Visual Studio there's a toolbar along the top showing various options available to you. There's also a menu that provides another way to perform tasks in the IDE. (For example, instead of selecting New Project from the Start page, you can use the menu and select File > New Project.)



Creating Your First Application

You can create applications using either Visual Basic or Visual C# as the programming language. Select Visual C# on the left and then select ASP.NET MVC 4 Web Application. Name your project "MvcMovie" and then click OK.



In the New ASP.NET MVC 4 Project dialog box, select Internet Application. Leave Razor as the default view engine.


Click OK. Visual Studio used a default template for the ASP.NET MVC project you just created, so you have a working application right now without doing anything! This is a simple "Hello World!" project, and it's a good place to start your application.



From the Debug menu, select Start Debugging



Notice that the keyboard shortcut to start debugging is F5.
F5 causes Visual Studio to start IIS Express and run your web application. Visual Studio then launches a browser and opens the application's home page. Notice that the address bar of the browser says localhost and not something like example.com. That's because localhost always points to your own local computer, which in this case is running the application you just built. When Visual Studio runs a web project, a random port is used for the web server. In the image below, the port number is 41788. When you run the application, you'll probably see a different port number.

Right out of the box this default template gives you  Home, Contact and About pages. It also provides support to register and log in, and links to Facebook and Twitter. The next step is to change how this application works and learn a little bit about ASP.NET MVC. Close your browser and let's change some code.


Entity Framework

I am going to use Entity Framework (EF) Code First for the data model. EF Code First lets us generate database tables with nothing more than a few Plain Old CLR Objects (POCO). Plus, EF lets us use LINQ to Entities and Lambda expressions, making it easy to query and issue commands. A win win!
Our application will be a review site for reviewing… stuff. Therefore, the data model needs to incorporate all the necessary bits and pieces for a single review. We’ll start with a class called Review. Write the following class in its own file in the Models directory:


// Review.cs
public class Review
{
    public int Id { get; set; }
    [Required]
    public string Content { get; set; }
    [Required]
    [StringLength(128)]
    public string Topic { get; set; }
    [Required]
    public string Email { get; set; }
    [Required]
    public bool IsAnonymous { get; set; }
    public int CategoryId { get; set; }
    public virtual Category Category { get; set; }
    public virtual IEnumerable<Comment> Comments { get; set; }
}




The Review class has it’s Id (the primary key), the Content property to store the review, a Topic such as a restaurant name (or any name of an organization), an Email property, and an IsAnonymous flag to signify if the reviewer is anonymous. The CategoryId and the Category properties create a foreign key relationship to tie a review to a Category (eg: Doctors, Dentists, etc). And last is a collection of Commentobjects.

Now write the Comment class. Once again, add the new class to the Models directory:

// Comment.cs
public class Comment
{
    public int Id { get; set; }
    [Required]
    public string Content { get; set; }
    [Required]
    public string Email { get; set; }
    [Required]
    public bool IsAnonymous { get; set; }
    public int ReviewId { get; set; }
    public Review Review { get; set; }
}

The comment class has an Id property for the primary key, Content of the comment, an Email property, and an IsAnonymous flag for users. Then there are ReviewId and Review properties to create a foreign key relationship between comments and reviews.
Last is the Category class. Here is its code:
// Category.cs
public class Category
{
    public int Id { get; set; }
    [Required]
    [StringLength(32)]
    public string Name { get; set; }
}



This class is self-explanatory.
You probably noticed extensive use of the [Required] data annotation in the above classes. These designate a non-nullable field in the database and provide validation later down the road. You can also create your own custom validation attributes if you so desire. In addition to [Required], we also used thevirtual keyword for some properties; those properties signify foreign key relationships with other tables.
To create the corresponding tables for these classes, you’ll need to create a DbContext class. The following code creates a context class called ReviewedContext:
public class ReviewedContext : DbContext
{
    public DbSet<Review> Reviews { get; set; }
    public DbSet<Category> Categories { get; set; }
    public DbSet<Comment> Comments { get; set; }
    public ReviewedContext()
    {
        Configuration.ProxyCreationEnabled = false;
    }
}




Every property in this class corresponds to a table when generating the database. TheConfiguration.ProxyCreationEnabled = false; makes sure that the entities are retrieved as objects of their respective classes instead of proxies–making debugging much easier.
Next, we set up a database initializer. An initializer ensures that the database is created correctly when the data model undergoes any change. Without an initializer, you’ll have to manually delete the database if you make a change to one of your POCOs. There are a few different types of initializers to choose from: DropCreateDatabaseAlways andDropCreateDatabaseIfModelChanges. The names are self explanatory. The one we are going to use isDropCreateDatabaseIfModelChanges.
The DropCreateDatabaseAlways andDropCreateDatabaseIfModelChanges initializers have a side effect: they drop the tables (and thus data) in the database when the model structure changes. But EF Code First provides a third way to generate databases: Migrations. This new feature tracks changes to the database and does not lose data as the POCO classes change.
Here’s the code for our initializer:
public class ReviewedContextInitializer : DropCreateDatabaseIfModelChanges<ReviewedContext>
{
    protected override void Seed(ReviewedContext context)
    {
        // Use the context to seed the db.
    }
}



The ReviewedContextInitializer class overrides the Seed() method. This gives us the ability to fill our database with some test data. Now, we need to visit the Global.asax file and add the following line to theApplication_Start() method:


Database.SetInitializer(new ReviewedContextInitializer());


Let’s create some repositories for retrieving data from the database, and we’ll go ahead and setup dependency injection (DI) with Ninject. If you don’t exactly know what DI or Inversion of Control (IoC) are, then take a moment to read this article.

Basically, the idea of dependency injection is to inject a concrete dependency into a class, as opposed to hard coding the class to be dependent upon the concrete dependency. In other words, it’s a decoupling of one concrete class from another. If that’s still clear as mud, let’s look at a brief example:

public class Foo
{
    private Bar _bar;
    public Foo()
    {
        _bar = new Bar();
    }
}
This code creates a class called Foo. It is dependent upon the functionality of an object of type Bar, and theBar object is created within the Foo class. This can be difficult to maintain and unit test because:
  • Foo and Bar are tightly coupled. As a result, maintenance is less than ideal.
  • Foo is dependent upon a specific implementation of Bar, making unit testing difficult.
This code can be improved upon with just a few modifications. Take a look at the revised Foo class
public class Foo
{
    private IBar _bar;
    public Foo(IBar bar)
    {
        _bar = bar;
    }
}



Now, the Foo class is not dependent upon a specific implementation of Bar. Instead, an object of a class implementing the IBar interface is supplied to Foo via the latter's constructor. This approach greatly improves maintainability, while also allowing us to inject any IBarobject--making it easier to unit test our code.
With that brief description out of the way, let's get Ninject up and running. Fire up the Package Manager Console and runInstall-Package Ninject.MVC3. This will add Ninject to our project.
The first repository we'll create is the ReviewsRepository, and it will implement the IReviewRepository interface. Here's the interface:


public interface IReviewRepository
{
    Review Get(int id);
    IQueryable<Review> GetAll();
    Review Add(Review review);
    Review Update(Review review);
    void Delete(int reviewId);
    IEnumerable<Review> GetByCategory(Category category);
    IEnumerable<Comment> GetReviewComments(int id);
}

This interface ensures that our review repositories provide the basic CRUD operations. We also get the utility of retrieving reviews by a specific category, as well as retrieving the comments for a given review. Now let's write a concrete class implementing this interface:


public class ReviewRepository : IReviewRepository

{
    private ReviewedContext _db { get; set; }
    public ReviewRepository()
        :this (new ReviewedContext())
    {
    }
    public ReviewRepository(ReviewedContext db)
    {
        _db = db;
    }
    public Review Get(int id)
    {
        return _db.Reviews.SingleOrDefault(r => r.Id == id);
    }
    public IQueryable<Review> GetAll()
    {
        return _db.Reviews;
    }
    public Review Add(Review review)
    {
        _db.Reviews.Add(review);
        _db.SaveChanges();
        return review;
    }
    public Review Update(Review review)
    {
        _db.Entry(review).State = EntityState.Modified;
        _db.SaveChanges();
        return review;
    }
    public void Delete(int reviewId)
    {
        var review = Get(reviewId);
        _db.Reviews.Remove(review);
    }
    public IEnumerable<Review> GetByCategory(Category category)
    {
        return _db.Reviews.Where(r => r.CategoryId == category.Id);
    }
    public IEnumerable<Comment> GetReviewComments(int id)
    {
        return _db.Comments.Where(c => c.ReviewId == id);
    }
}




This repository relies on a ReviewedContext object that is stored as a class variable. This enables us to use LINQ in any of the repository's methods, making database interaction easy.

WebAPI has a nice feature that lets us add our own DI framework. This feature is beyond the scope of this tutorial, so be sure to read this article to help get that setup.

One of the most important locations for our code is theApp_Start folder, which contains a file calledNinjectCommonWeb.cs (installing Ninject automatically adds this file to App_Start). This file contains a static class calledNinjectWebCommon, and it has a method called
RegisterServices(). In this method, add the following code:
kernel.Bind<IReviewRepository>().To<ReviewRepository>();
kernel.Bind<ICategoriesRepository>().To<CategoriesRepository>();
kernel.Bind<ICommentsRepository>().To<CommentsRepository>();
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);




WebAPI

Let's now create the controllers for the API. WebAPI is a MVC-like framework that we can use to easily create a RESTful service, and it can run inside of a MVC4 application, in its own project, or it can be self hosted outside of IIS. But that's not all; it has many other features, such as: content negotiation (to automatically serialize it data into whatever format is requested), model binding, validation, and many more.
We first need to create an endpoint with WebAPI, and we do that by creating a class that inheritsApiController. Getting started with this is rather easy. Visual Studio 2012 has a new feature that creates a new, partially scaffolded controller.

This will create a controller class with a few methods already defined for you. Here is an example:
// GET api/default1
public IEnumerable<string> Get()
{
    return new string[] { "value1", "value2" };
}
// GET api/default1/5
public string Get(int id)
{
    return "value";
}
// POST api/default1
public void Post(string value)
{
}
// PUT api/default1/5
public void Put(int id, string value)
{
}
// DELETE api/default1/5
public void Delete(int id)
{
}



The method names correspond to the HTTP verb they represent. We'll now create theReviewsController class. The code a bit long, but pretty straightforward.

public class ReviewsController : ApiController
{
    private ICategoriesRepository _categoriesRepository { get; set; }
    private IReviewRepository _reviewRepository { get; set; }
    public ReviewsController(IReviewRepository reviewRepository, ICategoriesRepository categoriesRepository)
    {
        _reviewRepository = reviewRepository;
        _categoriesRepository = categoriesRepository;
    }
    // GET api/review
    public IEnumerable<Review> Get()
    {
        var reviews = _reviewRepository.GetAll();
        return reviews;
    }
    // GET api/review/5
    public HttpResponseMessage Get(int id)
    {
        var category = _reviewRepository.Get(id);
        if (category == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        return Request.CreateResponse(HttpStatusCode.OK, category);
    }
    // POST api/review
    public HttpResponseMessage Post(Review review)
    {
        var response = Request.CreateResponse(HttpStatusCode.Created, review);
        // Get the url to retrieve the newly created review.
        response.Headers.Location = new Uri(Request.RequestUri, string.Format("reviews/{0}", review.Id));
        _reviewRepository.Add(review);
        return response;
    }
    // PUT api/review/5
    public void Put(Review review)
    {
        _reviewRepository.Update(review);
    }
    // DELETE api/review/5
    public HttpResponseMessage Delete(int id)
    {
        _reviewRepository.Delete(id);
        return Request.CreateResponse(HttpStatusCode.NoContent);
    }
    // GET api/reviews/categories/{category}
    public HttpResponseMessage GetByCategory(string category)
    {
        var findCategory = _categoriesRepository.GetByName(category);
        if (findCategory == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        return Request.CreateResponse(HttpStatusCode.OK,_reviewRepository.GetByCategory(findCategory));
    }
    // GET api/reviews/comments/{id}
    public HttpResponseMessage GetReviewComments(int id)
    {
        var reviewComments = _reviewRepository.GetReviewComments(id);
        if (reviewComments == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        return Request.CreateResponse(HttpStatusCode.OK, reviewComments);
    }
}




This code uses IReviewRepository and ICategoriesRepository objects to perform the appropriate action (eg: retrieving data for GET requests, adding data with POST requests, etc). These respositories are injected with Ninject via Constructor Injection.


Notice that some of the methods return different data types. WebAPI gives us the ability to return a non-string data type (such as IEnumerable<Review>), and it will serialize the object to send in the server's response. You can also use the new HttpResonseMessage class to returning a specific HTTP status code along with the returned data. One way to create an HttpResponseMessage object is by callingRequest.CreateResponse(responseCode, data).
We can properly test our WebAPI project with a tool such asFiddler2. If you don't have Fiddler yet, get it now--even if you're not a .NET developer. Fiddler is a fantastic HTTP debugging tool. Once you're running Fiddler, click on RequestBuilder and enter the API URL you want to test. Then choose the appropriate request type. If making a POST request, be sure and specify a Content-Type: application/json header, and then place a valid JSON structure into the request body. The following image demonstrates a raw JSON POST request to theapi/reviews URL:



When you send the request, you'll see something like the following image:


Notice the POST request's status code is a 201. WebAPI does a great job of returning the correct status code for a RESTfull web service. Have fun with Fiddler2, it's a fantastic tool!
With WebAPI, you can specify the routing for the controllers (just like MVC). In MVC4, a RouteConfig.csfile is added to the App_Start folder. Routes for a WebAPI project are just like MVC routes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
routes.MapHttpRoute(
    name: "GetReviewComments",
    routeTemplate: "api/reviews/comments/{id}",
    defaults: new { id = RouteParameter.Optional, controller = "Reviews", action = "GetReviewComments" }
);
routes.MapHttpRoute(
    name: "GetByCategories",
    routeTemplate: "api/reviews/categories/{category}",
    defaults: new { category = RouteParameter.Optional, controller = "Reviews", action = "GetByCategory" }
);
routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);



The DefaultApi route is automatically generated by Visual Studio. The other two routes are custom and map to specific methods on the Reviews controller. There are many articles and tutorials that provide good information on routing. Be sure to check this one out.

MVC4

That covers a lot of what WebAPI has to offer. Next, we'll write a few methods to display the data. We'll consume the API in a little bit, but for now we'll use the repositories in our HomeController. AHomeController was created by Visual Studio; let's just modify its methods to display the data. First, let's get a list of the categories in the Index method.

private ICategoriesRepository _categoriesRepository { get; set; }private IReviewRepository _reviewRepository { get; set; }public HomeController(ICategoriesRepository categoriesRepository, IReviewRepository reviewRepository){_categoriesRepository = categoriesRepository;_reviewRepository = reviewRepository;}public ActionResult Index(){var categories = _categoriesRepository.GetAll();return View(categories);}

Here, we continue to use DI by accepting the repositories as parameters for the HomeControllerconstructor. Ninject automatically inject the appropriate concrete classes for us. Next, let's add some code to the Index view to display the categories: @model IEnumerable<Reviewed.Models.Category><h3>Pick a Category:</h3><ul class="round">@foreach(var category in Model){<li><a href="@Url.Action("Reviews", new { id = @category.Name} )">@category.Name</a></li>}</ul>
This generates a list of categories that users can click on. Now add a new method to HomeController that retrieves a Review. We'll call this method Reviews, shown here:
public ActionResult Reviews(string id){List<Review> reviews = new List<Review>();if (!string.IsNullOrWhiteSpace(id)){reviews = _reviewRepository.GetByCategory(_categoriesRepository.GetByName(id)).ToList();}else{reviews = _reviewRepository.GetAll().ToList();}foreach (var review in reviews){var comments = _reviewRepository.GetReviewComments(review.Id);review.Comments = comments.ToList();}return View(reviews);}

Because a route already exists for /{controller}/{action}/{id}, you can use a URL such asHome/Reviews/Doctors. The routing engine will pass "Doctors" as the id parameter to the Reviewsmethod. We use the id as the category and retrieve all reviews associated with that category. If no category is provided, however, we simple retrieve all reviews in the database. Once we have all the reviews, we pass the review list to the view. Let's look at the view right now:

<div class="reviews">@foreach(var review in Model){<h3>@review.Topic</h3><p>@review.Content</p>var hasComments = review.Comments.Count > 0 ? "is-comments" : null;<ul class="@hasComments">@foreach(var comment in review.Comments){<li><strong>@(!comment.IsAnonymous ? string.Format("{0} says,", comment.Email) : "")</strong><blockquote>@comment.Content</blockquote></li>}</ul>}</div>This code uses a new feature of MVC4. The <ul/> element's class attribute will not appear in the HTML ifhasComments is null.


JAvaScript

No modern web app is complete without JavaScript, and we'll use it to consume our WebAPI service. We'll use Backbone.js for this; so, ahead on over and download Backbone and its dependency Underscore. Place the JavaScript files in the Scripts directory.

We'll take advantage of another new MVC4 feature called script bundling. In the App_Start folder, you'll find the BundleConfig.cs file. In this file, you can configure MVC4 to bundle JavaScript files together. Open it up and add a new bundle, like this:

bundles.Add(new ScriptBundle("~/bundles/backbone").Include(
"~/Scripts/underscore*",
"~/Scripts/backbone*"));

Then in the /Views/Shared/_Layout.cshtml file, add the following at the bottom of the page's body:

@Scripts.Render("~/bundles/backbone")

This will bundle your scripts if your application is in debug mode, or leave them alone with it turned off.

The MVC4 code we wrote for retrieving the review list is a fine way of displaying them, but all the new hawtness is using Ajax. So let's refactor the code to use Backbone.js. Through JavaScript, we'll retrieve the views asynchronously after the page has loaded. Create a new file in the Scripts folder called home.js. Add the following code to that file:

var Review = Backbone.Model.extend();
var Reviews = Backbone.Collection.extend({
model: Review,
url: '/api/reviews'
});
var Comment = Backbone.Model.extend({});
var Comments = Backbone.Collection.extend({
model: Comment,
url: '/api/reviews/comments/'
});

These are the JavaScript data models, each corresponding to a URL to retrieve data from the WebAPI service. Now let's write the view:
var ListReviews = Backbone.View.extend({
el: '.reviews',
initialize: function() {
this.collection.on('reset', this.render, this);
this.collection.fetch();
},
render: function() {
this.collection.each(this.renderItem, this);
},
renderItem: function(model) {
var view = new ReviewItem({
model: model
});
this.$el.append(view.el);
}
});

This view is for the entire list of reviews. When the collection's fetch() method is called, it triggers thereset event and then calls render(). The third parameter passed to the on() method is the scope, or what this will be in the render() callback. In the render() method, call the collection's each() method, passing the renderItem() method. The renderItem() method will be called on each item in the collection, generating a new ReviewItem for every review.

The code for ReviewItem follows:
var ReviewItem = Backbone.View.extend({
events: {
'click a': 'getComments'
},
tagName: 'li',
initialize: function () {
this.template = _.template($('#reviewsTemplate').html());
this.collection = new Comments();
this.collection.on('reset', this.loadComments, this);
this.render();
},
render: function () {
var html = this.template(this.model.toJSON());
this.$el.append(html);
},
getComments: function () {
this.collection.fetch({
data: {
Id: this.model.get('Id')
}
});
},
loadComments: function () {
var self = this,
item;
this.comments = this.$el.find('ul');
this.collection.each(function (comment) {
item = new CommentItem({
model: comment
});
self.comments.append(item.el);
});
this.$el.find('a').hide();
}
});

The ReviewItem view is responsible for rendering each individual review. The initialize() method compiles the template used to display each review; this template resides in a <script/> element. Backbone pulls the template out of the<script/> element and combines it with the review.

A click event handler is also set up for loading the comments for each review. When the link is clicked, thegetComments() method is called, fetching the comments by passing an Id to the WebAPI service. The fetch() method is merely an abstraction to jQuery's $.ajax method, so normal Ajax parameters, like data, can be passed in the fetch()call. Lastly, the loadComments() method will fire and create a new CommentItem view for each comment returned. ThetagName on this view ensures the view is created with an<li/> as its $el property.

Next, let's look at the CommentItem view:

var CommentItem = Backbone.View.extend({
tagName: 'li',
initialize: function () {
this.template = _.template($('#commentsTemplate').html());
this.render();
},
render: function () {
var html = this.template(this.model.toJSON());
this.$el.html(html);
}
});

This is a simple view that renders each comment. Now let's modify the Review.cshtml view as follows:

@model IEnumerable<Reviewed.Models.Review>
@section scripts {
<script type="text/javascript" src="/Scripts/home.js"></script>
}
<div class="reviews">
<ul></ul>
</div>
<script type="text/html" id="reviewsTemplate">
<h3><%= Topic %></h3>
<p>
<%= Content %>
</p>
<a href="#comments">Load Comments</a>
<ul></ul>
</script>
<script type="text/html" id="commentsTemplate">
<li>
<strong><%= !IsAnonymous ? Email + " says," : "" %></strong>
<blockquote><%= Content %></blockquote>
</li>
</script>

Notice the @section scripts in the above code. This is not a new feature to MVC4, but it is a great tool to render specific pieces of JavaScript. In the _layout.cshtml file, there's also a@RenderSection("scripts", required: false) which renders the section defined in the view. The<script/> elements are Underscore templates to render content. They follow a Ruby-esque syntax, and anything inside <% %> is evaluated as a statement. Anything inside of <%= %> will output to the HTML. Loops and conditional statements can be used like this:

<ul>
<script type="text/html" id="template">
<% for (var i = 0; i < list.length; i++) { %>
<li><%= list[i] %></li>
<% } %>
</ul>
<% if (someCondition) { %>
<%= output %>
<% } %>
</script>

That's the template. To use it, do this:

var template = _.template($('#template').html());
var html = template({
someCondition: true,
output: 'hello world',
list: ['foo', 'bar', 'bam']
});

Reference Books:







No comments:

Post a Comment