2009-07-15 58 views
31

Tôi đang sử dụng lớp ApplicationContext của riêng mình sử dụng mẫu đơn. Tôi muốn lưu trữ cá thể của nó trong HttpContext.Items, vì nó có thể truy cập được trong tất cả các phần của yêu cầu. Tôi đã đọc về cách sử dụng HttpContext với ASP.NET MVC và một trong những nỗi đau lớn là nó giới thiệu độ phức tạp thử nghiệm. Tôi đã thử làm nghiên cứu về testability của HttpContext.Items, nhưng tất cả những gì tôi có thể tìm thấy là các công cụ trên Session. Một trong những điều duy nhất tôi đã tìm thấy là trong một chương mẫu trong cuốn sách chuyên nghiệp ASP.NET 3.5 MVC trên Wrox (pdf link here). Trên trang 15 nó nói này:HttpContext.Items với ASP.NET MVC

Something Bạn không thể sử dụng: HttpContext.Items
Trên trong phần này, chúng tôi đã sạch và nói với bạn rằng chúng tôi đã nói dối với bạn: HttpContext không được chia sẻ giữa ASP .NET MVC và ASP.NET Web Forms. Kết quả là, bạn không thể sử dụng bộ sưu tập HttpContext.Items để lưu trữ và truy xuất các bit dữ liệu.

Lý do cho điều này là vì một khi bạn chuyển hướng đến một Controller, HttpHandler của bạn sẽ trở thành System.Web.Mvc.MvcHandler, được tạo ra bằng cách sử dụng HttpContextWrapper, sẽ có định nghĩa riêng của HttpContext.Current. Thật không may, trong quá trình bắt tay này, những thứ như HttpContext.Items không được chuyển.

Điều này tóm tắt là các loại HttpContext, mặc dù tìm kiếm và nghe rất giống nhau, không giống nhau, và bạn không thể truyền dữ liệu theo cách này.

Bây giờ, tôi đã thử kiểm tra điều này, và theo như tôi có thể nói, nếu bạn chuyển hướng đến bộ điều khiển khác bằng cách sử dụng RedirectToAction, HttpContext.Items vẫn còn. Tôi đang sử dụng dự án ASP.NET MVC mặc định để kiểm tra điều này. Những gì tôi đã làm là, thêm phương pháp này để Global.asax.cs:

protected void Application_BeginRequest() 
{ 
    Context.Items["Test"] = "Hello World"; 
} 

Và trong HomeController.cs, tôi đã thay đổi phương pháp Chỉ số:

public ActionResult Index() 
{ 
    return RedirectToAction("About"); 
} 

Và thay đổi Về phương pháp để:

public ActionResult About() 
{ 
    Response.Write(Convert.ToString(HttpContext.Items["Test"])); 
    return View(); 
} 

Khi tôi chạy các ứng dụng, trang đúng cách chuyển hướng đến/Home/Giới và Response.Writes chuỗi đúng "Hello World" thiết lập trong global.asax.cs. Vì vậy, có vẻ như với tôi như thể tôi hoặc là không hiểu những gì cuốn sách có ý nghĩa khi họ nói "những thứ như HttpContext.Items không được chuyển giao" HOẶC nó chuyển giao công cụ này và nó okay để sử dụng HttpContext. Mặt hàng.

Nếu bạn đề nghị tôi tránh HttpContext.Items, có cách nào khác để lưu trữ một đối tượng trên một yêu cầu trên cơ sở theo yêu cầu không?

+0

Đây là một nguồn lực khá hữu ích cho việc tạo ra một "bối cảnh ứng dụng" loại đối tượng: http://jcapka.blogspot.co.uk/2013/11/creating-application-context-for-net.html – JDandChips

Trả lời

35

Câu hỏi của bạn đang hỏi một vài điều nhưng tôi nghĩ mục số 1 là câu trả lời bạn đang tìm kiếm.

  1. Bạn có sử dụng Context.Items để lưu vào bộ nhớ cache theo yêu cầu không? Có. Nếu trong quá trình, mỗi yêu cầu, mỗi máy trong trang trại web là tiêu chí của bạn thì Context.Items cho bạn điều đó.

  2. Có phải thử thách Context.Items không? Theo như kiểm tra, tôi sẽ ẩn Context.Items phía sau giao diện của một số loại. Bằng cách này, bạn sẽ có được khả năng kiểm tra đơn vị mà không cần phải tham khảo trực tiếp Context.Items. Nếu không, bạn cần kiểm tra gì về Context.Items? Rằng khuôn khổ sẽ lưu trữ và lấy các giá trị? Giữ mã của bạn không biết gì về System.Web và bạn sẽ là người cắm trại hạnh phúc.

  3. Sẽ Context.Items tồn tại RedirectToAction? Không. Bài kiểm tra của bạn không hợp lệ. Cài đặt "Xin chào, thế giới" trên mọi yêu cầu web và thử nghiệm của bạn kéo dài hai yêu cầu web. Đầu tiên là khi hành động Index được gọi. Thứ hai là khi hành động RedirectToAction được gọi (đó là HTTP 302). Để làm cho nó thất bại, thiết lập một giá trị mới trong hành động Index và xem nó có được giữ lại trong hành động About hay không.

+0

Bingo! Bạn đúng rồi. Tất nhiên tôi đã không nhận ra nó, bởi vì tôi đã thiết lập mục ngữ cảnh trong BeginRequest, được chạy hai lần, một lần khi Index được gọi và sau đó một lần nữa sau khi Index chuyển hướng đến About. Tôi cho rằng mặc dù điều đó cho kịch bản của tôi (làm một singleton mà instance được lưu trữ trong Request.Items), tôi sẽ ổn với hành vi đó, vì đối tượng sẽ chỉ được xây dựng lại khi tôi chuyển hướng. Cảm ơn một lần nữa cho câu trả lời của bạn! –

+0

Ryan - "làm cho một singleton mà dụ được lưu trữ trong Request.Items," bạn có thể vui lòng xây dựng với mã mẫu làm thế nào bạn làm điều đó? – Picflight

+0

* "Tôi sẽ ẩn Context.Items đằng sau một giao diện của một số loại" * hoặc bạn có thể sử dụng [HttpContextBase] (https://msdn.microsoft.com/en-us/library/system.web.httpcontextbase (v = vs.110) .aspx) hoặc [HttpContextWrapper] (https://msdn.microsoft.com/en-us/library/system.web.httpcontextwrapper (v = vs.110).aspx) các lớp học, cả hai đều (trừu tượng) đều có thể nhạo báng được. – Liam

3

Sử dụng từ điển TempData, nó là chủ yếu để lưu trữ các đối tượng giữa Actions chuyển hướng:

public ActionResult Index() 
{ 
    TempData.Add("Test", "Hello world"); 
    return RedirectToAction("About"); 
} 

public ActionResult About() 
{ 
    ViewData["Test"] = TempData["Test"]; 
    return View(); 
} 

Sau đó lấy giá trị theo quan điểm của bạn:

<%=ViewData["Test"] %> 
+3

Cảm ơn câu trả lời, nhưng tôi không muốn sử dụng Session state. Điều này là do ứng dụng của tôi có thể chạy dưới một trang trại, và hiệu suất của trạng thái phiên không tốt khi hết quá trình. (TempData lưu trữ giá trị của nó trong SessionState) –

1

tôi đã làm một thử nghiệm và TempData không, quả thật vậy , phát nổ với trạng thái phiên bị tắt. Lời khuyên duy nhất của tôi là không lưu trữ chính đối tượng đó trong dữ liệu tạm thời nhưng lưu trữ các trường được nhập đơn giản như đã được đề xuất. Vì bạn không serializing cây đối tượng nên nó không phải là lớn của một tác động hiệu suất chạy ra khỏi quá trình.

+1

Nó thực sự * là * một tác động hiệu suất. Nếu bạn chạy một trang trại, bạn cần chia sẻ phiên trên toàn bộ trang trại (bởi vì trên một yêu cầu bạn có thể nhấn máy chủ A, và sau đó trong yêu cầu * tiếp theo * bạn có thể được chuyển đến máy chủ B). Điều này thường được thực hiện bằng cách sử dụng nhà cung cấp phiên SQL Server mà là hoàn toàn chậm và crappy so với trong quá trình. Nó rất chậm và crappy mà tất cả mọi người nên tránh nó với một cực 10 chân. Hoặc lâu hơn nếu bạn đã có một cái gì đó tiện dụng;). –

+0

Cũng vậy, việc lưu trữ đối tượng ngay cả trong TempData cũng sẽ đưa nó qua các yêu cầu. Tôi không muốn điều đó. Tôi chỉ muốn lưu trữ nó cho yêu cầu hiện tại. –

+0

FYI: Có thể tắt hoàn toàn TempData bằng cách viết một nhà cung cấp dữ liệu tùy chỉnh tạm thời không làm gì cả. Đó là nhà cung cấp mặc định thổi lên khi trạng thái phiên bị vô hiệu hóa trong thực tế chỉ là một lỗi trong ASP.NET MVC 1.0 và chúng tôi đã sửa nó cho bản phát hành tiếp theo của ASP.NET MVC! – Eilon