2013-03-21 31 views
13

Tôi đang cố gắng sử dụng Autofac để tiêm phụ thuộc vào FluentValidation trong một ứng dụng MVC 4. Tôi nghĩ rằng tôi đã có chiến lược làm việc ra, nhưng tôi đang gặp khó khăn với việc giải quyết ISomething theo yêu cầu của tôi từ một singleton.Autofac - làm thế nào để giải quyết Func cho ISomething từ Singleton nơi ISomething là InstancePerHttpRequest

Đây là kịch bản: Tôi có trình xác thực xuất phát từ AbstractValidator của FluentValidation. Tôi đã đọc các trình duyệt tính hợp lệ của FluentValidation hoạt động tốt nhất như các trình đơn, do đó nhà xây dựng của tôi mong đợi một Func và lưu trữ Nhà máy đó để sử dụng sau này. Khi trình duyệt tính hợp lệ được sử dụng, nó sẽ yêu cầu nhà máy được lưu trữ cho một IDataStore, nhận được cá thể được tạo cho yêu cầu đó và sử dụng nó. Đó là lý thuyết. Tôi muốn cung cấp tín dụng cho https://github.com/robdmoore/UnobtrusiveMVCTechniques, điều này đã giúp tôi giải quyết vấn đề này. Đây là trình xác thực ...

public class SiteAdminViewModelValidator : AbstractValidator<SiteAdminViewModel> { 
    private readonly Func<IDataStore> _dbFactory; 

    public SiteAdminViewModelValidator(Func<IDataStore> dbFactory) { 
     _dbFactory = dbFactory; 

     RuleFor(model => model.SiteCode).Length(1, 40).Must(BeSpecial); 
    } 

    public bool BeSpecial(string siteCode) { 
     var db = _dbFactory(); 
     List<Stuff> stuffs = db.All<Stuff>().ToList(); 

     return true; 
    } 
} 

Nếu ai đó có thể chỉ cho tôi một ví dụ làm việc về những gì tôi đang cố gắng, điều đó thật tuyệt, nhưng tôi cũng muốn biết giải pháp cho phần cụ thể này của thủ thuật Autofac.

Dưới đây là đăng ký xác nhận của tôi ...

public class FluentValidatorModule : Module { 
    protected override void Load(ContainerBuilder builder) { 
     base.Load(builder); 
     builder.RegisterType<AutofacValidatorFactory>().As<IValidatorFactory>().SingleInstance(); 

    var validators = AssemblyScanner.FindValidatorsInAssembly(System.Reflection.Assembly.GetExecutingAssembly()); 
    validators.ToList().ForEach(v => builder.RegisterType(v.ValidatorType).As(v.InterfaceType).SingleInstance()); 
    } 
} 

Dưới đây là đăng ký của tôi cho các nhà máy IDataStore ...

builder.RegisterType<SuperDB>().As<IDataStore>().InstancePerHttpRequest(); 
builder.Register<Func<IDataStore>>(c => { 
             var context = c.Resolve<IComponentContext>(); 
             return context.Resolve<IDataStore>; 
            }); 

Đây là lỗi tôi nhận được khi validator của tôi yêu cầu một IDataStore trên dòng - var db = _dbFactory();

Không phạm vi nào có khớp với thẻ 'AutofacWebRequest' hiển thị từ phạm vi trong trường hợp yêu cầu. Điều này thường cho biết rằng một thành phần được đăng ký theo yêu cầu trên HTTP đang được yêu cầu bởi thành phần SingleInstance() (hoặc một trường hợp tương tự.) Theo web tích hợp luôn yêu cầu phụ thuộc từ DependencyResolver.Current hoặc ILifetimeScopeProvider.RequestLifetime, không bao giờ từ chính thùng chứa.

... đó là chính xác những gì tôi nhận được khi tôi thử trước khi viết đăng ký Nhà máy của riêng tôi - đăng ký Func. Từ đọc câu trả lời khác nhau cho các câu hỏi tương tự, nó trông giống như những gì tôi có ở trên nên làm việc vì tôi nghĩ rằng tôi đã giải quyết Func để có được người giải quyết hiện tại.

Mọi trợ giúp sẽ được đánh giá cao.

Trả lời

17

Tôi đồng ý rằng điều này sẽ hoạt động - Func<IDataStore> đang xác định nhà máy sẽ tạo phụ thuộc theo từng phương pháp theo yêu cầu.

Cách mà tôi sử dụng phương pháp này là sử dụng DependencyResolver.Current như thông báo lỗi đề xuất. Lý do chính là tôi đã có nó thiết lập bằng cách sử dụng gói NuGet Autofac.Mvc4 ...

DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 

Vì vậy, để thực sự thiết lập các phương pháp tôi có func sau

public Func<T> PerHttpSafeResolve<T>() 
{ 
    return() => DependencyResolver.Current.GetService<T>(); 
} 

Và khi xây dựng chứa

builder.RegisterType<SuperDB>().As<IDataStore>().InstancePerHttpRequest(); 
builder.RegisterInstance(PerHttpSafeResolve<IDataStore>()); 

EDIT: dòng thứ hai được đăng ký dụ đang nói - Nếu bạn cần một Func<IDataStore> sau đó sử dụng các giá trị truyền vào phương pháp này. Kết quả của PerHttpSafeResolve<IDataStore> chỉ là một chức năng (nhà máy), do đó, nó có thể sống như một cá thể duy nhất.

+0

Công trình này! Cảm ơn. Tôi mới sử dụng Autofac. Tôi có thể nhận được chỉ là một làm rõ ngắn về việc đăng ký của builder.RegisterInstance (PerHttpSafeResolve [IDataStore]()); hàng? Vì vậy, nói rằng, "bất cứ khi nào bất cứ ai yêu cầu một Func [IDataStore], sử dụng phương pháp này để cung cấp cho họ một"? –

+0

Xem chỉnh sửa của tôi - Tôi sẽ cố gắng giải thích nó – Felix

+0

Tốt đẹp !! Kỹ thuật đó thật tuyệt vời. Tôi thích nó. Vì vậy, tôi đã viết một bài đăng trên blog: http://robdmoore.id.au/blog/2013/03/23/resolving-request-scoped-objects-into-a-singleton-with-autofac/. Nếu bạn có một blog, hãy cho tôi biết và tôi sẽ liên kết với nó thay vì người dùng SO của bạn. –

7

Vấn đề là phạm vi của trình xác thực. Autofac luôn giải quyết các phụ thuộc SingleInstance từ thùng chứa ứng dụng, điều đó có nghĩa là các phụ thuộc của trình xác nhận hợp lệ cũng đến từ thùng chứa ứng dụng.

Autofac đang yêu cầu ví dụ Func<IDataStore> từ , không phải từ vùng chứa yêu cầu. Khi bạn giải quyết IComponentContext bạn đang nhận được vùng chứa trong đó trình xác thực đang được giải quyết: vùng chứa ứng dụng. Vì Func<IDataStore> được dò tìm theo yêu cầu, không có cách nào để Autofac cung cấp nó ở cấp ứng dụng, do đó có lỗi.

Cách tiếp cận chính xác là đăng ký trình xác thực là InstancePerHttpRequest. Tuổi thọ của một thành phần được quyết định bởi sự phụ thuộc lâu nhất của nó; các trình xác nhận hợp lệ làm việc tốt nhất như các trình đơn khi chúng không có các phụ thuộc.Trong trường hợp này, mặc dù, một trình xác nhận hợp lệ phụ thuộc vào IDataStore bị ràng buộc để sống trong hầu hết thời gian tồn tại của cá thể IDataStore. (Trên mặt tươi sáng, bạn có thể loại bỏ số Func.)

Hãy nghĩ về việc đi dự tiệc: nếu bạn đi cùng chủ nhà, bạn phải ở đó cho đến khi bữa tiệc kết thúc. Bạn không thể đi cùng với chủ nhà nếu bạn muốn rời đi sớm.

+1

Điều này giúp tôi hiểu điều gì đang xảy ra. Tôi đoán đó là lý do tại sao giải pháp của Felix hoạt động và tôi thì không. Ông sử dụng một cách rõ ràng DependencyResolver.Current trong khi tôi chỉ sử dụng c.Resolve. Tôi thực sự muốn tránh việc các nhà xác nhận được xây dựng thường xuyên hơn là hoàn toàn cần thiết. Vì tôi có thể nhận được giải pháp singleton để làm việc, tôi sẽ đi tuyến đường đó. –

+0

@TimHardy: Rất vui khi nghe nó. Đừng quên để cho upvotes câu trả lời đã giúp :-) –

Các vấn đề liên quan