TRUNGTQ

Think Big, Act Small, Fail Fast and Learn Rapidly

NAVIGATION - SEARCH

ASP.NET 5 và AngularJS Phần 2, Sử dụng MVC 6 Web API

Đây là phần thứ 2 trong phần blog của loạt bài xây dựng ASP.NET 5 (ASP.NET vNext) ứng với AngularJS. Trong loạt bài đăng trên blog, tôi sẽ cho các bạn thấy làm thế nào để có thể tạo ra một ứng dụng Movie đơn giản sử dụng ASP.NET 5, MVC 6, và AngularJS.

Bạn có thể tải về mã đã thảo luận trong bài viết blog này từ GitHub:
github.com/StephenWalther/MovieAngularJSApp

Trong bài viết trên blog này, tôi giải thích làm thế nào để expose dữ liệu từ máy chủ của bạn bằng cách sử dụng Web API MVC 6. Chúng tôi sẽ lấy một danh sách các phim từ các API Web và hiển thị danh sách các phim trong AngularJS của chúng tôi ứng dụng bằng một mẫu AngularJS.

Enabling ASP.NET MVC

Bước đầu tiên là enable MVC cho các ứng dụng. Có hai file mà chúng ta cần phải sửa đổi để cho phép MVC.
Đầu tiên, chúng ta cần phải sửa đổi project.json để nó bao gồm MVC 6:

{
    "webroot": "wwwroot",
    "version": "1.0.0-*",
    "exclude": [
        "wwwroot"
    ],
    "packExclude": [
        "**.kproj",
        "**.user",
        "**.vspscc"
    ],
    "dependencies": {
        "Microsoft.AspNet.Server.IIS": "1.0.0-beta1",
        "Microsoft.AspNet.Mvc": "6.0.0-beta1"
    },
    "frameworks" : {
        "aspnet50" : { },
        "aspnetcore50": { }
    }
}

Các tập tin project.json được sử dụng bởi quản lý gói NuGet để xác định gói theo yêu cầu của dự án. Chúng tôi đã chỉ ra rằng chúng ta cần gói MVC 6 (beta1).
Chúng ta cũng cần phải sửa đổi các tập tin Startup.cs trong thư mục gốc của dự án MovieAngularJS của. Thay đổi nội dung của tập tin Startup.cs để nó trông như thế này:

using System;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.Framework.DependencyInjection;

namespace MovieAngularJSApp
{
    public class Startup
    {

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseMvc();
        }

    }
}



Method ConfigureServices () được sử dụng để đăng ký MVC với built-in Dependency Injection framework trong ASP.NET 5. Method Configure() được sử dụng để đăng ký MVC với OWIN.

Tạo Movie Model

Hãy tạo ra một Movie model class mà chúng ta có thể sử dụng để truyền các bộ phim từ máy chủ tới trình duyệt (từ Web API tới AngularJS). Tạo một thư mục Models trong thư mục gốc của dự án MovieAngularJS:

alt

Chú ý rằng bạn tạo các thư mục Models bên ngoài thư mục wwwroot. Source code không thuộc trong wwwroot.
Thêm các class C # tên Movie.cs vào thư mục Models:

using System;

namespace MovieAngularJSApp.Models
{
    public class Movie
    {
        public int Id { get; set; }

        public string Title { get; set; }

        public string Director { get; set; }
    }
}



Tạo Web API Controller

Không giống như các phiên bản trước đó của ASP.NET, lớp controller base được sử dụng cho cả các MVC controllers và Web API controllers. Bởi vì chúng tôi đã kéo trong gói NuGet cho MVC 6, chúng tôi đã sẵn sàng để bắt đầu tạo ra Web API controllers.
Thêm một thư mục API vào thư mục gốc của dự án MovieAngularJS của bạn:

alt

Chú ý rằng bạn không thêm các thư mục API bên trong thư mục wwroot của bạn. Tất cả các mã nguồn của bạn - bao gồm cả mã nguồn cho các controller - nên được đặt bên ngoài thư mục wwwroot.
Tiếp theo, thêm một controller Web API bằng cách nhấn phải chuột vào thư mục API và chọn Add New Item. Chọn Web API Controller Class templateu và đặt tên cho MoviesController.cs điều khiển mới:

alt

Nhập đoạn mã sau cho controller Web API:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Mvc;
using MovieAngularJSApp.Models;

namespace MovieAngularJSApp.API.Controllers
{
    [Route("api/[controller]")]
    public class MoviesController : Controller
    {
        // GET: api/values
        [HttpGet]
        public IEnumerable<Movie> Get()
        {
            return new List<Movie> {
                new Movie {Id=1, Title="Star Wars", Director="Lucas"},
                new Movie {Id=2, Title="King Kong", Director="Jackson"},
                new Movie {Id=3, Title="Memento", Director="Nolan"}
            };
        }

    }
}

Trong đoạn mã trên, Get() action trả về một danh sách các phim. Bạn có thể kiểm tra xem các action đang làm việc bằng cách bắt đầu ứng dụng của bạn và điều hướng đến /api/movies trong trình duyệt của bạn. Trong Google Chrome, bạn sẽ nhận được một đại diện XML của phim:

alt

TẠo AngularJS App

Chúng tôi sẽ hiển thị danh sách các phim sử dụng mẫu AngularJS. Đầu tiên, chúng ta cần phải tạo ra ứng dụng AngularJS.
Nhấp chuột phải vào thư mục Scripts và chọn Add New Item. Chọn mẫu AngularJS Module và nhấn vào nút Add.

alt

Nhập đoạn mã sau cho các module AngularJS mới:

(function () {
    'use strict';

    angular.module('moviesApp', [
        'moviesServices'
    ]);
})();

Đoạn mã trên định nghĩa một AngularJS mô-đun mới có tên moviesApp. Các moviesApp có một sự phụ thuộc vào một module AngularJS tên moviesServices. Chúng tôi tạo ra các moviesServices dưới đây.

Tạo AngularJS Controller

Bước tiếp theo của chúng tôi là tạo ra một Controller AngularJS phía khách hàng. Tạo một thư mục Controller mới trong thư mục Scripts:

alt

Kích chuột phải vào thư mục Controller và chọn Add New Item. Thêm một AngularJS Controller sử dụng $scope mới có tên moviesController.js vào thư mục Controllers. Nhập nội dung sau đây cho các tập tin moviesController.js:

(function () {
    'use strict';

    angular
        .module('moviesApp')
        .controller('moviesController', moviesController);

    moviesController.$inject = ['$scope', 'Movies'];

    function moviesController($scope, Movies) {
        $scope.movies = Movies.query();
    }
})();

Controller AngularJS trên phụ thuộc vào Movies service mà cung cấp danh sách các phim. Các Movies service được chuyển tới Controller sử dụng dependency injection. Các Movies service được thông qua như là tham số thứ hai đến function moviesController() .
Method moviesController.$inject() cần thiết để cho phép các moviesController làm việc với minification. AngularJS dependency injection sẽ ko cần tên của các tham số. Trong bài blog trước, tôi thiết lập Grunt và UglifyJS rút gọn tất cả các tập tin JavaScript. Là một phần của quá trình rút gọn, tất cả các tên tham số chức năng được rút ngắn (đọc sai). phương thức $inject() cho phép dependency injection để làm việc ngay cả khi các tên tham số là đọc sai.

Tạo AngularJS Movies Service

Chúng tôi sẽ sử dụng một AngularJS Movies service để tương tác với Web API. Thêm một thư mục Services mới vào thư mục Scripts. Tiếp theo, kích chuột phải vào thư mục Services và chọn Add New Item. Thêm AngularJS Factory có tên AngularJS moviesService.js vào thư mục dịch vụ:
Nhập đoạn mã sau cho moviesService.js:

(function () {
    'use strict';

    var moviesServices = angular.module('moviesServices', ['ngResource']);

    moviesServices.factory('Movies', ['$resource',
      function ($resource) {
          return $resource('/api/movies/', {}, {
              query: { method: 'GET', params: {}, isArray: true }
          });
      }]);

})();

Các movieServices phụ thuộc vào đối tượng $resource . Các đối tượng $resource thực hiện các yêu cầu Ajax sử dụng một mẫu RESTful.
Trong đoạn mã trên, các moviesServices được kết hợp với /api/movies/ route trên máy chủ. Nói cách khác, khi bạn thực hiện một truy vấn đối với moviesServices trong mã khách hàng của bạn sau đó các Web API MoviesController được viện dẫn để trả về một danh sách các phim.

Tạo AngularJS Template

Bước cuối cùng là tạo ra các mẫu AngularJS hiển thị danh sách các phim. Kích chuột phải vào thư mục wwwroot và thêm một trang HTML mới tên là index.html.

alt

Sửa đổi các nội dung của index.html để nó trông như thế này:

<!DOCTYPE html>
<html ng-app="moviesApp">
<head>
    <meta charset="utf-8" />
    <title>Movies</title>

    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular-resource.js"></script>
    <script src="app.js"></script>
</head>
<body ng-cloak>
    <div ng-controller="moviesController">

        <table>
            <thead>
                <tr>
                    <th>Title</th>
                    <th>Director</th>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="movie in movies">
                    <td>{{movie.Title}}</td>
                    <td>{{movie.Director}}</td>
                </tr>
            </tbody>
        </table>

    </div>
</body>
</html>

Có một số điều mà bạn nên chú ý về tập tin HTML này:
Chú ý rằng các phần tử <html> bao gồm một ng-app directive. directive này liên kết các moviesApp với các tập tin HTML.
Chú ý rằng <script> được sử dụng để thêm angular và angular-resource JavaScript từ CDN của Google.
Chú ý rằng <body> bao gồm một ng-controller directive. directive này liên kết các moviesController với các nội dung của phần tử <div>.
Chú ý rằng các phim được hiển thị bằng cách sử dụng một ng-repeat directive. Tiêu đề và đạo diễn sẽ được hiển thị cho mỗi bộ phim.
Chú ý rằng <body> yếu tố bao gồm một ng-cloak directive. ng-cloak directive giấu một mẫu AngularJS cho đến khi dữ liệu đã được nạp và mẫu đã được trả lại.
Khi bạn mở trang index.html trong trình duyệt của bạn, bạn có thể xem danh sách các phim được hiển thị trong bảng HTML.

alt

Tóm lược

Trong bài viết trên blog này, chúng tôi tạo ra một ứng dụng AngularJS gọi một hành động Web API để lấy danh sách các bộ phim. Chúng tôi hiển thị danh sách các phim trong một bảng HTML bằng cách tận dụng một mẫu AngularJS.
In the next blog post, I discuss how you can take advantage of AngularJS routing to divide a client-side AngularJS app into multiple virtual pages.
Trong bài blog tiếp theo, tôi sẽ thảo luận làm thế nào bạn có thể tận dụng lợi thế của AngularJS routing để chia một client-side AngularJS app vào nhiều trang ảo.

Nguồn:https://viblo.asia/le.anh.duong/posts/AQrMJb8wM40E

ASP.NET MVC Solution Architecture – Best Practices

Bài viết hơi cũ, nhưng kiến trúc dạng này thuộc vào dạng ngon, đáng để tham khảo.

SourceCode: mvcarchitecture

  1. Entity Framework Code First development
  2. Generic Repository Pattern
  3. Dependency Injection using Autofac framework
  4. Automapper

mvc-architecture-01

Choosing the right architecture for Web Applications is a must, especially for large scale ones. Using the default Visual Studio ASP.NET MVC Web Application project templates, adding controllers with Scaffolding options, just to bootstrap your application and create pages and data in just a few minutes, sounds awesome for sure, but let’s be honest it’s not always the right choise. Peeking all the default options, keeping business, data and presentation logic in the same project will impact several factors in your solutions, such as scalability, usability or testability. In this post, will see how to keep things clean, creating a highly loosely coupled ASP.NET MVC Solution, where Data Access, Business and Presentation layers are defined in the right manner. To do this, we ‘ll make use of several patterns and frameworks, some of those are presented below.

  1. Entity Framework Code First development
  2. Generic Repository Pattern
  3. Dependency Injection using Autofac framework
  4. Automapper

The architecture we will try to build in this post is summarized in the following diagram.
Let’s start. Assuming we want to built an e-shop Web Application called “Store”, create a blank solution with the same name.

Models

Add a class library project to the solution, named Store.Model. This library is where we ‘ll keep all of our domain objects. Entity Framework will count on them in order to build the database but we are not going to configure Code First using DataAnnotations attributes on this project. Instead, we are going to put all the Code First configuration in specific Configuration classes using the Fluent API. Add a folder named Models and add the following two simple classes.

Gadget.cs
1
2
3
4
5
6
7
8
9
10
11
public class Gadget
    {
        public int GadgetID {get;set; }
        public string Name {get;set; }
        public string Description {get;set; }
        public decimal Price {get;set; }
        public string Image {get;set; }
 
        public int CategoryID {get;set; }
        public Category Category {get;set; }
    }
Category.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Category
    {
        public int CategoryID {get;set; }
        public string Name {get;set; }
        public DateTime? DateCreated {get;set; }
        public DateTime? DateUpdated {get;set; }
 
        public virtual List<Gadget> Gadgets {get;set; }
 
        public Category()
        {
            DateCreated = DateTime.Now;
        }
    }

I preffered to keep the namespace Store.Model instead of the namespace Store.Model.Models

Data Access Layer and Repositories

mvc-architecture-02
The purpose of this layer, is the direct access to the database. It’s the only layer responsible to communicate with the database. If some other layer wants to access the database, then this will be done through some of the classes (repositories) we will define in this project. This will be strictly the only way Add a new class library project named Store.Data and make sure you add a reference to the previous created project, Store.Model. Install Entity Framework using the Nuget Package Manager. First thing we wanna do, is to define the Entity Type Configurations for our domain objecs. Add a folder named Configuration with the following two classes that inherits the EntityTypeConfiguration class.

GadgetConfiguration.cs
1
2
3
4
5
6
7
8
9
10
public class GadgetConfiguration: EntityTypeConfiguration<Gadget>
    {
        public GadgetConfiguration()
        {
            ToTable("Gadgets");
            Property(g => g.Name).IsRequired().HasMaxLength(50);
            Property(g => g.Price).IsRequired().HasPrecision(8, 2);
            Property(g => g.CategoryID).IsRequired();
        }
    }
CategoryConfiguration.cs
1
2
3
4
5
6
7
8
public class CategoryConfiguration : EntityTypeConfiguration<Category>
    {
        public CategoryConfiguration()
        {
            ToTable("Categories");
            Property(c => c.Name).IsRequired().HasMaxLength(50);
        }
    }

There isn’t any difficult configuration to explain, the point is just to understand where to put the right objects. The next thing we will do is to create the DbContext class that will be responsible to access the database. Add the following class under the root of the current project.

StoreEntities.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class StoreEntities : DbContext
    {
        public StoreEntities() :base("StoreEntities") { }
 
        public DbSet<Gadget> Gadgets {get;set; }
        public DbSet<Category> Categories {get;set; }
 
        public virtual void Commit()
        {
            base.SaveChanges();
        }
 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new GadgetConfiguration());
            modelBuilder.Configurations.Add(new CategoryConfiguration());
        }
    }

We want to seed the database when our application fire up for the first time, so add the following class to the root of the project as well.

StoreSeedData
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public class StoreSeedData : DropCreateDatabaseIfModelChanges<StoreEntities>
    {
        protected override void Seed(StoreEntities context)
        {
            GetCategories().ForEach(c => context.Categories.Add(c));
            GetGadgets().ForEach(g => context.Gadgets.Add(g));
 
            context.Commit();
        }
 
        private static List<Category> GetCategories()
        {
            return new List<Category>
            {
                new Category {
                    Name ="Tablets"
                },
                new Category {
                    Name ="Laptops"
                },
                new Category {
                    Name ="Mobiles"
                }
            };
        }
 
        private static List<Gadget> GetGadgets()
        {
            return new List<Gadget>
            {
                new Gadget {
                    Name ="ProntoTec 7",
                    Description ="Android 4.4 KitKat Tablet PC, Cortex A8 1.2 GHz Dual Core Processor,512MB / 4GB,Dual Camera,G-Sensor (Black)",
                    CategoryID = 1,
                    Price = 46.99m,
                    Image ="prontotec.jpg"
                },
                new Gadget {
                    Name ="Samsung Galaxy",
                    Description ="Android 4.4 Kit Kat OS, 1.2 GHz quad-core processor",
                    CategoryID = 1,
                    Price = 120.95m,
                    Image="samsung-galaxy.jpg"
                },
                new Gadget {
                    Name ="NeuTab® N7 Pro 7",
                    Description ="NeuTab N7 Pro tablet features the amazing powerful, Quad Core processor performs approximately Double multitasking running speed, and is more reliable than ever",
                    CategoryID = 1,
                    Price = 59.99m,
                    Image="neutab.jpg"
                },
                new Gadget {
                    Name ="Dragon Touch® Y88X 7",
                    Description ="Dragon Touch Y88X tablet featuring the incredible powerful Allwinner Quad Core A33, up to four times faster CPU, ensures faster multitasking speed than ever. With the super-portable size, you get a robust power in a device that can be taken everywhere",
                    CategoryID = 1,
                    Price = 54.99m,
                    Image="dragon-touch.jpg"
                },
                new Gadget {
                    Name ="Alldaymall A88X 7",
                    Description ="This Alldaymall tablet featuring the incredible powerful Allwinner Quad Core A33, up to four times faster CPU, ensures faster multitasking speed than ever. With the super-portable size, you get a robust power in a device that can be taken everywhere",
                    CategoryID = 1,
                    Price = 47.99m,
                    Image="Alldaymall.jpg"
                },
                new Gadget {
                    Name ="ASUS MeMO",
                    Description ="Pad 7 ME170CX-A1-BK 7-Inch 16GB Tablet. Dual-Core Intel Atom Z2520 1.2GHz CPU",
                    CategoryID = 1,
                    Price = 94.99m,
                    Image="asus-memo.jpg"
                },
                // Code ommitted
            };
        }
    }

I have ommitted some of the Gadges objects for brevity but you can always download the solution project at the bottom of this post. Now let’s create the Heart of this project. Add a folder named Infrastructure. In order to use the Repository Pattern in the right manner, we need to define a well designed infrastructure. From the bottom to the top all instances will be available through injected interfaces. And the first instance we will require, guess what.. will be an instance of the StoreEntities. So let’s create a factory Interface responsible to initialize instances of this class. Add an interface named IDbFactory into the Infrastructure folder.

1
2
3
4
public interface IDbFactory : IDisposable
    {
        StoreEntities Init();
    }

You can see that this interface inherits the IDisposable one, so the Concrete class that will implement the IDbFactory interface, must also implement the IDisposable one. To do this in a clean way, add a Disposable class that will implement the IDisposable interface. Then any class that will implement the IDbFactory interface, will just want to inherit this very class.

Disposable.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Disposable : IDisposable
    {
        private bool isDisposed;
 
        ~Disposable()
        {
            Dispose(false);
        }
 
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        private void Dispose(bool disposing)
        {
            if (!isDisposed && disposing)
            {
                DisposeCore();
            }
 
            isDisposed =true;
        }
 
        // Ovveride this to dispose custom objects
        protected virtual void DisposeCore()
        {
        }
    }

I have highlighted the DisposeCore virtual method cause this method will make others classes inherit this one, to dispose their own objects in the way the need to. Now add the implementation class of the IDbFactory interface.

DbFactory.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class DbFactory : Disposable, IDbFactory
    {
        StoreEntities dbContext;
 
        public StoreEntities Init()
        {
            return dbContext ?? (dbContext =new StoreEntities());
        }
 
        protected override void DisposeCore()
        {
            if (dbContext !=null)
                dbContext.Dispose();
        }
    }

It’s time to create a generic IRepository interface where we will declare the default operations that our repositories will support. Here I added some that i thought are the most used ones, but you can extend those operations as you wish.

IRepository.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface IRepository<T>where T :class
    {
        // Marks an entity as new
        void Add(T entity);
        // Marks an entity as modified
        void Update(T entity);
        // Marks an entity to be removed
        void Delete(T entity);
        void Delete(Expression<Func<T,bool>>where);
        // Get an entity by int id
        T GetById(int id);
        // Get an entity using delegate
        T Get(Expression<Func<T,bool>>where);
        // Gets all entities of type T
        IEnumerable<T> GetAll();
        // Gets entities using delegate
        IEnumerable<T> GetMany(Expression<Func<T,bool>>where);
    }

Notice that the CRUD operations are commented as Mark to do something... This means that when a repository implentation adds, updates or removes an entity, does not send the command to the database at that very moment. Instead, the caller (service layer) will be responsible to send a Commit command to the database through a IUnitOfWork injected instance. For this to be done will use a pattern called UnitOfWork. Add the following two files into the Infrastructure folder.

IUnitOfWork.cs
1
2
3
4
public interface IUnitOfWork
    {
        void Commit();
    }
UnitOfWork.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class UnitOfWork : IUnitOfWork
    {
        private readonly IDbFactory dbFactory;
        private StoreEntities dbContext;
 
        public UnitOfWork(IDbFactory dbFactory)
        {
            this.dbFactory = dbFactory;
        }
 
        public StoreEntities DbContext
        {
            get {return dbContext ?? (dbContext = dbFactory.Init()); }
        }
 
        public void Commit()
        {
            DbContext.Commit();
        }
    }

In the same way we used the Disposable class we are going to use an abstract class that has virtual implementations of the IRepository interface. This base class will be inherited from all specific repositories and hence will implement the IRepository interface. Add the following class.

RepositoryBase.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public abstract class RepositoryBase<T>where T :class
    {
        #region Properties
        private StoreEntities dataContext;
        private readonly IDbSet<T> dbSet;
 
        protected IDbFactory DbFactory
        {
            get;
            private set;
        }
 
        protected StoreEntities DbContext
        {
            get {return dataContext ?? (dataContext = DbFactory.Init()); }
        }
        #endregion
 
        protected RepositoryBase(IDbFactory dbFactory)
        {
            DbFactory = dbFactory;
            dbSet = DbContext.Set<T>();
        }
 
        #region Implementation
        public virtual void Add(T entity)
        {
            dbSet.Add(entity);
        }
 
        public virtual void Update(T entity)
        {
            dbSet.Attach(entity);
            dataContext.Entry(entity).State = EntityState.Modified;
        }
 
        public virtual void Delete(T entity)
        {
            dbSet.Remove(entity);
        }
 
        public virtual void Delete(Expression<Func<T,bool>>where)
        {
            IEnumerable<T> objects = dbSet.Where<T>(where).AsEnumerable();
            foreach (T objin objects)
                dbSet.Remove(obj);
        }
 
        public virtual T GetById(int id)
        {
            return dbSet.Find(id);
        }
 
        public virtual IEnumerable<T> GetAll()
        {
            return dbSet.ToList();
        }
 
        public virtual IEnumerable<T> GetMany(Expression<Func<T,bool>>where)
        {
            return dbSet.Where(where).ToList();
        }
 
        public T Get(Expression<Func<T,bool>>where)
        {
            return dbSet.Where(where).FirstOrDefault<T>();
        }
 
        #endregion
     
    }

Since the implementations marked as virtual, any repository can ovveride a specific operation as required. And now the Concrete repositories: Add a new folder named Repositories and add the following two classes:

GadgetRepository.cs
1
2
3
4
5
6
7
8
9
10
public class GadgetRepository : RepositoryBase<Gadget>, IGadgetRepository
    {
        public GadgetRepository(IDbFactory dbFactory)
            :base(dbFactory) { }
    }
 
    public interface IGadgetRepository : IRepository<Gadget>
    {
 
    }
CategoryRepository.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class CategoryRepository : RepositoryBase<Category>, ICategoryRepository
    {
        public CategoryRepository(IDbFactory dbFactory)
            :base(dbFactory) { }
 
        public Category GetCategoryByName(string categoryName)
        {
            var category =this.DbContext.Categories.Where(c => c.Name == categoryName).FirstOrDefault();
 
            return category;
        }
 
        public override void Update(Category entity)
        {
            entity.DateUpdated = DateTime.Now;
            base.Update(entity);
        }
    }
 
    public interface ICategoryRepository : IRepository<Category>
    {
        Category GetCategoryByName(string categoryName);
    }

You can see that the GadgetRepository supports the default operations using the default behavior and of course that’s OK. On the other hand, you can see an example where a specific repository requires to either extend it’s operations (GetCategoryByName) or overried the default ones (Update). Usually you add a repository for each of your Model classes, hence each repository of type T, is responsible to manipulate a specific DbSet through the DbContext.Set<T>. We are done implementing the Data Access layer so we can procceed to the next one.

Service Layer


What operations do you want to expose your MVC Controllers? Where is the business logic is going to be implemented? Yeap.. you have guessed right, in this very layer. Add a new class library project named Store.Service. You will have to add references to the two previous created projects, Store.Model and Store.Data. Notice I haven’t told you yet to install Entity Framework to this project.. and I am not going to, cause any database operation required will be done through the injected repositories we created before. Add the first Service file to this project.

GadgetService.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// operations you want to expose
    public interface IGadgetService
    {
        IEnumerable<Gadget> GetGadgets();
        IEnumerable<Gadget> GetCategoryGadgets(string categoryName,string gadgetName =null);
        Gadget GetGadget(int id);
        void CreateGadget(Gadget gadget);
        void SaveGadget();
    }
 
    public class GadgetService : IGadgetService
    {
        private readonly IGadgetRepository gadgetsRepository;
        private readonly ICategoryRepository categoryRepository;
        private readonly IUnitOfWork unitOfWork;
 
        public GadgetService(IGadgetRepository gadgetsRepository, ICategoryRepository categoryRepository, IUnitOfWork unitOfWork)
        {
            this.gadgetsRepository = gadgetsRepository;
            this.categoryRepository = categoryRepository;
            this.unitOfWork = unitOfWork;
        }
 
        #region IGadgetService Members
 
        public IEnumerable<Gadget> GetGadgets()
        {
            var gadgets = gadgetsRepository.GetAll();
            return gadgets;
        }
 
        public IEnumerable<Gadget> GetCategoryGadgets(string categoryName,string gadgetName =null)
        {
            var category = categoryRepository.GetCategoryByName(categoryName);
            return category.Gadgets.Where(g => g.Name.ToLower().Contains(gadgetName.ToLower().Trim()));
        }
 
        public Gadget GetGadget(int id)
        {
            var gadget = gadgetsRepository.GetById(id);
            return gadget;
        }
 
        public void CreateGadget(Gadget gadget)
        {
            gadgetsRepository.Add(gadget);
        }
 
        public void SaveGadget()
        {
            unitOfWork.Commit();
        }
 
        #endregion
     
    }

The first and the last highlighted code lines reminds you why we created the IUnitOfWork interface. If we wanted to create a gadget object though this service class, we would write something like this..

1
2
3
// init a gadget object..
gadgetService.CreateGadget(gadget);
gadgetService.SaveGadget();

The other highlighted code lines denotes that any required repository for this service, will be injected through it’s constructor. This will be done through a Dependency Container we will setup in the MVC project’s start up class, using the Autofac framework. In the same way I created the GadgetService.cs file.

CategoryService.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// operations you want to expose
   public interface ICategoryService
   {
       IEnumerable<Category> GetCategories(string name =null);
       Category GetCategory(int id);
       Category GetCategory(string name);
       void CreateCategory(Category category);
       void SaveCategory();
   }
 
   public class CategoryService : ICategoryService
   {
       private readonly ICategoryRepository categorysRepository;
       private readonly IUnitOfWork unitOfWork;
 
       public CategoryService(ICategoryRepository categorysRepository, IUnitOfWork unitOfWork)
       {
           this.categorysRepository = categorysRepository;
           this.unitOfWork = unitOfWork;
       }
 
       #region ICategoryService Members
 
       public IEnumerable<Category> GetCategories(string name =null)
       {
           if (string.IsNullOrEmpty(name))
               return categorysRepository.GetAll();
           else
               return categorysRepository.GetAll().Where(c => c.Name == name);
       }
 
       public Category GetCategory(int id)
       {
           var category = categorysRepository.GetById(id);
           return category;
       }
 
       public Category GetCategory(string name)
       {
           var category = categorysRepository.GetCategoryByName(name);
           return category;
       }
 
       public void CreateCategory(Category category)
       {
           categorysRepository.Add(category);
       }
 
       public void SaveCategory()
       {
           unitOfWork.Commit();
       }
 
       #endregion
   }

And we are done with the service layer as well. Let’s procceed with the last one, the ASP.NET MVC Web Application.

Presentation Layer


Add a new ASP.NET Web Application named Store.Web choosing the empty template with the MVC option checked. We need to add references to all of the previous class library projects and an Entity Framework installation via Nuget Packages as well. You may be wondering, are we going to write any Entity Framework related queries in this project? Not at all, we need though some of it’s namespaces so we can setup the database configurations for our application, such as the database initializer. And since we started with this, open Global.asax.cs file and add the following line of code to setup the seed initializer we created in the Store.Data project.

Glbal.asax.cs
1
2
3
4
5
6
7
8
protected void Application_Start()
        {
            // Init database
            System.Data.Entity.Database.SetInitializer(new StoreSeedData());
 
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }

You will also need to create a connection string element to define where you want the database to be created. Add the following element in the Web.config file and changed it accoarding to your development enviroment requirements.

Web.config
1
2
3
<connectionStrings>
  <add name="StoreEntities" connectionString="Data Source=(localdb)\v11.0;Initial Catalog=StoreDb;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>

We have made such an effort in the previous steps to create repositories and services but now it’s the time to make them work all together. If you recall, all services contructors have repositories interfaces that must be injected to. The services themeselfs will later be injected in to the controllers conustructors and this is how our application will work. To achieve this, we need to setup Dependancy Injection and for thish reason I decided to use Autofac. Make sure you install Autofac ASP.NET MVC 5 Integration through Nuget Packages.

Create a Bootstrapper.cs file under the Start_App folder and paste the following code.

Bootstrapper.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static void Run()
        {
            SetAutofacContainer();
        }
 
        private static void SetAutofacContainer()
        {
            var builder =new ContainerBuilder();
            builder.RegisterControllers(Assembly.GetExecutingAssembly());
            builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();
            builder.RegisterType<DbFactory>().As<IDbFactory>().InstancePerRequest();
 
            // Repositories
            builder.RegisterAssemblyTypes(typeof(GadgetRepository).Assembly)
                .Where(t => t.Name.EndsWith("Repository"))
                .AsImplementedInterfaces().InstancePerRequest();
            // Services
            builder.RegisterAssemblyTypes(typeof(GadgetService).Assembly)
               .Where(t => t.Name.EndsWith("Service"))
               .AsImplementedInterfaces().InstancePerRequest();
 
            IContainer container = builder.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }
    }

The code itself is self explanatory. I hope you have followed along with me and you have named your repository and service classes as I did, cause otherwise, this is not gonna work. There are two importants things left to complete the tutotiral. The first one to define ViewModel classes and set Automapper to map domain entities to viewmodels and backwards. The second one is to see how to setup CSS Bootstrap in our web application. I suppose most of you, install bootstrap from Nuget Packages and start adding css and script references to your project. Here though we will follow a different approach.

CSS Bootstrap

First of all download Boostrap distribution from the official site. Add three folders to your application named css, fonts and js respectively. In the css folder paste the bootstrap.css file from what you have downloaded, in the fonts folder paste everything is inside the respective fonts folder and in the js folder, just paste the bootstrap.js file. We are going to use Bundling and Minification for bootstrap and to achieve that you need to install Microsoft ASP.NET Web Optimazation Framework through Nuget Packages.

When you finish installing this, add a new class named BundleConfig into the App_Start folder as follow:

BundleConfig.cs
1
2
3
4
5
6
7
8
9
10
public class BundleConfig
    {
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/bootstrap/js").Include("~/js/bootstrap.js","~/js/site.js"));
            bundles.Add(new StyleBundle("~/bootstrap/css").Include("~/css/bootstrap.css","~/css/site.css"));
 
            BundleTable.EnableOptimizations =true;
        }
    }

As you can see I have also referenced site.js and site.css javascript and css files. Those files can host any bootstrap css customazations you wanna do or any javascript related code. Feel free to add the respective files and leave them empty. Now we need to declare that we want MVC to use bundling and minication, so add the following line into the Global.asax.cs file.

Global.asax.cs
1
2
3
4
5
6
7
8
9
10
11
12
protected void Application_Start()
        {
            // Init database
            System.Data.Entity.Database.SetInitializer(new StoreSeedData());
 
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
 
            // Autofac and Automapper configurations
            Bootstrapper.Run();
        }

Notice that I have also called the Bootstrapper.Run() function that will setup the Autofac’s configuration we made before. This function will also configure Automapper, something we gonna see in a bit. Let’s finish with Bootrap for now. We will need a Layout to use for our application, so go and create a Shared folder under the Views folder and add a new item of type MVC 5 Layout Page (Razor) named _Layout.cshtml.

_Layout.cshtml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>@ViewBag.Title</title>
    <!-- Bootstrap -->
    @Styles.Render("~/bootstrap/css")
    <!--[if lt IE 9]>
    html5shiv.js"></script>
    respond.min.js"></script>
    <![endif]-->
</head>
<body>
    <nav id="myNavbar" class="navbar navbar-default navbar-inverse navbar-fixed-top" role="navigation">
        <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbarCollapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                @Html.ActionLink("Store", "Index", "Home", new { }, new { @class = "navbar-brand" })
            </div>
            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="navbarCollapse">
                <ul class="nav navbar-nav">
                    <li class="active">
                        @Html.ActionLink("Tablets", "Index", "Home", new { category = "Tablets" }, null)
                    </li>
                    <li class="active">
                        @Html.ActionLink("Laptops", "Index", "Home", new { category = "Laptops" }, null)
                    </li>
                    <li class="active">
                        @Html.ActionLink("Mobiles", "Index", "Home", new { category = "Mobiles" }, null)
                    </li>
                </ul>
            </div>
    </nav>
    @RenderBody()
    @Scripts.Render("~/bootstrap/js")
</body>
</html>

The page will probably complain that cannot resolve Razor syntax so you have to add the following using statement in the web.config file which is under the Views folder (not application’s web.config). Following is part of that file..

web.config
1
2
3
4
5
6
7
8
<namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="Store.Web" />
        <add namespace="System.Web.Optimization" />
      </namespaces>

Automapper

In a real application your domain objects will probably have a lot of properties but you only want to display some of them in the browser. More over when posting back to server, for example when creating objects though a form element, you also want to post only a few of the domain object’s properties. For this reason you define ViewModel objects and use them instead of the real domain ones. Make sure you install Automapper from Nuget Packages.

Add a new folder named ViewModels with the following classes.

GadgetViewModel.cs
1
2
3
4
5
6
7
8
9
10
public class GadgetViewModel
    {
        public int GadgetID {get;set; }
        public string Name {get;set; }
        public string Description {get;set; }
        public decimal Price {get;set; }
        public string Image {get;set; }
 
        public int CategoryID {get;set; }
    }
CategoryViewModel.cs
1
2
3
4
5
6
7
public class CategoryViewModel
    {
        public int CategoryID {get;set; }
        public string Name {get;set; }
 
        public List<GadgetViewModel> Gadgets {get;set; }
    }
GadgetFormViewModel.cs
1
2
3
4
5
6
7
8
public class GadgetFormViewModel
    {
        public HttpPostedFileBase File {get;set; }
        public string GadgetTitle {get;set; }
        public string GadgetDescription {get;set; }
        public decimal GadgetPrice {get;set; }
        public int GadgetCategory {get;set; }
    }

When your ViewModel classes have properties named as the respective domain objects, Automapper is smart enough to make the mapping through default conventions. Otherwise you have to set the mapping manualy by yourself. Notice the last class I have added, the GadgetFormViewModel. We can make a convetion to add a “Form” word before “ViewModel” so that we know that this type of view model, is posted back to server through a form element. Let’s now configure the mappings. Add a new folder Mappings and add the following class file.

AutoMapperConfiguration.cs
1
2
3
4
5
6
7
8
9
10
11
public class AutoMapperConfiguration
    {
        public static void Configure()
        {
            Mapper.Initialize(x =>
            {
                x.AddProfile<DomainToViewModelMappingProfile>();
                x.AddProfile<ViewModelToDomainMappingProfile>();
            });
        }
    }

We haven’t created the required profiles yet but we will in a bit. What I wanted to show you is that you can create as many Automapper profiles you want and then add them into Mapper.Initialize function. Here we will define two profiles, one to map domain models to ViewModels and another one for backwards. Add the following classes in the same folder as the previous.

DomainToViewModelMappingProfile.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
public class DomainToViewModelMappingProfile : Profile
    {
        public override string ProfileName
        {
            get {return "DomainToViewModelMappings"; }
        }
 
        protected override void Configure()
        {
            Mapper.CreateMap<Category,CategoryViewModel>();
            Mapper.CreateMap<Gadget, GadgetViewModel>();
        }
    }
ViewModelToDomainMappingProfile.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ViewModelToDomainMappingProfile : Profile
    {
        public override string ProfileName
        {
            get {return "ViewModelToDomainMappings"; }
        }
 
        protected override void Configure()
        {
            Mapper.CreateMap<GadgetFormViewModel, Gadget>()
                .ForMember(g => g.Name, map => map.MapFrom(vm => vm.GadgetTitle))
                .ForMember(g => g.Description, map => map.MapFrom(vm => vm.GadgetDescription))
                .ForMember(g => g.Price, map => map.MapFrom(vm => vm.GadgetPrice))
                .ForMember(g => g.Image, map => map.MapFrom(vm => vm.File.FileName))
                .ForMember(g => g.CategoryID, map => map.MapFrom(vm => vm.GadgetCategory));
        }
    }

For the Domain -> ViewModels mapping we didn’t need to setup anything. Automapper will use the default conventions and that’s fine. For our GadgetFormViewModel -> Gadget mapping though, we set manually the configuration as shown above. The last thing remained to finish with Automapper is to add the following line in the Bootstrapper class.

Bootsrapper.cs
1
2
3
4
5
6
7
8
9
public static class Bootstrapper
    {
        public static void Run()
        {
            SetAutofacContainer();
            //Configure AutoMapper
            AutoMapperConfiguration.Configure();
        }
// Code ommitted

Controllers and Views

We are almost finished. Add a new MVC Controller named HomeController and paste the following code.

HomeController.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class HomeController : Controller
    {
        private readonly ICategoryService categoryService;
        private readonly IGadgetService gadgetService;
 
        public HomeController(ICategoryService categoryService, IGadgetService gadgetService)
        {
            this.categoryService = categoryService;
            this.gadgetService = gadgetService;
        }
 
        // GET: Home
        public ActionResult Index(string category =null)
        {
            IEnumerable<CategoryViewModel> viewModelGadgets;
            IEnumerable<Category> categories;
 
            categories = categoryService.GetCategories(category).ToList();
 
            viewModelGadgets = Mapper.Map<IEnumerable<Category>, IEnumerable<CategoryViewModel>>(categories);
            return View(viewModelGadgets);
        }
    }

Now you can see in action why we have made such an effort to setup Repositories, Services, Autofac and Automapper. Services will be injected in the controller for each request and their data will be mapped to ViewModels before send to the Client. Right click in the Index action and add a View named Index with the following code. I must mention here, that the gadgets objects we use, have image references to a folder named images in the Web Application project. You can use your images or just download this project at the end of this post.

Views/Home/Index.cshtml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
@model IEnumerable<Store.Web.ViewModels.CategoryViewModel>
 
@{
    ViewBag.Title ="Store";
    Layout ="~/Views/Shared/_Layout.cshtml";
}
 
<p>
 
</p>
<divclass="container">
    <divclass="jumbotron">
 
        @foreach (var itemin Model)
        {
            <divclass="panel panel-default">
                <divclass="panel-heading">
                    @*@Html.DisplayFor(modelItem => item.Name)*@
                    @Html.ActionLink("View all " + item.Name,"Index",new { category = item.Name },new { @class ="pull-right" })
                    @using (Html.BeginForm("Filter","Home",new { category = item.Name }, FormMethod.Post,new { @class ="navbar-form" }))
                    {
                        @Html.TextBox("gadgetName",null,new { @class ="form-control", placeholder ="Search in " + item.Name })
                    }
 
 
                </div>
                @foreach (var gadgetin item.Gadgets)
                {
                    @Html.Partial("Gadget", gadget)
                }
                <divclass="panel-footer">
                    @using (Html.BeginForm("Create","Home", FormMethod.Post,
                            new { enctype ="multipart/form-data", @class ="form-inline" }))
                    {
                        @Html.Hidden("GadgetCategory", item.CategoryID)
                        <divclass="form-group">
                            <labelclass="sr-only" for="file">File</label>
                            <input type="file" class="form-control" name="file" placeholder="Select picture..">
                        </div>
                        <divclass="form-group">
                            <labelclass="sr-only" for="gadgetTitle">Title</label>
                            <input type="text" class="form-control" name="gadgetTitle" placeholder="Title">
                        </div>
                        <divclass="form-group">
                            <labelclass="sr-only" for="gadgetName">Price</label>
                            <input type="number" class="form-control" name="gadgetPrice" placeholder="Price">
                        </div>
                        <divclass="form-group">
                            <labelclass="sr-only" for="gadgetName">Description</label>
                            <input type="text" class="form-control" name="gadgetDescription" placeholder="Description">
                        </div>
                        <button type="submit" class="btn btn-primary">Upload</button>
                    }
                </div>
            </div>
        }
 
    </div>
 
</div>

Two things to notice here. The first one is that we need to create a Partial view to diplay a GadgetViewModelobject and the second one is the Form’s control element’s names. You can see that they much our GadgetFormViewModel properties. Under the Shared folder create the following Partial view for displaying a GadgetViewModel object.

Views/Shared/Gadget.cshtml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@model Store.Web.ViewModels.GadgetViewModel
 
<div class="panel-body">
    <div class="media">
        <a class="pull-left" href="#">
            <img class="media-object" src="../../images/@Model.Image" />
        </a>
        <div class="media-body">
            <h3 class="media-heading">
                @Model.Name
            </h3>
            <p>@Model.Description</p>
        </div>
    </div>
</div>

In the Index.cshtml page I have added search and filter functionality and Create gadget as well. To achieve that you need to add the following Action methods to the HomeController.

HomeController.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public ActionResult Filter(string category,string gadgetName)
        {
            IEnumerable<GadgetViewModel> viewModelGadgets;
            IEnumerable<Gadget> gadgets;
 
            gadgets = gadgetService.GetCategoryGadgets(category, gadgetName);
 
            viewModelGadgets = Mapper.Map<IEnumerable<Gadget>, IEnumerable<GadgetViewModel>>(gadgets);
 
            return View(viewModelGadgets);
        }
 
        [HttpPost]
        public ActionResult Create(GadgetFormViewModel newGadget)
        {
            if (newGadget !=null && newGadget.File !=null)
            {
                var gadget = Mapper.Map<GadgetFormViewModel, Gadget>(newGadget);
                gadgetService.CreateGadget(gadget);
 
                string gadgetPicture = System.IO.Path.GetFileName(newGadget.File.FileName);
                string path = System.IO.Path.Combine(Server.MapPath("~/images/"), gadgetPicture);
                newGadget.File.SaveAs(path);
 
                gadgetService.SaveGadget();
            }
 
            var category = categoryService.GetCategory(newGadget.GadgetCategory);
            return RedirectToAction("Index",new { category = category.Name });
        }

I am sure that at this point you understand the purpose of all the above code so I won’t explain anything. You need to add a Filter page so right click in the Filter action and create the following View.

Home/Views/Filter.cshtml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@model IEnumerable<Store.Web.ViewModels.GadgetViewModel>
 
@{
    ViewBag.Title = "Filter";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
<div class="container">
    <div class="jumbotron">
 
        @foreach (var item in Model)
        {
            <div class="panel panel-default">
                <div class="panel-heading">
                    @Html.Label(item.Name)
                </div>
                @Html.Partial("Gadget", item)
            </div>
        }
 
    </div>
</div>


You can filter gadgets by category or search gadgets in a specific category. That’s it, we have finished creating a highly decoupled architecture that could support large scale MVC applications.

Github

I have decided to move all of my code to my Github account so you can download most of the projects that we have seen on this blog from there. You can download this project from here. I hope you enjoyed this post as much as I did.

In case you find my blog’s content interesting, register your email to receive notifications of new posts and follow chsakell’s Blog on its Facebook or Twitter accounts.

LINK: https://chsakell.com/2015/02/15/asp-net-mvc-solution-architecture-best-practices/

HTTP Get, Put, Post And Delete Verbs In ASP.NET WEB API

Introduction

In this article, I will explain about Http Get, Put, Post and Delete verbs in ASP.Net Web API in detail. These are very significant verbs in ASP.NET Web API. This article explains how to perform these 4 verbs in ASP.NET Web API.

Steps for performing HTTP verbs using ASP.NET web API

The steps given below explain about how HTTP verbs perform with ASP.NET Web API.

Step 1

Open new project in Visual Studio, select the Web under visual C# and select ASP.NET Web Application. Finally, give the project name and click OK. Now, select Web API from template Window and click OK.

After opening the project solutions, we can see the all folders in Solution Explorer. Everything is same as ASP.NET MVC but we can find one extra controller and this controller is Value controller. Value controller is inherited from APIController. APIController is an abstract class. Before reading this article, please refer to the article, as it helps to know about APIControllers and API routing.\

Step 2

We can find the five methods in ValuesController. ValuesController looks, as shown below.

In this Controller, we create one static variable with the type of list. In this variable, we assign three strings.

Example 

 
  1. static List<string> languages = new List<string>() {   
  2.             "C#","ASP.NET","MVC"  
  3.         };  

Get method returns what are the strings assigned in the languages variable. Get method contains the code, which looks, as shown below. 

 
  1. // GET api/values  
  2.        public IEnumerable<string> Get()  
  3.        {  
  4.            return languages;  
  5.        }   

If need arises, you can get the specified string from the list. We can get it, using Get method with the parameter. Here, Get method contains overload. 

 
  1. // GET api/values/5  
  2.        public string Get(int id)  
  3.        {  
  4.            return languages[id];  
  5.        }   

If need to Add or Save data in the list arises, we can use Post method. For Post method, we use code given below. 

 
  1. // POST api/values  
  2.         public void Post([FromBody]string value)  
  3.         {  
  4.             languages.Add(value);  
  5.         }   

We can update and delete the data in the list, using the code given below. 

 
  1. // PUT api/values/5  
  2.        public void Put(int id, [FromBody]string value)  
  3.        {  
  4.            languages[id] = value;  
  5.        }  
  6.   
  7.        // DELETE api/values/5  
  8.        public void Delete(int id)  
  9.        {  
  10.            languages.RemoveAt(id);  
  11.        }   

Step 3

We are using Fiddler for monitoring Get, Put, Post, Update actions in Web API. We can download it for free from the URL “https://www.telerik.com/download/fiddler” and install it.

Now, build the project solution and run it. I am running URL http://localhost:51860/api/values/. Now, it will call Get action method in ValueController. Put a breakpoint and you can see which method calls in ValueControllers.



When we put above-mentioned output without the parameter, it automatically calls Get method in Web API. After returning an output, we can see the output as an XML, which is shown below.


If we pass index value of the list, we can get a particular string from the list. I am giving http://localhost:51860/api/values/1so, it will return “ASP.NET” because it has an index value 1.


Step 4

Now, open Fiddler and using it, we can monitor POST, PUT and delete. First, run the Application and then copy http://localhost:51860/api/values URL past in Fiddler in composer tab, followed by clicking enter.

Now, double click the latest URL on the left side in Fiddler and you can view the result. This will show the type of result and request header details.

First, refresh the Application in the Browser. Now, go to composer tab, select GET in the drop-down list and click. Track the latest URL from the left side to composer tab. We can see all details like Host, Connection, Catch-Control, User-Agent and Accept details. 



Now, add new string, using post HTTP verb, how to add and again get back from the list, using Fiddler.

Go to composer tab, select POST in the drop-down list and add new string or value in Request body and add Content-Type: application/JSON, followed by clicking Execute button in right side top.

Now, double click the latest URL on the left side of Fiddler and you can see the response of giving Post request in Fiddler. We can see the response is 204 No Content because post action method is void return type.

Now, we can check whether a string is added in a static variable. Now, select get request and delete added string in request body and click execute. Now, double click the latest one on the left side in Fiddler and you can see added string, which looks as shown below.

Now, we can update the last string in a static variable, using PUT HTTP verb in Fiddler. Now, select PUT from the dropdown in composer tab and the type where we want a new string to update the old string, followed by passing the index value to update the string in the URL and click execute button.

Now, refresh the page and get a new one on the left side of Fiddler. Double-click it and we can see the updated string in Fiddler.

Similarly, we can delete the string from a static variable. Similar to selecting Delete HTTP verb, pass an index value of the one, which needs to be deleted from a static variable. After clicking executes, it refreshes our application. For reference, view the screenshot given below.

Conclusion

This step by step article explained about Http verbs in Web API in ASP.NET. I hope it helps freshers and those who are learning ASP.NET Web API.

LINK: http://www.c-sharpcorner.com/article/http-get-put-post-and-delete-verbs-in-asp-net-web-api/http://www.c-sharpcorner.com/article/http-get-put-post-and-delete-verbs-in-asp-net-web-api/