TryUpdateModel 在 ASP.NET MVC 3 单元测试中抛出 NullReferenceException

发布于 2024-10-02 01:59:21 字数 1152 浏览 3 评论 0原文

由于我从 MVC 2 升级到 MVC 3 RC,因此使用 TryUpdateModel 会导致 NullReferenceException。仅当将我的操作方法作为单元测试的一部分运行时,才会出现此问题。在实际服务器上运行它可以按预期工作。

这是异常的堆栈跟踪:

System.NullReferenceException:对象 未设置对实例的引用 目的。在 System.Web.Mvc.JsonValueProviderFactory.GetValueProvider(ControllerContext 控制器上下文)在 System.Web.Mvc.ValueProviderFactoryCollection.<>c_DisplayClassc.b_7(ValueProviderFactory 工厂)在 System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() 在 System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() 在 System.Collections.Generic.List1..ctor(IEnumerable1 集合)在 System.Linq.Enumerable.ToList[TSource](IEnumerable`1 来源)在 System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext 控制器上下文)在 System.Web.Mvc.Controller.TryUpdateModel[TModel](TModel 型号,字符串前缀)
...我自己的代码从这里开始...

万一重要的话,我的控制器具有以下签名:

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

我的猜测是这与 MVC3 中 DI 工作的新方式有关,但我不知道是什么我做错了。也许 MVC 3 中需要 DI 设置,但 MVC 2 中不需要?

Since I upgraded from MVC 2 to MVC 3 RC, using TryUpdateModel causes a NullReferenceException. This problem only occurs when running my action method as part of a unit test. Running it on the actual server works as expected.

Here's a stack trace of the exception:

System.NullReferenceException: Object
reference not set to an instance of an
object. at
System.Web.Mvc.JsonValueProviderFactory.GetValueProvider(ControllerContext
controllerContext) at
System.Web.Mvc.ValueProviderFactoryCollection.<>c_DisplayClassc.b_7(ValueProviderFactory
factory) at
System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext()
at
System.Linq.Enumerable.WhereSelectEnumerableIterator
2.MoveNext()
at
System.Collections.Generic.List1..ctor(IEnumerable1
collection) at
System.Linq.Enumerable.ToList[TSource](IEnumerable`1
source) at
System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext
controllerContext) at
System.Web.Mvc.Controller.TryUpdateModel[TModel](TModel
model, String prefix)
... my own code from here on....

In case it matters, my controller has the following signature:

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

My guess is that this has to do with the new way DI works in MVC3, but I can't figure out what I'm doing wrong. Perhaps there is something in terms of DI setup that is required in MVC 3, but wasn't required in MVC 2?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

放手` 2024-10-09 01:59:21

您应该添加此代码:

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

我有同样的问题,此代码对我有帮助。

You should add this code:

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

I have the same problem and this code helps me.

回忆躺在深渊里 2024-10-09 01:59:21

如果其他人有同样的问题并找到这篇文章:

我根据 Ivan Kortym 的答案一般性地解决了问题(谢谢!),在我的控制器基类构造函数中使用以下代码:

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

In case someone else has the same problem and finds this post:

I solved the problem generically based on Ivan Kortym's answer (thanks!), with the following piece of code in my controller base class constructor:

if (Request!=null && Request.Form != null && Request.Form.HasKeys() && ValueProvider == null)
{
    ValueProvider = new FormCollection(Request.Form).ToValueProvider();
}
锦爱 2024-10-09 01:59:21

这可能是 System.Web.Mvc.JsonValueProviderFactory.GetValueProvider 的实现发生了变化,导致 ControllerContext 中的值为 null。

您可能需要在 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 属性。这又会使用当前控制器 ControllerContext 属性调用 ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext)

您应该能够创建一个新的 ControllerContext 实例并相应地设置控制器的属性...

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

    controller.ControllerContext = controllerContext;

    controller.Edit(...);       
}

不过,可能需要一些额外的模拟才能使其完全发挥作用。有关如何完全模拟 ControllerContext 的一些信息:模拟 Asp.net-mvc 控制器上下文

It's probably a change in implementation of System.Web.Mvc.JsonValueProviderFactory.GetValueProvider that is hitting a value in ControllerContext that is null.

You may need to mock an additional value in ControllerContext.

At least that's where I'd look first.

EDIT

Yeah, looks like it's doing a null check on 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);
}

From the stacktrace we can see that TryUpdateModel[TModel](TModel model, String prefix). Using reflector, it is accessing the ControllerBase ValueProvider property. This in turn calls ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext) with the current Controllers ControllerContext property.

You should just be able to create a new ControllerContext instance and set the controller's property accordingly...

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

    controller.ControllerContext = controllerContext;

    controller.Edit(...);       
}

Some additional mocking may be required to get it to fully function though. Some info on how to fully mock ControllerContext: Mocking Asp.net-mvc Controller Context

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文