8

Da quando ho eseguito l'aggiornamento da MVC 2 a MVC 3 RC, l'utilizzo di TryUpdateModel causa una eccezione NullReferenceException. Questo problema si verifica solo quando si esegue il mio metodo di azione come parte di un test unitario. L'esecuzione sul server effettivo funziona come previsto.TryUpdateModel genera NullReferenceException nel test di unità ASP.NET MVC 3

Ecco una traccia dello stack di eccezione:

System.NullReferenceException: Oggetto riferimento non impostato a un'istanza di un oggetto . a System.Web.Mvc.JsonValueProviderFactory.GetValueProvider (ControllerContext controllerContext) a System.Web.Mvc.ValueProviderFactoryCollection. <> c_ DisplayClassc.b _7 (ValueProviderFactory fabbrica) a System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext() at System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext() a System.Collections.Generic.List raccolta) a System.Linq. Enumerable.ToList [TSource] (IEnumerable`1 fonte) System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider (ControllerContext controllerContext) a System.Web.Mvc.Controller.TryUpdateModel [tModel] (tModel modello, prefix String)
... il mio codice f rom qui ....

Nel caso in cui è importante, il mio controller ha la seguente firma:

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

La mia ipotesi è che questo ha a che fare con il nuovo modo DI lavora in MVC3, ma Non riesco a capire cosa sto sbagliando. Forse c'è qualcosa in termini di configurazione DI richiesta in MVC 3, ma non era richiesta in MVC 2?

risposta

2

Nel caso in cui qualcun altro ha lo stesso problema e trova questo post:

ho risolto il problema genericamente in base alla risposta di Ivan Kortym, con il seguente pezzo di codice nel mio controller costruttore della classe base (grazie!):

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

Questa non è una buona idea, perché stai aggiungendo il codice per facilitare i test nel codice di produzione. Viene eseguito anche su ogni richiesta ed è completamente inutile. –

+3

Perché non usare semplicemente la riga "ValueProvider = ..." nella configurazione del controller nei test delle unità. – JoelFan

1

È probabilmente un cambiamento nell'implementazione di System.Web.Mvc.JsonValueProviderFactory.GetValueProvider che sta colpendo un valore in ControllerContext che è nullo.

Potrebbe essere necessario prendere in prestito un valore aggiuntivo in ControllerContext.

Almeno questo è il posto dove guarderei prima.

EDIT

Sì, sembra che stia facendo un controllo su nulla 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); 
} 

Dalla stacktrace possiamo vedere che TryUpdateModel[TModel](TModel model, String prefix). Utilizzando riflettore, si accede alla proprietà ControllerBaseValueProvider. Ciò a sua volta chiama ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext) con la proprietà corrente Controller ControllerContext.

Si dovrebbe solo essere in grado di creare una nuova ControllerContext istanza e impostare la proprietà del controller di conseguenza ...

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

    controller.ControllerContext = controllerContext; 

    controller.Edit(...);  
} 

Alcuni beffardo aggiuntivo può essere richiesto per farlo funzionare pienamente però.Alcune informazioni su ControllerContext come completamente falsa: Mocking Asp.net-mvc Controller Context

+0

Immagino quasi tanto, ma quale valore esattamente ho bisogno di prendere in giro? E come posso fare questo? Questo sembra essere uno scenario piuttosto comune ... –

+0

Uno scenario comune per il nuovo codice non è comune. ;) Perché non includi i tuoi finti mazzi e quindi potremmo indicare le probabili aggiunte. Stai prendendo in giro l'intestazione? – jfar

+0

Sì, non sembra che la sorgente MVC3 sia ancora disponibile ... potrebbe rendere le cose un po 'più impegnative. Caricherò Reflector e vedrò cosa riesco a trovare. – bmancini

15

Si dovrebbe aggiungere questo codice:

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

Ho lo stesso problema e questo codice mi aiuta.