sử dụng autofac trong asp.net mvc
autofac
Là 1 ioc container như bao ioc container khác (Unity/Ninject/StructureMap/...). Sở dĩ mình chọn autofac là vì:
Autofac is always kept up to date to support the latest version of ASP.NET MVC
và autofac intergrate with asp.net mvc giúp cho việc setup và sử dụng đơn giản hơn bản giờ hết.
Trong phạm vi bài viết này mình sẽ không nói về Inversion of Control (IoC)/ IoC container mà chỉ hướng dẫn cách sử dụng Autofac ioc container trong asp.net mvc. Bên cạnh đó, sử dụng ioc hay không cũng tùy vào ý muốn của bạn (có lẽ bạn nên tìm hiểu nhiều hơn để biết mình có nên/cần sử dụng ioc hay không).
Xem tại đây để biết các thuật ngữ được khi sử dụng autofac. Mình xin giải thích 1 cách "tương đối" 1 số thuật ngữ cơ bản để bạn có thể dễ dàng hình dung:
- Service: [là] 1 interface, trong đó expose các methods để "sử dụng"
public interface IFoo // autofac Service
{
int Add(int x, int y);
}
- Component: [là] 1 class/type kế thừa 1 interface (service) nào đó
public class Foo : IFoo // autofac component
{ }
- Dependencies: [là] 1 hoặc nhiều các service được chèn (inject) vào 1 phương thức của component
public class Foo : IFoo
{
// IBar is a service
// bar is a dependency
public int DoSomething(IBar bar)
{
return 0;
}
}
- Parameter: [là] 1 tham số của 1 hàm nhưng không phải là dependency
public class Foo : IFoo
{
// bar is dependency, score is parameter
public int DoSomething(IBar bar, int score)
{
return 0;
}
}
setup
Ở đây mình sử dụng Asp.NET Mvc integration, cho nên mình sẽ cài package này luôn thông qua nuget
Install-Package Autofac.Mvc5
đăng ký
Hầu hết các IoC container đều cho phép đăng ký thông qua xml hoặc code behind. Mình thích sử dụng code behind hơn (vì có intellisence ^^). Trong Mvc bạn có thể đăng ký 1 lần duy nhất ở Application_Start
protected void Application_Start()
{
IoCContainer.InitContainer();
// other things
}
Đăng ký container:
// remember to using these namespaces
using Autofac;
using Autofac.Integration.Mvc;
public class IoCContainer
{
public static void InitContainer()
{
var builder = new ContainerBuilder();
// register assembly
builder.RegisterControllers(typeof(your-namespace.MvcApplication).Assembly);
// register model binder
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterModelBinderProvider();
// register web abstractions
builder.RegisterModule<AutofacWebTypesModule>();
// enable property injection in view pages
builder.RegisterSource(new ViewRegistrationSource());
// enable property injection into action filters
builder.RegisterFilterProvider();
// set the dependency resolver to to autofac
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
Bạn có thể lược bỏ các register optional đi nếu không sử dụng (minimum setup)
public class IoCContainer
{
public static void InitContainer()
{
var builder = new ContainerBuilder();
// register assembly
builder.RegisterControllers(typeof(your-namespace.MvcApplication).Assembly);
// set the dependency resolver to to autofac
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
Nếu bạn có sử dụng Repository
public class IoCContainer
{
public static void InitContainer()
{
var builder = new ContainerBuilder();
// register assembly
builder.RegisterControllers(typeof(your-namespace.MvcApplication).Assembly);
// register repositories
builder.Register(t => new PostRepository(new YourDbContext())).As<IPostRepository>();
// set the dependency resolver to to autofac
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
Nếu bạn có sử dụng RenericRepository (lưu ý thứ tự đăng ký, vì IPostRepository kế thừa từ IGenericRepository nên mình phải đăng ký IGenericRepository trước)
public class IoCContainer
{
public static void InitContainer()
{
var builder = new ContainerBuilder();
// register assembly
builder.RegisterControllers(typeof(your-namespace.MvcApplication).Assembly);
// register generic repository
builder.RegisterGeneric(typeof(GenericRepository<,>))
.As(typeof(IGenericRepository<,>))
.WithParameter("db", new YourDbContext());
// register repositories
builder.Register(t => new PostRepository(new YourDbContext())).As<IPostRepository>();
// set the dependency resolver to to autofac
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
Với interface IGenericRepository của mình như sau
public interface IGenericRepository<TEntity, TKey> :
IDisposable where TEntity : class
Và GenericRepository với constructor
public class GenericRepository<TEntity, TKey> :
IGenericRepository<TEntity, TKey> where TEntity : class
{
public GenericRepository(YourDbContext db)
{
// init
}
}
Một số chú ý:
Registerdùng để đăng ký 1 type bất kỳRegisterGenericdùng để đăng ký 1 generic type- với extension method
.WithParameter(name, value), bạn có thể truyền tham số mặc định cho constructor
Xem thêm 1 số cách register khác tại: autofac registration document
instance scope
Instance scope hiểu đơn giản là phạm vi sử dụng của 1 instance sau khi được khởi tạo. Bạn có thể xem thêm trong document của autofac để biết thêm.
Với những service có sử dụng connection/transaction..., bạn nên kế thừa interface IDisposable để autofac disposal dispose object qua mỗi request/response (xem thêm để biết, sử dụng lâu sẽ hiểu :v)
Sử dụng
Giả sử mình có 1 service như sau:
public interface IPostRepository
{
List<Post> GetAllPost();
}
Component implement service:
public class PostRepository : GenericRepository<Post, int>, IPostRepository
{
public PostRepository(YourDbContext db) : base(db)
{ }
public List<Post> GetAllPost()
{
return new List<Post>();
}
}
Cuối cùng, trong Controller
public class HomeController : BaseController
{
private IPostRepository _postRepo;
public HomeController(IPostRepository postRepo) // inject
{
_postRepo = postRepo;
}
public ActionResult Index()
{
var posts = _postRepo.GetAllPost(); // using
return View(model);
}
}
Tất nhiên bạn vẫn có thể khai báo container hoặc sử dụng service locator như thường.
Kết
Vẫn còn khá nhiều tranh cãi (trên mạng) về việc sử dụng IoC, tuy nhiên lợi ích của nó thì không thể chối cãi. Bạn thấy đấy, code rất gọn gàng, modular..bla bla bla :))
Hy vọng qua bài viết này bạn có thêm 1 option cho mình khi lựa chọn 1 IoC container ưa thích cho mình. Good look ^^!
No comments:
Post a Comment
make a awesome comment