8

Vì tôi đã nâng cấp từ MVC 2 lên MVC 3 RC, sử dụng TryUpdateModel gây ra một NullReferenceException. Vấn đề này chỉ xảy ra khi chạy phương pháp hành động của tôi như là một phần của một thử nghiệm đơn vị. Chạy nó trên máy chủ thực tế hoạt động như mong đợi.TryUpdateModel ném NullReferenceException trong ASP.NET MVC 3 đơn vị kiểm tra

Dưới đây là một chồng dấu vết của các ngoại lệ:

System.NullReferenceException: Object tài liệu tham khảo không được đặt để một thể hiện của một đối tượng . tại System.Web.Mvc.JsonValueProviderFactory.GetValueProvider (ControllerContext controllerContext) tại System.Web.Mvc.ValueProviderFactoryCollection. <> c_ DisplayClassc.b _7 (ValueProviderFactory nhà máy) tại System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext() at System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext() tại System.Collections.Generic.List bộ sưu tập) tại System.Linq. Enumerable.ToList [TSource] (IEnumerable`1 nguồn) tại System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider (controllerContext controllerContext) tại System.Web.Mvc.Controller.TryUpdateModel [TModel] (TModel mô hình, string prefix)
... mã của riêng tôi f rom ở đây trên ....

Trong trường hợp vấn đề, điều khiển của tôi có chữ ký sau đây:

[AcceptVerbs(HttpVerbs.Post)] 
public virtual ActionResult Edit(int id, FormCollection collection) 
{ 
} 

Tôi đoán là điều này đã làm với các phương pháp mới DI việc trong MVC3, nhưng Tôi không thể hiểu được tôi đang làm gì sai. Có lẽ có một cái gì đó về DI thiết lập đó là cần thiết trong MVC 3, nhưng không được yêu cầu trong MVC 2?

Trả lời

2

Trong trường hợp ai đó có cùng một vấn đề và tìm thấy bài đăng này:

tôi giải quyết vấn đề tổng quát dựa trên câu trả lời Ivan Kortym, với những đoạn mã sau đây trong điều khiển constructor lớp cơ sở của tôi (cảm ơn!):

if (Request!=null && Request.Form != null && Request.Form.HasKeys() && ValueProvider == null) 
{ 
    ValueProvider = new FormCollection(Request.Form).ToValueProvider(); 
} 
+2

Đây không phải là một ý tưởng hay, bởi vì bạn đang thêm mã để tạo điều kiện thử nghiệm vào mã sản xuất. Nó cũng được thực hiện trên mọi yêu cầu, và nó hoàn toàn không cần thiết. –

+3

Tại sao không chỉ sử dụng dòng "ValueProvider = ..." trong thiết lập bộ điều khiển của bạn trong các bài kiểm tra đơn vị của bạn. – JoelFan

1

Đó có thể là thay đổi trong việc triển khai System.Web.Mvc.JsonValueProviderFactory.GetValueProvider đang đạt giá trị trong ControllerContext không có giá trị.

Bạn có thể cần giả lập giá trị bổ sung trong ControllerContext.

Ít nhất đó là nơi tôi sẽ nhìn đầu tiên.

CHỈNH SỬA

Vâng, có vẻ như nó đang thực hiện kiểm tra trống controllerContext.

public override IValueProvider GetValueProvider(ControllerContext controllerContext) 
{ 
    if (controllerContext == null) 
    { 
     throw new ArgumentNullException("controllerContext"); 
    } 
    object deserializedObject = GetDeserializedObject(controllerContext); 
    if (deserializedObject == null) 
    { 
     return null; 
    } 
    Dictionary<string, object> backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); 
    AddToBackingStore(backingStore, string.Empty, deserializedObject); 
    return new DictionaryValueProvider<object>(backingStore, CultureInfo.CurrentCulture); 
} 

Từ stacktrace chúng ta có thể thấy rằng TryUpdateModel[TModel](TModel model, String prefix). Sử dụng phản xạ, nó đang truy cập vào thuộc tính ControllerBaseValueProvider. Điều này lần lượt gọi ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext) với bộ điều khiển hiện tại ControllerContext tài sản.

Bạn chỉ có thể tạo ra một ControllerContext dụ mới và thiết lập thuộc tính của bộ điều khiển phù hợp ...

[TestMethod] 
public void EditTest 
{ 
    var controller = new Controller();   
    var controllerContext = new ControllerContext(); 

    controller.ControllerContext = controllerContext; 

    controller.Edit(...);  
} 

Một số mocking bổ sung có thể được yêu cầu để làm cho nó hoạt động hoàn toàn mặc dù.Một số thông tin về ControllerContext làm thế nào để hoàn toàn giả: Mocking Asp.net-mvc Controller Context

+0

Tôi rất thích, nhưng giá trị chính xác nào tôi cần phải giả lập? Và làm thế nào tôi có thể làm điều này? Điều này có vẻ là một kịch bản khá phổ biến ... –

+0

Một kịch bản phổ biến cho mã mới hoàn toàn không phải là điều phổ biến. ;) Tại sao bạn không bao gồm mocks hiện tại của bạn và sau đó chúng tôi có thể chỉ ra bổ sung có khả năng. Bạn đang chế nhạo tiêu đề? – jfar

+0

Có vẻ như không có nguồn MVC3 nào ... có thể khiến mọi thứ trở nên khó khăn hơn. Tôi sẽ tải lên Reflector và xem những gì tôi có thể tìm thấy. – bmancini

15

Bạn nên thêm mã này:

FormCollection formValues = new FormCollection() 
     { 
      { "Test", "test" }, 
      { "FirstName", "TestName" } 
     }; 
     rootController.ValueProvider = formValues.ToValueProvider(); 

Tôi có cùng một vấn đề và mã này giúp tôi.