Search This Blog

Saturday, April 15, 2017

Tạo demo áp dụng Dependency Injection trong ASP.NET MVC

Bước 1: Tạo project ASP.NET MVC như hình bên dưới, đặt tên là DemoDependencyInjection.

Chọn template cho project là MVC, sau đó click OK để tạo project.

Bước 2: Tạo mới một Controller.

Chọn MVC5 Controller - Empty.

Đặt tên là DIController.

DIController sau khi tạo xong.
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Web;  
 using System.Web.Mvc;  
 namespace DemoDependencyInjection.Controllers  
 {  
   public class DIController : Controller  
   {  
     // GET: DI  
     public ActionResult Index()  
     {  
       return View();  
     }  
   }  
 }  

Bước 3: Cài đặt Nuget package Microsoft.Extensions.DependencyInjection.
Trong cửa sổ Package Manager Console, nhập "install-package Microsoft.Extensions.DependencyInjection".

Bước 4: Cập nhật file Startup.cs.
Ban đầu khi tạo mới project thì bên trong file Startup.cs chúng ta chỉ có một method Configuration.
 using Microsoft.Owin;  
 using Owin;  
 [assembly: OwinStartupAttribute(typeof(DemoDependencyInjection.Startup))]  
 namespace DemoDependencyInjection  
 {  
   public partial class Startup  
   {  
     public void Configuration(IAppBuilder app)  
     {  
       ConfigureAuth(app);  
     }  
   }  
 }  

Chúng ta bổ sung thêm method ConfigureServices như bên dưới.
 public void ConfigureServices(IServiceCollection services)  
 {  
 }  

Hãy nhớ bổ sung namespace "Microsoft.Extensions.DependencyInjection" cho class Startup.

Cập nhật lại method Configuration như bên dưới
 public void Configuration(IAppBuilder app)  
 {  
    ConfigureAuth(app);  

    var services = new ServiceCollection();  
    ConfigureServices(services);  
 }  

Tạo class MyDepedencyResolver kế thừa từ interface IDependencyResolver và bổ sung đoạn code như bên dưới, chú ý bổ sung namespace System.Web.MvcMicosoft.Extensions.DependencyInjection.
 using System;  
 using System.Collections.Generic;  
 using System.Web.Mvc;  
 using Microsoft.Extensions.DependencyInjection;  
 namespace DemoDependencyInjection  
 {  
   public class MyDependencyResolver : IDependencyResolver  
   {  
     protected IServiceProvider serviceProvider;  
     public MyDependencyResolver(IServiceProvider serviceProvider)  
     {  
       this.serviceProvider = serviceProvider;  
     }  
     public object GetService(Type serviceType)  
     {  
       return this.serviceProvider.GetService(serviceType);  
     }  
     public IEnumerable<object> GetServices(Type serviceType)  
     {  
       return this.serviceProvider.GetServices(serviceType);  
     }  
   }  
 }  

Sau khi đã tạo class MyDependencyResolver xong, tiến hành cập nhật method Configuration trong file Startup.cs.
 public void Configuration(IAppBuilder app)  
 {  
    ConfigureAuth(app);  

    var services = new ServiceCollection();  
    ConfigureServices(services);  
    var resolver = new MyDependencyResolver(services.BuildServiceProvider());  
    DependencyResolver.SetResolver(resolver);  
 }  

Bước 5: Tạo service.
Tạo interface IDIService gồm method GetCode như bên dưới.
 namespace DemoDependencyInjection  
 {  
   public interface IDIService  
   {  
     string GetCode();  
   }  
 }  

Tạo class DIService kế thừa từ interface đã tạo ở trên, đồng thời implement method GetCode.
 namespace DemoDependencyInjection  
 {  
   public class DIService : IDIService  
   {  
     public string GetCode()  
     {  
       return "Hello " + GetHashCode();  
     }  
   }  
 }  

Bước 6: Sử dụng service trong controller.
Vào lại class DIController, khai báo một biến _service từ interface IDIService.
private readonly IDIService _service;  

vả bổ sung hàm khởi tạo có tham số đầu vào cho DIController như bên dưới
public DIController(IDIService service)  
{  
   this._service = service;  
} 

Cập nhật lại action Index bên trong DIController, nó sẽ nhận kết quả từ method GetCode của serivce và gán vào ViewBag.Message.
 // GET: DI  
 public ActionResult Index()  
 {  
     // say Hello  
     ViewBag.Message = this._service.GetCode();  
     return View();  
 }  

Bên dưới là đoạn code đầy đủ của DIController.
 using System.Web.Mvc;  
 namespace DemoDependencyInjection.Controllers  
 {  
   public class DIController : Controller  
   {  
     private readonly IDIService _service;  
     public DIController(IDIService service)  
     {  
       this._service = service;  
     }  
     // GET: DI  
     public ActionResult Index()  
     {  
       // say Hello  
       ViewBag.Message = this._service.GetCode();  
       return View();  
     }  
   }  
 }  

Bước 7: Tiến hành Add View cho action Index.

Đặt tên cho view là Index.


Cập nhật code cho view Index hiển thị thông điệp từ ViewBag.Message.
 @{  
   ViewBag.Title = "Index";  
 }  
 <h2>@ViewBag.Message</h2>  

Bước 8: Đăng ký service trong file Startup.cs.
Vào method ConfigureServices trong file Startup.cs và đăng ký vào danh sách service.
 public void ConfigureServices(IServiceCollection services)  
 {  
    services.AddTransient<IDIService, DIService>();  
 }  

Tiến hành BuildRun project, trên thanh Address đi đến trang DI.

Lúc này chúng ta sẽ nhận thông báo lỗi vì DIController chưa được đăng ký cho phép có hàm khởi tạo có tham số đầu vào. Để cho phép điều này, ta cần đăng ký controller vào danh sách service.

Tạo mới một static class đặt tên ServiceProviderExtensions và bổ sung static method AddControllersAsServices như là một extension của IServiceCollection như bên dưới.
 using Microsoft.Extensions.DependencyInjection;  
 using System;  
 using System.Collections.Generic;  
 namespace DemoDependencyInjection  
 {  
   public static class ServiceProviderExtensions  
   {  
     public static IServiceCollection AddControllersAsServices(this IServiceCollection services, IEnumerable<Type> controllerTypes)  
     {  
       foreach (var type in controllerTypes)  
       {  
         services.AddTransient(type);  
       }  
       return services;  
     }  
   }  
 }  

Vào lại file Startup.cs, trong method ConfigureServices tiến hành đăng ký tất cả controller vào danh sách service.
 public void ConfigureServices(IServiceCollection services)  
 {  
     services.AddControllersAsServices(typeof(Startup).Assembly.GetExportedTypes()  
         .Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition)  
         .Where(t => typeof(IController).IsAssignableFrom(t)   
         || t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)));  

     services.AddTransient<IDIService, DIService>();  
 }  

Tiến hành BuildRun project, lúc này khi đi đến trang DI đã không còn lỗi và hiển thị thông điệp từ method GetCode.

Tiếp theo hãy thử Refresh trang, lúc này chúng ta sẽ có một kết quả hiển thị khác.
Đó là bởi vì trong method ConfigureServices chúng ta đăng ký service một cách tạm thời.
services.AddTransient<IDIService, DIService>();  
Mỗi khi có yêu cầu sử dụng DIService, nó sẽ tạo mới một instance, do đó kết quả trả về từ method GetCode của DIService sẽ khác nhau cho mỗi lần yêu cầu.

Trong trường hợp nếu chúng ta muốn chỉ tạo ra một và chỉ một instance của DIService được sử dụng cho mọi yêu cầu, thay thế đoạn code trên bằng đoạn code bên dưới.
services.AddSingleton<IDIService, DIService>();  

----------------------
Share to be shared
----------------------