14

IoC kütüphanem olarak SimpleInjector kullanıyorum. Web isteği doğrultusunda DbContext'u kayıt ederim ve iyi çalışıyor. Ama arka plan iş parçacığında çalıştırdığım bir görev var. Yani, DbContext örnekleri oluşturmak için bir sorunum var. Örneğin.Basit Sıkıştırıcı ile Per Konu Başına ve Web İsteği Başına Karışık Yaşam Tarzı

  1. Service1DbContext
  2. Service2 bir örneği olan arka plan akıştan DbContext
  3. Service1 ve Service2 seferin bir örneği vardır.
  4. Service1 bir varlık getirir ve Service2
  5. Service2 iletecek varlık olduğunu kullanır ama Aslında sorun burada varlık DbContext

ayrılır: Service1.DbContextService2.DbContext gelen farktır.

ASP.NET MVC'de ayrı bir iş parçacığında bir görev çalıştırdığımda, SimpleInjector her arama için yeni bir DbContext örneği oluşturur. Bazı IoC kütüphaneleri (örneğin, StructureMap) web-per-thread-thread başına karışık bir yaşam tarzına sahip olsa da, SimpleInjector'un bir tane olmadığı görülmektedir. Ben haklı mıyım

SimpleInjector'da bu sorunu çözmek için herhangi bir fikriniz var mı? Şimdiden teşekkürler.

DÜZENLEME:

Hizmetlerim Buradasınız:

class Service1 : IService1 { 
    public Service1(MyDbContext context) { } 
} 

class Service2 : IService2 { 
    public Service2(MyDbContext context, IService1 service1) { } 
} 

class SyncServiceUsage { 
    public SyncServiceUsage(Service2 service2) { 
     // use Service2 (and Service1 and DbContext) from HttpContext.Current 
    } 
} 

class AsyncServiceUsage { 
    public AsyncServiceUsage(Service2 service2) { 
     // use Service2 (and Service1 and DbContext) from background thread 
    } 
} 

public class AsyncCommandHandlerDecorator<TCommand> 
    : ICommandHandler<TCommand> where TCommand : ICommand { 

    private readonly Func<ICommandHandler<TCommand>> _factory; 

    public AsyncCommandHandlerDecorator(Func<ICommandHandler<TCommand>> factory) { 
     _factory = factory; 
    } 

    public void Handle(TCommand command) { 
     ThreadPool.QueueUserWorkItem(_ => { 
      // Create new handler in this thread. 
      var handler = _factory(); 
      handler.Handle(command); 
     }); 
    } 
} 

void InitializeSimpleInjector() { 
    register AsyncCommandHandlerDecorator for services (commands actually) that starts with "Async" 
} 

Ben kullanıcı Service2 bazen ve AsyncService2 diğer zamanlarda.

+0

İlgili: http://stackoverflow.com/questions/11041601/simple-injector-multi-threading-in-mvc3-asp-net – Steven

+0

İlgili: http://stackoverflow.com/questions/10304023/simpleinjector-is -bu-sağ-yol-için-kayıt-erkek-posta-ne-i-var – Steven

cevap

17

ASP.NET MVC ayrı bir konu bir görev çalıştırdığınızda görünüyor, SimpleInjector her arama için DBContext yeni bir örneğini oluşturur.

aşağıda

Basit Enjektör v1.5 ait RegisterPerWebRequest yaşam tarzı davranışı ve örnekleri (HttpContext.Current boş) bir web isteği bağlamı dışında istendiğinde geçici örneğini döndürmektir. Geçici bir örneğin döndürülmesi, Basit Enjektörde bir tasarım hatasıydı, çünkü bu yanlış kullanımı gizlemeyi kolaylaştırıyor. Version 1.6 of the Simple Injector, geçici olarak hatalı bir örnek döndürmek yerine, kapsayıcıyı yanlış yapılandırdığınız açıkça iletişim kurmak için bir istisna atar.

(örneğin StructureMap için) bazı IoC kütüphaneler başına iplik başına webrequest için karışık yaşam tarzı sahipken

, değil bir

Bu doğrudur Basit Enjektör sahiptir görünüyor Basit Enjektör Birkaç sebepten dolayı karışık yaşam tarzları için yerleşik destek yoktur. Her şeyden önce pek çok insanın ihtiyaç duyduğu egzotik bir özellik. İkincisi, iki ya da üç yaşam tarzını bir araya getirebilirsiniz, böylece melezlerin neredeyse sonsuz bir kombinasyonu olacaktır.Ve son olarak, bunu (güzel) kolayca kendiniz kaydedin.

Eğer Per Thread yaşam tarzları ile Per Web Request karıştırabilirsiniz olsa da, Per Lifetime Scope Web Request Başına mix Ömür Kapsam ile beri açıkça başlatmak ve kapsamını bitirmek (ve kapsam sona erdiğinde DbContext imha edebiliriz) zaman, muhtemelen daha iyi olurdu .

Simple Injector 2'dan itibaren, Lifestyle.CreateHybrid yöntemini kullanarak herhangi bir sayıda yaşam tarzını kolayca birleştirebilirsiniz. Simple Injector: multi-threading in MVC3 ASP.NET

GÜNCELLEME Güncellemenize Hakkında

:

var hybridLifestyle = Lifestyle.CreateHybrid(
    () => HttpContext.Current != null, 
    new WebRequestLifestyle(), 
    new LifetimeScopeLifestyle()); 

// Register as hybrid PerWebRequest/PerLifetimeScope. 
container.Register<DbContext, MyDbContext>(hybridLifestyle); 

derin biraz, bir göz atmak isteyebilirsiniz Bu konuda gider başka Stackoverflow soru var: İşte bir örnek. Neredeyse ordasın. Arka plan iş parçacığı üzerinde çalışan komutların Ömür Boyu Kapsamı içinde çalışması gerekir, bu nedenle bunu açıkça başlatmanız gerekir. Buradaki hile, yeni iş parçacığına BeginLifetimeScope numaralı telefonu aramaktır, ancak gerçek komut işleyicisi (ve bağımlılıkları) oluşturulmadan önce. Başka bir deyişle, bunu yapmanın en iyi yolu bir dekoratörün içinde. Bu dekoratör hem yeni iş parçacığı üzerinde komutları çalıştırır beri SOLID ilkeleri bu sınıf Single Responsibility Principle ihlal ettiğini bağıracak savunan

public class AsyncCommandHandlerDecorator<TCommand> 
    : ICommandHandler<TCommand> where TCommand : ICommand 
{ 
    private readonly Container _container; 
    private readonly Func<ICommandHandler<TCommand>> _factory; 

    public AsyncCommandHandlerDecorator(Container container, 
     Func<ICommandHandler<TCommand>> factory) 
    { 
     _container = container; 
     _factory = factory; 
    } 

    public void Handle(TCommand command) 
    { 
     ThreadPool.QueueUserWorkItem(_ => 
     { 
      using (_container.BeginLifetimeScope()) 
      { 
       // Create new handler in this thread 
       // and inside the lifetime scope. 
       var handler = _factory(); 
       handler.Handle(command); 
      } 
     }); 
    } 
} 

Purists:

kolay çözüm kapsamını eklemek için AsyncCommandHandlerDecorator yenilenmesini sağlar ve yeni bir ömür boyu kapsamı başlatır. Bu konuda çok fazla endişelenmem, çünkü arka plan iş parçacığı ile hayat boyu bir alan kurmaya başlamak arasında yakın bir ilişki olduğunu düşündüğümden (zaten bir başkasını kullanamazsın). Ama yine de, kolayca AsyncCommandHandlerDecorator bakir bırakın ve aşağıdaki gibi yeni LifetimeScopedCommandHandlerDecorator oluşturabilirsiniz:

public class LifetimeScopedCommandHandlerDecorator<TCommand> 
    : ICommandHandler<TCommand> where TCommand : ICommand 
{ 
    private readonly Container _container; 
    private readonly Func<ICommandHandler<TCommand>> _factory; 

    public LifetimeScopedCommandHandlerDecorator(Container container, 
     Func<ICommandHandler<TCommand>> factory) 
    { 
     _container = container; 
     _factory = factory; 
    } 

    public void Handle(TCommand command) 
    { 
     using (_container.BeginLifetimeScope()) 
     { 
      // The handler must be created inside the lifetime scope. 
      var handler = _factory(); 
      handler.Handle(command); 
     } 
    } 
} 

AsyncCommandHandlerDecoratorLifetimeScopedCommandHandlerDecorator sarmak gerektiğinden bu dekoratörler, tabii esas teşkil eden kayıtlı sırası. Bu konuda

container.RegisterDecorator(typeof(ICommandHandler<>), 
    typeof(LifetimeScopedCommandHandlerDecorator<>), 
    backgroundCommandCondition); 

container.RegisterDecorator(typeof(ICommandHandler<>), 
    typeof(AsyncCommandHandlerDecorator<>), 
    backgroundCommandCondition); 

This old Stackoverflow question görüşmelere daha ayrıntılı olarak: Bu LifetimeScopedCommandHandlerDecorator kaydı şeyden önce gelmeli anlamına gelir. Kesinlikle bir göz atmalısın.

+1

Teşekkürler + Steven Ben diğer bağlantıyı ve yararlı ve yararlı okuyun. Ayrıca, SimpleInjector'ın itibarını iyileştirmek için cevabın tamamını ve hepsini sorguladım. İyi şanslar –

+0

WTF Kafam karıştı! Sorumu düzenlerim. Bana kullanımdan bahseder misiniz? "Service1" ve "Service2" nesneleri, hem ana iş parçacığında (web isteği) hem de arka plan iş parçacığında kullanılır. Bunu yapabilmek istiyorum. Ve ben bunlara enjektör enjeksiyonu ile 'DbContext' enjekte ediyorum. Uygulamamı değiştirmeli miyim? –

+1

@Javad_Amiry: Geç cevap verdiğim için üzgünüm, ama geliştiricilerin bile bazen dinlenmeye ihtiyacı var ;-). Cevabımı güncelledim. Umarım bu yardımcı olur. – Steven