2013-04-30 51 views
5

Tôi đang sử dụng Ninject và các tiện ích mở rộng EventBroker và DependencyCreation trong ứng dụng MVC 3. Tôi đã cài đặt và đang sử dụng gói Ninject.MVC3 và do đó là OnePerRequestModule.Ninject - Phạm vi yêu cầu đã được xử lý

Tôi đang cố gắng tiêm dịch vụ, được gọi là IParentService vào bộ điều khiển. IParentService có sự phụ thuộc vào ChildService được tạo qua tiện ích DependencyCreation (không có tham chiếu cứng).

Cả hai dịch vụ được đăng ký trên trường hợp người môi giới sự kiện địa phương (địa phương là ParentService).

Tôi muốn số IParentService được dàn xếp theo yêu cầu và tôi muốn người phụ thuộc và nhà môi giới sự kiện được xử lý cùng lúc với số IParentService, tuy nhiên, tôi nhận được ScopeDisposedException. Tôi đang làm gì sai?

Một số mã:

Dịch vụ Định nghĩa:

public interface IParentService 
{ 
} 

public class ParentService : IParentService 
{ 
    [EventPublication("topic://ParentService/MyEvent")] 
    public event EventHandler<EventArgs> MyEvent; 
} 

public class ChildService 
{ 
    [EventSubscription("topic://ParentService/MyEvent", typeof(bbv.Common.EventBroker.Handlers.Publisher))] 
    public void OnMyEvent(object sender, EventArgs eventArgs) 
    {    
    } 
} 

Kernel đăng ký (NinjectWebCommon)

private static void RegisterServices(IKernel kernel) 
    { 
     kernel.Bind<IParentService>().To<ParentService>() 
      .InRequestScope() 
      .OwnsEventBroker("ParentServiceBroker") 
      .RegisterOnEventBroker("ParentServiceBroker"); 

     kernel.DefineDependency<IParentService, ChildService>(); 
     kernel.Bind<ChildService>().ToSelf() 
      .WhenInjectedInto<ParentService>() 
      .InDependencyCreatorScope() 
      .RegisterOnEventBroker("ParentServiceBroker");    
    } 

Stack trace:

[ScopeDisposedException: The requested scope has already been disposed.] 
    Ninject.Extensions.NamedScope.NamedScopeExtensionMethods.GetScope(IContext context, String scopeParameterName) in c:\Projects\Ninject\ninject.extensions.namedscope\src\Ninject.Extensions.NamedScope\NamedScopeExtensionMethods.cs:118 
    Ninject.Extensions.NamedScope.NamedScopeExtensionMethods.GetScope(IContext context, String scopeParameterName) in c:\Projects\Ninject\ninject.extensions.namedscope\src\Ninject.Extensions.NamedScope\NamedScopeExtensionMethods.cs:126 
    Ninject.Extensions.NamedScope.<>c__DisplayClass1`1.<InNamedScope>b__0(IContext context) in c:\Projects\Ninject\ninject.extensions.namedscope\src\Ninject.Extensions.NamedScope\NamedScopeExtensionMethods.cs:40 
    Ninject.Planning.Bindings.BindingConfiguration.GetScope(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Bindings\BindingConfiguration.cs:119 
    Ninject.Planning.Bindings.Binding.GetScope(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Bindings\Binding.cs:224 
    Ninject.Activation.Context.GetScope() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:123 
    Ninject.Activation.Caching.Cache.TryGet(IContext context) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Caching\Cache.cs:110 
    Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\ninject\src\Ninject\Activation\Context.cs:150 
    Ninject.<>c__DisplayClass10.<Resolve>b__c(IBinding binding) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:386 
    System.Linq.WhereSelectEnumerableIterator`2.MoveNext() +145 
    System.Linq.<CastIterator>d__b1`1.MoveNext() +85 
    System.Linq.Enumerable.Single(IEnumerable`1 source) +191 
    Ninject.ResolutionExtensions.Get(IResolutionRoot root, String name, IParameter[] parameters) in c:\Projects\Ninject\ninject\src\Ninject\Syntax\ResolutionExtensions.cs:50 
    Ninject.Extensions.ContextPreservation.ContextPreservationExtensionMethods.ContextPreservingGet(IContext context, String name, IParameter[] parameters) in c:\Projects\Ninject\ninject.extensions.contextpreservation\src\Ninject.Extensions.ContextPreservation\ContextPreservationExtensionMethods.cs:56 
    Ninject.Extensions.bbvEventBroker.<>c__DisplayClass2`1.<RegisterOnEventBroker>b__0(IContext ctx, T instance) in c:\Projects\Ninject\ninject.extensions.bbveventbroker\src\Ninject.Extensions.bbvEventBroker\EventBrokerExtensionMethods.cs:45 
    Ninject.Planning.Bindings.<>c__DisplayClass29`1.<OnDeactivation>b__28(IContext context, Object instance) in c:\Projects\Ninject\ninject\src\Ninject\Planning\Bindings\BindingConfigurationBuilder.cs:513 
    Ninject.Activation.Strategies.<>c__DisplayClass4.<Deactivate>b__3(Action`2 action) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Strategies\BindingActionStrategy.cs:42 
    Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map(IEnumerable`1 series, Action`1 action) in c:\Projects\Ninject\ninject\src\Ninject\Infrastructure\Language\ExtensionsForIEnumerableOfT.cs:32 
    Ninject.Activation.Strategies.BindingActionStrategy.Deactivate(IContext context, InstanceReference reference) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Strategies\BindingActionStrategy.cs:42 
    Ninject.Activation.<>c__DisplayClass6.<Deactivate>b__4(IActivationStrategy s) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Pipeline.cs:72 
    Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map(IEnumerable`1 series, Action`1 action) in c:\Projects\Ninject\ninject\src\Ninject\Infrastructure\Language\ExtensionsForIEnumerableOfT.cs:32 
    Ninject.Activation.Pipeline.Deactivate(IContext context, InstanceReference reference) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Pipeline.cs:72 
    Ninject.Activation.Caching.Cache.Forget(CacheEntry entry) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Caching\Cache.cs:253 
    Ninject.Activation.Caching.Cache.Forget(IEnumerable`1 cacheEntries) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Caching\Cache.cs:242 
    Ninject.Activation.Caching.Cache.Clear(Object scope) in c:\Projects\Ninject\ninject\src\Ninject\Activation\Caching\Cache.cs:197 
    Ninject.Web.Common.<>c__DisplayClass2.<DeactivateInstancesForCurrentHttpRequest>b__1(IKernel kernel) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\OnePerRequestHttpModule.cs:74 
    Ninject.GlobalKernelRegistration.MapKernels(Action`1 action) in c:\Projects\Ninject\ninject\src\Ninject\GlobalKernelRegistration.cs:75 
    Ninject.Web.Common.OnePerRequestHttpModule.DeactivateInstancesForCurrentHttpRequest() in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\OnePerRequestHttpModule.cs:74 
    Ninject.Web.Common.OnePerRequestHttpModule.<Init>b__0(Object o, EventArgs e) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\OnePerRequestHttpModule.cs:56 
    System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +136 
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +69 

EDIT - CHI TIẾT THÊM

Các lỗi được ném trong một đại biểu vô hiệu hóa được thiết lập trong các cuộc gọi đến RegisterOnEventBroker, nơi mã cố gắng unregister bất kỳ đối tượng đăng ký trên môi giới sự kiện. Nó không thành công vì phạm vi môi giới sự kiện đã được xử lý, có lẽ vì dịch vụ cha mẹ đã được xử lý. Theo như tôi biết, Ninject sẽ chỉ gọi các đại biểu OnDeactivation cho các đối tượng có thời gian tồn tại ngoài phạm vi Tạm thời, vậy tại sao điều này không hoạt động khi dịch vụ cha mẹ được đăng ký trong RequestScope gây nhầm lẫn cho tôi. Phạm vi thoáng qua là không đủ cho dịch vụ cha mẹ bởi vì tôi đang gặp phải rò rỉ bộ nhớ vì vấn đề này.

Tôi bắt đầu tự hỏi nếu đây là lỗi trong phần mở rộng EventBroker.

Trả lời

2

Trước tiên, bạn phải liên kết IParentService đến ParentService sau đó sử dụng tự ràng buộc loại bê tông kernel.Bind<ParentService>().ToSelf() để xác định phạm vi Đối tượng và nhà môi giới sự kiện.

private static void RegisterServices(IKernel kernel) 
    { 
     kernel.Bind<IParentService>().To<ParentService>(); 


     kernel.Bind<ParentService>().ToSelf() 
     .InRequestScope() 
     .OwnsEventBroker("ParentServiceBroker") 
     .RegisterOnEventBroker("ParentServiceBroker"); 

     kernel.DefineDependency<IParentService, ChildService>(); 
     kernel.Bind<ChildService>().ToSelf() 
      .WhenInjectedInto<ParentService>() 
      .InDependencyCreatorScope() 
      .RegisterOnEventBroker("ParentServiceBroker"); 
    }  

được sửa đổi: nếu loại bạn đang giải quyết là một loại bê tông (như ParentService ở trên), Ninject sẽ tự động tạo ra một liên kết mặc định thông qua một cơ chế gọi là tiềm ẩn ràng buộc tự. Như thế này:

kernel.Bind<ParentService>().ToSelf(); 

Mặt ngầm tự ràng buộc khác được tạo ra trong Phạm vi đối tượng mặc định đó là Transient. Đây là lý do tại sao mã của bạn không chạy trong phạm vi Request.

Để biết thêm thông tin, xem here

Chỉnh sửa 2:

Có một lỗi trong bbvEventBroker mở rộng trong phạm vi Request gây EventBroker được xử lý trước khi xử lý các đối tượng mà đăng ký trên EventBroker đó. Do đó trong phương thức OnDeactivation của đối tượng không có EventBroker mà Unregister của nó có thể được gọi và ScopeDisposedException được ném.

public static IBindingOnSyntax<T> OwnsEventBroker<T>(this IBindingOnSyntax<T> syntax, string eventBrokerName) 
    { 
     string namedScopeName = "EventBrokerScope" + eventBrokerName; 
     syntax.DefinesNamedScope(namedScopeName); 
     syntax.Kernel.Bind<IEventBroker>().To<EventBroker>().InNamedScope(namedScopeName).Named(eventBrokerName); 
     syntax.Kernel.Bind<IEventBroker>().ToMethod(ctx => ctx.ContextPreservingGet<IEventBroker>(eventBrokerName)).WhenTargetNamed(eventBrokerName); 
     return syntax; 
    } 

Bạn có thể nhìn thấy trong OwnsEventBroker phương pháp NamedScope xác định trong phạm vi của đối tượng (ParentService) mà thực thi nó để xử lý trước khi đối tượng (ParentService).

Mặt khác trong OnDeactivation đối tượng (ParentService) cần có EventBroker được xử lý trước đó.

public static IBindingOnSyntax<T> RegisterOnEventBroker<T>(
     this IBindingOnSyntax<T> syntax, string eventBrokerName) 
    { 
     return 
      syntax.OnActivation((ctx, instance) => ctx.ContextPreservingGet<IEventBroker>(eventBrokerName).Register(instance)) 
        .OnDeactivation((ctx, instance) => ctx.ContextPreservingGet<IEventBroker>(eventBrokerName).Unregister(instance)); 
    } 

EventBrokerExtensionMethods.cs

Giải pháp là tạo ra cây đối tượng với NamedScope. Xác định cha mẹ trong phạm vi Request trong khi xác định NamedScope cho con của nó (Nhà xuất bản/Người đăng ký) và sở hữu nhà môi giới sự kiện (OwnsEventBroker). Sau đó, xác định Nhà xuất bản (ChildService1) và Người đăng ký (ChildService2) trong phạm vi được đặt tên đã được xác định bởi phụ huynh. Bằng cách này, bạn có thể đảm bảo rằng chủ sở hữu của người môi giới sự kiện sẽ được xử lý sau khi con họ.

+0

Cảm ơn Kambiz, điều đó giải quyết được lỗi. Bạn có thể xây dựng thêm một chút về những gì đã sai với cách tôi đã làm nó và tại sao nó cần phải được thực hiện theo cách này? – nukefusion

+0

@nukefusion Tôi cập nhật câu trả lời kiểm tra xem nó –

+0

Tôi đã tăng gấp đôi kiểm tra này nhưng trong thử nghiệm của tôi tôi đang tiêm IParentService không phải là loại cụ thể. Điều này xuất hiện để sửa chữa vấn đề của tôi nhưng thực sự nó chỉ là sử dụng ràng buộc đầu tiên của bạn thay vì thứ hai 'tự' ràng buộc. Nếu tôi sử dụng mã của bạn và tiêm một ví dụ 'ParentService' tôi nhận được cùng một ngoại lệ. – nukefusion

2

Ninject core hiện đang hủy kích hoạt các đối tượng nằm trong phạm vi của đối tượng trước khi hủy kích hoạt đối tượng.

Thay đổi thứ tự dường như khắc phục được sự cố đó. Mặc dù trước khi đẩy thay đổi đó, tôi phải kiểm tra những tác dụng phụ nào có thể xảy ra trong các tình huống khác.

+0

Cảm ơn bạn đã xem Remo này. Có một vấn đề mở cho điều này vì vậy tôi có thể theo dõi nó? – nukefusion