2010-07-03 14 views
6

[OR] Làm thế nào để xác định một chu kỳ sống StructureMap cho UOW được tiêu thụ bởi các yêu cầu http và việc làm thạch anhStructureMap trả về một đối tượng session nHibenrate thanh lý khoản từ chủ đề local scope

Tôi có ứng dụng web này trong đó sử dụng SM cho IoC. Tôi đang sử dụng HybridHttpOrThreadLocalScoped phạm vi để lưu trữ các đối tượng ISH nHibernate của tôi. Điều này làm việc ok trong một phiên cho mỗi yêu cầu thời trang cho các yêu cầu web của tôi.

Nhưng tôi cũng có quartz.net để lên lịch cho một vài công việc. Công việc này sử dụng cùng một đơn vị công việc để có được đối tượng ISession. Trong trường hợp này khi trình lên lịch bắt đầu công việc, mọi thứ hoạt động tốt lúc đầu và công việc chạy tốt cho vài lần UNTIL id công việc được lặp lại.

Hãy tưởng tượng rằng khi công việc được lên lịch, nó bắt đầu chạy trong các chủ đề có id 11, 12, 13 và sau đó với chuỗi id 11 một lần nữa. Tại thời điểm này structuremap trả về một đối tượng session đã được xử lý và tôi nhận được "System.ObjectDisposedException: Session bị đóng!" lỗi. Vì vậy, từ những gì tôi có thể nhìn thấy, phiên được giữ trong lưu trữ cục bộ luồng và sau khi tôi bỏ phiên vào cuối đơn vị công việc của tôi, đối tượng phiên vẫn được giữ trong bộ nhớ cục bộ của luồng. Dường như sau khi chủ đề chấm dứt lưu trữ cục bộ của nó không bị xóa và bằng cách nào đó khi một chuỗi mới có cùng id được tạo, structuremap tìm kiếm phiên trong lưu trữ cục bộ cũ thread (được cho là xóa cho chuỗi mới) Tôi tin) và trả về đối tượng phiên đã được xử lý.

Câu hỏi:

  1. Có cách nào để xóa thread lưu trữ địa phương (về việc chấm dứt)?
  2. Có tương đương với "ReleaseAndDisposeAllHttpScopedObjects" cho các đối tượng có phạm vi chuỗi không?
  3. Có cách nào để vô hiệu hóa (hoặc đẩy ra) đối tượng được xử lý để ngay cả khi SM tìm kiếm nó thì nó sẽ không tìm thấy bất kỳ và phải tạo một cá thể mới?

Tôi hy vọng tôi đã làm rõ câu hỏi của mình. Điều này đã mất vài giờ thời gian của tôi và vẫn còn tôi đã không tìm thấy một cách xung quanh nó. Tôi đánh giá cao bất kỳ gợi ý:>

Cập nhật: tôi đã thêm giải pháp của riêng mình để thực hiện một UOW phục vụ bởi việc StructureMap với cả hai yêu cầu http và việc làm thạch anh. Hãy cho tôi biết nếu bạn có giải pháp tốt hơn/dễ dàng hơn/đơn giản hơn.

+0

Bạn có đang quản lý các IJob thạch anh của mình với StructureMap không? –

+0

@Mauricio: Tôi đang sử dụng StructureMap trong ứng dụng của mình. Tôi không chắc chắn những gì bạn có nghĩa là bằng cách quản lý công việc thạch anh bởi StructeMap mặc dù:> – kaptan

+0

là trường hợp thạch anh IJob của bạn được quản lý bởi StructureMap? Nói cách khác: bạn có đăng ký công việc của bạn trong container? –

Trả lời

1

Tại sao không tạo phiên mới cho công việc thạch anh? Một đơn vị công việc thường là một hoạt động giao dịch trên db. Tôi không thể tưởng tượng các công việc thạch anh đang giao dịch liên quan đến yêu cầu/phản hồi trên web. Tạo phiên mới không tốn kém. Đây có phải là một khả năng?

+0

Có. Tôi muốn tạo một phiên mới cho mỗi công việc thạch anh. Nhưng vì tôi đang sử dụng ý tưởng của UoW, tôi muốn nó nhất quán trong ứng dụng của tôi. Vì vậy, tôi không muốn tạo phiên trực tiếp cho công việc thạch anh. Tôi muốn tạo một cá thể UoW. Nhưng đồng thời tôi muốn sử dụng StructureMap để có được một thể hiện của UoW. Đó là lý do tại sao tôi đã kết thúc việc xác định một vòng đời lai trong StructeMap cho UoW của tôi sao cho nó sẽ trả về UoW thích hợp cho mỗi yêu cầu http hoặc mỗi lần thực hiện công việc thạch anh. – kaptan

+0

@kaptan: Tôi đồng ý với @rcravens. Những gì tôi đã làm là lấy một thể hiện của ISessionFactory (ObjectFactory.GetInstance ()) và mở một phiên mới khi công việc của tôi kích hoạt. – LeftyX

2

Tôi đã xem lại những gì tôi đã làm để StructureMap hoạt động với UoW trên mỗi Http và UoW trên mỗi công việc thạch anh và tôi quyết định chia sẻ giải pháp của mình ở đây. Vì vậy, ý tưởng là tôi muốn sử dụng phạm vi StructureMap Hybrid để có được một thể hiện của UoW khi có một bối cảnh http và cũng nhận được một thể hiện khác của UoW trên mỗi luồng khi không có ngữ cảnh http (như khi một công việc thạch anh cháy). Như thế này:

For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<UnitOfWork>(); 

UoW cho http đã hoạt động tốt. Vấn đề là UoW mỗi thread.

Đây là những gì sẽ xảy ra. Khi một công việc quratz bắn nó kéo một luồng từ nhóm luồng và bắt đầu thực hiện công việc bằng cách sử dụng luồng đó. Khi công việc bắt đầu, tôi yêu cầu một UoW. StructureMap trông dưới kho lưu trữ cục bộ cho luồng đó để trả về UoW, nhưng vì nó không thể tìm thấy bất kỳ nó ngay lập tức và lưu nó dưới bộ nhớ cục bộ của thread.I nhận được UoW, sau đó perfom Begin, Commit, Dispose và mọi thứ đều ổn.

Sự cố xảy ra khi luồng được kéo từ nhóm luồng đã được sử dụng trước đó để kích hoạt công việc (và sử dụng UoW). Ở đây khi bạn yêu cầu một UoW, StructureMap tìm trong bộ đệm (lưu trữ cục bộ luồng) và tìm một UoW và trả về nó cho bạn. Nhưng vấn đề là UoW được xử lý!

Vì vậy, chúng tôi không thể thực sự sử dụng UoW cho mỗi chủ đề cho các công việc thạch anh vì bản thân các chủ đề không được xử lý và chúng giữ các UoW được lưu trữ cũ. Về cơ bản vòng đời của một sợi không khớp với vòng đời của công việc thạch anh. Đó là lý do tại sao tôi tạo chu kỳ sống của riêng mình cho một công việc thạch anh.

Trước tiên tôi tạo riêng lớp chu http-thạch anh lai cuộc sống của tôi:

public class HybridHttpQuartzLifecycle : HttpLifecycleBase<HttpContextLifecycle, QuartzLifecycle> 
{ 
    public override string Scope { get { return "HybridHttpQuartzLifecycle"; } } 
} 

Sau đó, tôi tạo ra lớp QuartzLifecyle tôi:

public class QuartzLifecycle : ILifecycle 
{ 

    public void EjectAll() 
    { 
     FindCache().DisposeAndClear(); 
    } 

    public IObjectCache FindCache() 
    { 
     return QuartzContext.Cache; 
    } 

    public string Scope { get { return "QuartzLifecycle"; } } 
} 

Sau đó, tôi cần phải tạo ra một số lớp bối cảnh như HttpContext cho thạch anh để giữ thông tin liên quan đến ngữ cảnh. Vì vậy, tôi tạo ra lớp QuartzContext. Khi công việc thạch anh được kích hoạt, JobExecutionContext cho công việc đó sẽ được đăng ký trong QuartzContext. Sau đó, cache thực tế (MainObjectCache) cho các cá thể StructureMap sẽ được tạo ra dưới lớp JobExecutionContext cụ thể đó. Vì vậy, cách này sau khi thực hiện công việc kết thúc bộ nhớ cache sẽ biến mất quá và chúng tôi sẽ không có vấn đề xử lý UoW trong bộ nhớ cache.

Cũng vì _jobExecutionContext là ThreadStatic, khi chúng tôi yêu cầu bộ nhớ cache từ QuartzContext, nó sẽ trả về bộ đệm từ JobExecutionContext được lưu cho cùng một chuỗi. Vì vậy, khi nhiều công việc đang chạy cùng một lúc, JobExecutionContexts của họ được lưu riêng và chúng tôi sẽ có bộ đệm riêng cho từng công việc đang chạy.

public class QuartzContext 
{ 

    private static readonly string _cacheKey = "STRUCTUREMAP-INSTANCES"; 

    [ThreadStatic] 
    private static JobExecutionContext _jobExecutionContext; 

    protected static void Register(JobExecutionContext jobExecutionContext) 
    { 
     _jobExecutionContext = jobExecutionContext; 
     _jobExecutionContext.Put(_cacheKey, new MainObjectCache()); 
    } 

    public static IObjectCache Cache 
    { 
     get 
     { 
      return (IObjectCache)_jobExecutionContext.Get(_cacheKey); 
     } 
    } 
} 

Tôi có một lớp trừu tượng được gọi là BaseJobSingleSession mà các công việc khác xuất phát từ đó. Lớp này mở rộng lớp QuartzContext. Bạn có thể thấy rằng tôi đăng ký JobExecutionContext khi công việc được kích hoạt.

abstract class BaseJobSingleSession : QuartzContext, IStatefulJob 
{ 
    public override void Execute(JobExecutionContext context) 
    { 
     Register(context); 
     IUnitOfWork unitOfWork = ObjectFactory.GetInstance<IUnitOfWork>(); 

     try 
     { 
      unitOfWork.Begin(); 

      // do stuff .... 

      unitOfWork.Commit(); 
     } 
     catch (Exception exception) 
     { 
      unitOfWork.RollBack(); 

     } 
     finally 
     { 
      unitOfWork.Dispose(); 
     } 
    } 
} 

Cuối cùng tôi đã xác định vòng đời cho UOW: (. Đối với chu kỳ sống và lớp bối cảnh tôi nhìn vào mã nguồn StructureMap để có được những ý tưởng)

For<IUnitOfWork>().LifecycleIs(new HybridHttpQuartzLifecycle()).Use<UnitOfWork>(); 

Xin hãy chia sẻ ý tưởng, nhận xét và đề xuất của bạn:>

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