8

Tôi đang sử dụng ASP.NET MVC 5 và Identity Framework. Khi tôi gọi UserManager.UpdateAsync (...) của tôi eventhandlers trên ApplicationDbContext() SaveChanges sẽ chạy. Ở đây tôi đang sử dụng HttpContext.Current cho các mục đích khác nhau (đăng nhập và kiểm toán) vì vậy tôi phải nói người dùng hiện tại. Tuy nhiên, toàn bộ phương thức chạy trong một luồng công nhân, và ở đây HttpContext.Current là null.HttpContext.Current is null bên trong các phương thức của Identity Framework

Vấn đề lớn nhất là các phương thức "đồng bộ hóa" của UserManager chỉ bao quanh các phiên bản async, vì vậy các cuộc gọi được tuần tự hóa, nhưng các phương thức (và eventhandlers) vẫn chạy trong một chuỗi công nhân khác.

Xin lưu ý rằng vấn đề này không liên quan gì đến bối cảnh không đồng bộ/chờ đợi. Trong bộ điều khiển sau khi chờ đợi (hoặc gọi phiên bản 'đồng bộ') Tôi đã quay lại đúng HttpContext, ngay cả khi phương thức của bộ điều khiển đang tiếp tục trong một chủ đề khác. Đó là tốt.

Vì vậy, sự cố bên trong công nhân không đồng bộ sẽ chạy trong cả hai phiên bản "đồng bộ hóa" và không đồng bộ. Tôi nghĩ rằng tôi hiểu các hiện tượng (nhưng tôi không hài lòng với các phiên bản phương pháp 'đồng bộ' giả, phương thức đồng bộ hóa thực sự sẽ không thể hiện vấn đề này.) Tôi không biết cách giải quyết/giải quyết nó.

[btw: Sẽ không tự nhiên hơn khi triển khai các toán hạng của UserManager như các phiên bản đồng bộ thuần túy đơn giản, sau đó bọc chúng bằng các trình bao bọc đa luồng không đồng bộ ?. NẾU chúng ta tiếp tục thời trang không đồng bộ này mà không nghĩ chúng ta sẽ sớm phát minh ra toán tử gán async. Chi phí cho tôi hàng chục giờ (chỉ vấn đề này), và chi phí trên toàn thế giới zillion đô la, tôi chắc chắn trong nhiều trường hợp ít hơn giá của nó.]

Tiền thưởng: Chúng tôi đang nói về UserManager tác động khá biên, nhưng giống nhau nguyên tắc và vấn đề có thể áp dụng bất kỳ thư viện nào trong hộp thư (hộp đen cho bạn) mà tác giả không triển khai phiên bản đồng bộ hóa hoặc không quan tâm đến ngữ cảnh của trình điều khiển. Điều gì về EF, nó không phải là quá biên ... và những gì về DI container cơ sở hạ tầng instantiation như "phạm vi yêu cầu" hoặc "phạm vi phiên". Chắc chắn là chúng hoạt động sai nếu việc giải quyết xảy ra trong một luồng không có HttpContext.Current. Gần đây tôi đã làm mới SendGrid NuGet, và (như là một thay đổi phá vỡ) Deliver() phương pháp đi, và bây giờ chỉ DeliverAsync() là hiện tại ...

Tôi muốn có một cách đáng tin cậy an toàn, làm thế nào tôi có thể truy cập HttpContext bên trong công nhân này cho mục đích khai thác gỗ và kiểm toán.

Mẫu mã, bộ điều khiển 'đồng bộ' phiên bản:

[AcceptVerbs(HttpVerbs.Post)] 
public virtual ActionResult Edit(ApplicationUser user) 
{ 
    // validation etc 
    // Update() seems to be only a poor wrapper around the async version, still uses a worker thread. 
    var result = UserManager.Update(user); 
    // Note: HttpContext is correct here so it is not an async/await problem 

    // error handling, creating ActionResult etc. 
} 

Mẫu mã, phiên bản điều khiển async:

[AcceptVerbs(HttpVerbs.Post)] 
public virtual async Task<ActionResult> Edit(ApplicationUser user) 
{ 
    // validation etc 
    var result = await UserManager.UpdateAsync(user); 
    // Note: HttpContext is correct here so it is not an async/await problem 

    // error handling, creating ActionResult etc. 
} 

và xử lý sự kiện nơi HttpContext là null:

public ApplicationDbContext() : base("DefaultConnection", false) 
{ 
    InitializeAudit(); 
} 

private void InitializeAudit() 
{ 
    var octx = ((IObjectContextAdapter) this).ObjectContext; 

    octx.SavingChanges += 
     (sender, args) => 
     { 
      // HttpContext.Current is null here 
     }; 
} 

Bất kỳ ý tưởng nào?

+0

Cân nhắc hiển thị mã ... –

+0

Bạn có thể hiển thị mã cụ thể mà bạn đang yêu cầu không? – i3arnon

+1

Làm thế nào về việc lưu trữ 'HttpContext.Current' trong một biến cục bộ trước khi tạo bất kỳ nhiệm vụ nào và chuyển nó đến các nhiệm vụ/chủ đề bằng cách nào đó. – EZI

Trả lời

4

Như bạn đã nói, điều này xảy ra do luồng. Các đại biểu chạy trong một chủ đề khác nhau, làm cho HttpContext không thể tiếp cận.

Bạn có thể di chuyển biến bên ngoài của đại biểu, làm cho nó bị đóng.

private void InitializeAudit() 
{ 
    var octx = ((IObjectContextAdapter) this).ObjectContext; 
    HttpContext context = HttpContext.Current; 

    octx.SavingChanges += 
     (sender, args) => 
     { 
      // context is not null 
     }; 
} 
+1

Cảm ơn tôi đã nghĩ điều tương tự. Tuy nhiên nó vẫn không phải là tôi, người tạo ra cá thể ApplicationDbContext nó cũng là Identity Framework, do đó nó không đảm bảo được tạo ra trong luồng của controller, vì vậy trong constructor của nó là không cần thiết, chúng ta có HttpContext. –

1

Bạn đang sử dụng danh tính asp.net qua owin, nên một ví dụ của dbcontext được tạo ra theo yêu cầu, và bạn có thể nhận được thông tin này từ bất cứ nơi nào trong các đường ống theo yêu cầu.

nb. đây là tiện dụng nhưng tôi nghĩ rằng dbcontext không nên được truy cập bên ngoài người quản lý. Trong thiết kế nhận dạng asp.net, chỉ người quản lý mới biết về cửa hàng. Tôi tin rằng dbcontext được tiếp xúc bởi vì một số middleware nhận dạng asp.net có một sự phụ thuộc vào nó.

Tuy nhiên, nó có thể giúp giải quyết bạn vấn đề:

Cho phép tùy chỉnh của bạn dbcontext xử lý được thiết lập bên ngoài lớp:

public EventHandler SavingChangesEventHandler 
     { 
      set 
      { 
       (((System.Data.Entity.Infrastructure.IObjectContextAdapter)this).ObjectContext).SavingChanges += value; 
      } 
     } 

Khai báo một lớp tùy chỉnh ActionFilter và đăng ký nó, sau đó ghi đè OnActionExecuting:

Filtering trong ASP.NET MVC https://msdn.microsoft.com/en-us/library/gg416513(VS.98).aspx

public class CustomizeAppDbcontextFilter : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(HttpActionContext actionContext) 
    { 
     var dbcontext = HttpContext.GetOwinContext().Get<ApplicationDbContext>();  
     var currentuser = HttpContext.Current.User; 

     dbcontext.SavingChangesEventHandler = (sender, args) => 
      { 
       // use currentuser 
      }; 
    }  
} 

bạn có thể cần sử dụng các báo cáo này để có thể gọi là phương pháp khuyến nông identity.owin:

sử dụng Microsoft.AspNet.Identity;

sử dụng Microsoft.AspNet.Identity.Owin;

Bạn phải ở trong chuỗi bộ điều khiển vì OnActionExecuting đang gói hành động bộ điều khiển.

Tôi không thử nghiệm, vì vậy nó có thể cần một số đánh bóng nhưng khái niệm sẽ hoạt động.

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