8

由於我從MVC 2升級到MVC 3 RC,使用TryUpdateModel會導致NullReferenceException。只有在將我的操作方法作爲單元測試的一部分運行時,纔會出現此問題。在實際服務器上運行它按預期工作。TryUpdateModel在ASP.NET MVC 3單元測試中拋出NullReferenceException

這裏是異常的堆棧跟蹤:

System.NullReferenceException:對象 引用未設置爲一個 對象的實例。在 System.Web.Mvc.JsonValueProviderFactory.GetValueProvider(ControllerContext controllerContext)at System.Web.Mvc.ValueProviderFactoryCollection。 <> C_ DisplayClassc.b _7(ValueProviderFactory 工廠)在 System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext() at System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext() 在 System.Collections.Generic.List 集合)在 System.Linq的。 Enumerable.ToList [TSource](IEnumerable`1 源)在 System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(controllerContext controllerContext)在 System.Web.Mvc.Controller.TryUpdateModel [TModel的](TModel的 模型,字符串前綴)
...我自己的代碼f ROM這裏....

在如此重要的情況下,我的控制器具有以下特徵:

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

我的猜測是,這與新路子DI工作在MVC3做的,但我無法弄清楚我做錯了什麼。也許在MVC 3中需要DI設置,但在MVC 2中不需要?

回答

2

萬一別人有同樣的問題,發現這個帖子:

我解決了一般基於伊萬Kortym的回答這個問題,在我的控制器基類的構造函數下面的一段代碼(謝謝!):

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

這不是一個好主意,因爲您要添加代碼以便將測試轉換爲生產代碼。它也會在每個請求中執行,而這完全沒有必要。 – 2012-07-16 21:05:20

+3

爲什麼不在您的單元測試中使用「ValueProvider = ...」行來設置控制器。 – JoelFan 2012-11-28 21:06:22

1

這可能是System.Web.Mvc.JsonValueProviderFactory.GetValueProvider的實現中的一個變更,它的值爲ControllerContext,該值爲空。

您可能需要在ControllerContext中模擬附加值。

至少這是我首先看的地方。

編輯

是啊,看起來像它做對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); 
} 

從stacktrace中我們可以看到TryUpdateModel[TModel](TModel model, String prefix)。使用反射器時,它正在訪問ControllerBaseValueProvider屬性。這又會調用ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext)與當前的控制器ControllerContext屬性。

你應該只能夠相應地創建一個新的ControllerContext實例,並設置控制器的財產......

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

    controller.ControllerContext = controllerContext; 

    controller.Edit(...);  
} 

一些額外的嘲諷,可能需要得到它正常地工作,雖然。如何充分模擬ControllerContext的一些信息:Mocking Asp.net-mvc Controller Context

+0

我覺得幾乎一樣多,但我需要嘲笑哪些值呢?我該怎麼做?這似乎是一個相當常見的情況... – 2010-11-12 15:55:13

+0

全新代碼的常見情況並不常見。 ;)爲什麼你不包括你當前的模擬,然後我們可以指出可能的增加。你在嘲笑標題嗎? – jfar 2010-11-12 16:05:45

+0

是啊,看起來MVC3的源代碼看起來還不夠...可能會讓事情變得更具挑戰性。我將加載反射器,看看我能找到什麼。 – bmancini 2010-11-12 16:16:26

15

您應該添加以下代碼:

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

我有同樣的問題,這個代碼可以幫助我。

相關問題