2010-09-24 17 views
12

Tôi có một lớp tĩnh với một tài sản get tĩnh, và trong khách sạn này, tôi làm điều này:C#: Thêm ngữ cảnh để Parallel.ForEach() trong ASP.NET

// property body 
{ 
    // HttpContext.Current is NOT null 
    ... 

    Parallel.ForEach(files, file => 
    { 
     // HttpContext.Current is null 
     var promo = new Promotion(); 
     ... 
    }); 
    ... 

    // HttpContext.Current is NOT null 
} 

lớp tĩnh này không đã khởi tạo kiểu cho đến khi chế độ xem sử dụng thuộc tính này.

Vấn đề là Promotion của hàm tạo tĩnh, được khởi tạo lần đầu tiên new Promotion() được tạo trong phạm vi Parallel.ForEach(), sử dụng HttpContext.Current. Khi promo được khởi tạo trong phạm vi của Parallel.ForEach(), HttpContext.Current này là nullnew Promotion() do đó gây ra ngoại lệ.

HttpContext.Current không phải là rỗng trong thuộc tính tĩnh nhận bởi vì nó không được gọi cho đến khi chế độ xem sử dụng nó (và do đó có một HttpContext.Current).

Nếu Promotion sử dụng HttpContext.Current trong trường hợp của mình thay vì các thành viên tĩnh của nó, tôi có thể có lẽ chỉ cần vượt qua HttpContext.Current vào new Promotion() constructor:

var context = HttpContext.Current; 
Parallel.ForEach(files, file => 
{ 
    var promo = new Promotion(context); 
}); 

Nhưng kể từ static thành viên Xúc tiến cần HttpContext.Current, tôi không thể . Tôi có thể thiết kế lại lớp Promotion để thay đổi các thành viên tĩnh cần nó là thành viên cá thể, nhưng chúng tĩnh vì lý do - sẽ có một hình phạt hiệu suất lớn nếu tất cả các thành viên tĩnh phải được xác định thay vào mỗi mỗi lần một số new Promotion được khởi tạo.

Giải pháp có thể có cho điều này là gì? Tôi đã không nhận ra HttpContext.Current sẽ là không trong phạm vi Parallel.ForEach().

+0

thành viên tĩnh của khuyến mãi sẽ được khởi tạo chỉ một lần, khi mã của lớp được chạm lần đầu tiên .... Làm thế nào chúng có thể phụ thuộc vào 'HttpContext.Current'? –

+0

Mã nguồn cho 'Khuyến mãi' dưới sự kiểm soát của bạn? –

Trả lời

11

HttpContext.Current is null vì nó đang chạy trong "chủ đề không phải web". Nếu bạn chia nhỏ một số mã bằng cách sử dụng new Thread(...), nó sẽ giống hệt nhau. TPL phần nào che giấu điều này, nhưng bạn vẫn cần phải nhận ra rằng mỗi lần lặp trong Parallel.ForEach của bạn có khả năng chạy trong một luồng khác và xử lý nó cho phù hợp.

Cụ thể, nếu bạn muốn sử dụng một số lớp hoặc phương pháp ngoài yêu cầu web (và Parallel.ForEach là cách sử dụng như vậy), bạn không thể sử dụng HttpContext.Current. Một cách giải quyết khác là truyền đạt một cách rõ ràng HttpContext (hoặc HttpContextBase để cải thiện khả năng kiểm thử) trong hàm khởi tạo (hoặc như một tham số phương thức)

Tóm lại: bạn cần thoát khỏi sử dụng HttpContext.Current tĩnh.

0

Như Mauricio chỉ ra, HttpContext.Current phụ thuộc vào chuỗi đang thực hiện. Nó làm tôi ngạc nhiên khi một nhà xây dựng tĩnh tĩnh phụ thuộc vào giá trị vốn có tức thời như HttpContext.Current, nhưng có lẽ đó không phải là ý tưởng của bạn.

Nếu bạn có thể thay đổi lớp Promotion, đó sẽ là tùy chọn đầu tiên tôi cân nhắc.

Nếu không, bạn cần bằng cách nào đó để buộc khởi tạo loại cho Promotion tại thời điểm HttpContext.Current vẫn hợp lệ. Để tìm hiểu xem khởi tạo kiểu lực nào đọc this Jon Skeet blog post.

Một tùy chọn có thể là tạo đối tượng giả Promotion, (chỉ một lần trong toàn bộ chương trình là đủ). Nếu đó không phải là một lựa chọn, bạn có thể thử bằng cách đọc thuộc tính với sự phản chiếu. Tôi không biết liệu lực lượng đó có khởi tạo được không, nhưng tôi đoán vậy.

4

Chỉ cần chuyển bất kỳ ngữ cảnh nào bạn có từ bên ngoài cuộc gọi Parallel.ForEach xuống bất kỳ chức năng nào bạn gọi bên trong dựa vào bối cảnh đã nói.

var context = HttpContext.Current; 
Parallel.ForEach(items, item => 
    { 
     DoSomething(item, context); 
    } 
); 



private static void DoSomething(item, context = null) { 
    if (context == null) context = HttpContext.Current; 

    ... 
} 

Tôi muốn có dự phòng về giá trị rỗng vì vậy tôi không phải lo lắng về việc luôn đi xung quanh ngữ cảnh. Tôi chỉ nhớ rằng các chức năng của tôi cần ngữ cảnh khi gọi từ một chủ đề khác, và sau đó tôi tát em bé đó ngay trong đó.

0

Nó không hoạt động, bởi vì bên trong foreach, một chủ đề mới được tạo ra, vì vậy ngữ cảnh là rỗng. Ngay cả việc tạo ra một phương thức DoSomething để thiết lập bối cảnh curren, ngữ cảnh vẫn là null.

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