2009-05-18 36 views
16

Hiện tại tôi có một ActionFilter lấy tên người dùng hiện tại từ HttpContext và chuyển nó vào hành động sử dụng nó trên một phương thức dịch vụ. ví dụ:ASP.NET MVC: HTTPContext và Dependency Injection

Service.DoSomething(userName); 

Bây giờ tôi có lý do để làm điều này không phải ở cấp hành động mà là cấp độ bộ điều khiển bộ điều khiển. Hiện tại tôi đang sử dụng bản đồ cấu trúc để tạo bộ điều khiển và tiêm dịch vụ. Tôi đang xem một cái gì đó như:

public interface IUserProvider 
{ 
    string UserName { get; } 
} 

public class HttpContextUserProvider : IUserProvider 
{ 
    private HttpContext context; 

    public HttpContextUserProvider(HttpContext context) 
    { 
     this.context = context; 
    } 

    public string UserName 
    { 
     get 
     { 
      return context.User.Identity.Name; 
     } 
    } 
} 

Điều đó nói rằng, IoC foo của tôi thực sự yếu vì đây là dự án đầu tiên tôi đã sử dụng.

Vì vậy, câu hỏi của tôi là ... làm thế nào tôi có thể nói cho bản đồ cấu trúc để vượt qua trong HttpContext trong constructor cho HttpContextUserProvider? Điều này có vẻ lạ ... Tôi không chắc làm thế nào để nghĩ về HttpContext.

Trả lời

8

Có một giao diện trừu tượng HttpContext.Current. Chỉ trưng ra các phương thức bạn cần GetUserName() sẽ gọi HttpContext.Current.User.Identity.Name trong thực hiện, ví dụ. Hãy chắc rằng như mỏng càng tốt.

Hãy trừu tượng đó và tiêm nó vào lớp nhà cung cấp khác của bạn. Điều này sẽ cho phép bạn kiểm tra các nhà cung cấp bằng cách chế giễu http bối cảnh trừu tượng. Là một lợi ích phụ, bạn có thể làm những điều tiện lợi khác với HttpContext trừu tượng bên cạnh việc giả lập nó. Tái sử dụng nó, cho một điều. Thêm thông số loại chung cho túi xách, v.v.

+0

Ý của bạn là gì, "Thêm các tham số kiểu chung cho túi"? Âm thanh hấp dẫn. –

+4

cung cấp các trình bao bọc mạnh mẽ trong phiên –

+3

bạn có bất kỳ mã mẫu/liên kết nào không, điều này có vẻ thú vị. Tôi không hiểu điều này đúng cách, bất kỳ trợ giúp/lời khuyên nào sẽ được đánh giá cao ... – Haroon

2

Có lẽ tôi lại một cái gì đó, nhưng câu trả lời ở trên không làm việc cho tôi (từ đó đã được xóa - nó vẫn còn là một câu trả lời hữu ích mặc dù - nó đã cho thấy làm thế nào để nói với SM để vượt qua đối số nhà xây dựng). Thay vào đó, nếu tôi làm:

ObjectFactory.Initialize(x => 
{ 
    x.BuildInstancesOf<HttpContext>() 
     .TheDefault.Is.ConstructedBy(() => HttpContext.Current); 
    x.ForRequestedType<IUserProvider>() 
     .TheDefault.Is.OfConcreteType<HttpContextUserProvider>(); 
}); 

Tôi làm cho nó hoạt động. Tôi đã làm điều này sau khi tìm thấy: http://codebetter.com/blogs/jeremy.miller/archive/2008/03/20/if-you-need-something-in-structuremap-but-you-can-t-build-it-with-new.aspx


chỉnh sửa:

Nhờ câu trả lời của Brad Tôi nghĩ Tôi có một xử lý tốt hơn trên HttpContext. Câu trả lời của ông chắc chắn công trình, tôi chỉ không chắc chắn tôi thích có cuộc gọi đến HttpContext.Current bên trong một lớp (nó có vẻ như nó ẩn phụ thuộc, nhưng tôi xa một chuyên gia về công cụ này).

Mã trên sẽ hoạt động để tiêm HttpContext theo như tôi có thể biết. Matt Hinze sẽ trả thêm điểm rằng nếu tất cả những gì cần từ HttpContext là User.Identity.Name, thiết kế của tôi nên rõ ràng về điều đó (có một giao diện xung quanh HttpContext chỉ phơi bày những gì tôi cần). Tôi nghĩ rằng đây là một ý tưởng tốt.

Điều này là qua bữa ăn trưa Tôi kinda nhận ra dịch vụ của tôi thực sự chỉ cần phụ thuộc vào một chuỗi: userName. Có nó phụ thuộc vào IUserProvider có thể không có nhiều giá trị gia tăng. Vì vậy, tôi biết tôi không muốn nó phải phụ thuộc vào HttpContext, và tôi biết tất cả tôi cần là một chuỗi (userName) - Tôi cần phải xem liệu tôi có thể học đủ StructureMap foo có làm cho kết nối này cho tôi. (Câu trả lời của sirrocoo đưa ra gợi ý về nơi bắt đầu nhưng anh ta đã xóa nó: *().

+0

Trong thuật ngữ bố cục khi một hàm tạo có phụ thuộc của HttpContext IoC sẽ truyền trong thể hiện của HttpContext.Current. Và khi một hàm tạo có một sự phụ thuộc của IUserProvider, IoC sẽ khởi tạo một thể hiện mới của HttpContextUserProvider và truyền nó vào trong hàm tạo. –

+0

Giao diện StructureMap đọc tốt. Sự nhầm lẫn của tôi là tôi nghĩ rằng trong hai phần: 1) Tôi đã từng sử dụng ForRequestedType - làm thế nào để tôi biết khi nào để phá vỡ BuildInstancesOf thay vào đó (tôi có thể chỉ cần google này - câu hỏi dễ dàng) 2) Tôi có thể chỉ cho phép StructureMap biết làm thế nào để có được HttpContext.Current? Tôi đoán HttpContext gây nhầm lẫn cho tôi một chút ở chỗ nó chỉ dường như kỳ diệu trôi nổi ở khắp mọi nơi. Tôi không thể nghĩ ra một nguồn duy nhất tôi có thể đi đến để có được nó, nơi mà mọi thứ khác có một nguồn rõ ràng hơn. – anonymous

+0

thực sự giải pháp của tôi đã không hoạt động - và với một lỗi hardcore thậm chí, ngoại lệ bên trong nói điều gì đó về một giới hạn JIT ... wow – sirrocco

3

Tôi không chắc tại sao bạn lại bận tâm. Bạn sẽ không bao giờ thay thế bằng một HttpContext khác ...

+0

Yah ... Tôi không nghĩ rằng tôi * nhận * HttpContext. Tôi đoán tôi đang sử dụng để có một cái gì đó thông qua trong xây dựng thông qua nơi HttpContext xuất hiện để chỉ trên toàn cầu được ở đó? – anonymous

+0

Ok, đã trả về HttpContext.Current.User.Identity.Name; Và nó hoạt động. Tôi đoán tôi kinda chậm trên sự hấp thu ở đây nhưng hiện tại một tài sản tĩnh trên HttpContext có trách nhiệm biết làm thế nào để tìm HttpContext hiện tại. Nhược điểm duy nhất là bạn có thể không (tôi không nghĩ ít nhất) được rõ ràng về tùy thuộc vào HttpContext thông qua constructor tiêm vì bạn không thể vượt qua trong một tài sản tĩnh hoặc loại? Bạn có thể làm cho một số wrapper như IHttpContextProvider mà chỉ trả về HttpContext.Current và sau đó bạn muốn biết một cái gì đó phụ thuộc vào HttpContext? Hay là ngu ngốc. – anonymous

+0

Bạn sẽ tiêm HttpContext như thế nào trong một lớp dịch vụ không tham chiếu đến web, có lẽ chúng ta có thể nói đây là trường hợp sử dụng cho điều đó, nơi các bản ghi/tập dữ liệu phụ thuộc vào người dùng hiện tại? (asp.net mvc2) ... – Haroon

9

Có vẻ như bạn nên sử dụng HttpContextBase thay vì HttpContextUserProvider.Đây là một sự trừu tượng vượt trội của HttpContext và cho phép bạn tạo một mô hình, viết UnitTests và tiêm phụ thuộc của bạn.

public class SomethingWithDependenciesOnContext 
{ 
    public SomethingWithDependenciesOnContext(HttpContextBase context) { 
     ... 
    } 

    public string UserName 
    { 
     get {return context.User.Identity.Name;} 
    } 
} 

ObjectFactory.Initialize(x => 
      x.For<HttpContextBase>() 
      .HybridHttpOrThreadLocalScoped() 
      .Use(() => new HttpContextWrapper(HttpContext.Current)); 
Các vấn đề liên quan