由于我从MVC 2升级到MVC 3 RC,因此使用TryUpdateModel会导致NullReferenceException。仅当将我的操作方法作为单元测试的一部分运行时,才会出现此问题。在实际服务器上运行它可以按预期工作。
这是异常的堆栈跟踪:
System.NullReferenceException:Object 引用未设置为的实例 宾语。在 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.List1..ctor(IEnumerable
1 收藏) System.Linq.Enumerable.ToList [TSource](IEnumerable`1 来源) System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext)at System.Web.Mvc.Controller.TryUpdateModel [TModel的](TModel的 model,String prefix)
......我自己的代码来自......
如果重要,我的控制器有以下签名:
[AcceptVerbs(HttpVerbs.Post)]
public virtual ActionResult Edit(int id, FormCollection collection)
{
}
我的猜测是,这与DI在MVC3中工作的新方式有关,但我无法弄清楚我做错了什么。也许在MVC 3中需要一些DI设置,但在MVC 2中不需要它?
答案 0 :(得分:15)
您应该添加以下代码:
FormCollection formValues = new FormCollection()
{
{ "Test", "test" },
{ "FirstName", "TestName" }
};
rootController.ValueProvider = formValues.ToValueProvider();
我有同样的问题,这段代码可以帮助我。
答案 1 :(得分:2)
如果其他人遇到同样的问题并发现此帖:
我根据Ivan Kortym的回答(谢谢!)解决了这个问题,在我的控制器基类构造函数中使用了以下代码:
if (Request!=null && Request.Form != null && Request.Form.HasKeys() && ValueProvider == null)
{
ValueProvider = new FormCollection(Request.Form).ToValueProvider();
}
答案 2 :(得分: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);
}
从堆栈跟踪中我们可以看到TryUpdateModel[TModel](TModel model, String prefix)
。使用反射器,它正在访问ControllerBase
ValueProvider
属性。这反过来使用当前的控制器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