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.WhereSelectEnumerableIterator
2.MoveNext() at System.Linq.Enumerable.WhereSelectEnumerableIterator
2.MoveNext() at System.Collections.Generic.List1..ctor(IEnumerable
1 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?
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.
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();
}
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With