Domanda

Ho un tipo in un assembly che non è referenziato dalla libreria principale ma viene fatto riferimento dall'applicazione Web. per esempio

namespace MyApp.Models {
    public class LatestPosts {
        public int NumPosts { get; set; }
    }
}

Ora ho il seguente codice nella libreria principale:

[HttpPost, ValidateAntiForgeryToken]
public ActionResult NewWidget(FormCollection collection) {
    var activator = Activator.CreateInstance("AssemblyName", "MyApp.Models.LatestPosts");
    var latestPosts = activator.Unwrap();

    // Try and update the model
    TryUpdateModel(latestPosts);
}

Il codice è piuttosto autoesplicativo ma la proprietà di Numposts non si aggiorna mai anche se il valore esiste nella raccolta dei moduli.

Lo apprezzerei se qualcuno potesse aiutare a spiegare perché questo non funziona e se esiste un metodo alternativo.

Grazie

È stato utile?

Soluzione

Il tuo problema non ha nulla a che fare con il fatto che il tipo è in un altro assembly o che lo stai creando dinamicamente Activator.Create. Il seguente codice illustra il problema in modo molto semplificato:

[HttpPost, ValidateAntiForgeryToken]
public ActionResult NewWidget(FormCollection collection) 
{
    // notice the type of the latestPosts variable -> object
    object latestPosts = new MyApp.Models.LatestPosts();

    TryUpdateModel(latestPosts);

    // latestPosts.NumPosts = 0 at this stage no matter whether you had a parameter
    // called NumPosts in your request with a different value or not
    ...
}

Il problema deriva dal fatto che Controller.TryUpdateModel<TModel> usi typeof(TModel) invece di model.GetType() Per determinare il tipo di modello come spiegato in Questo problema di connessione (che è chiuso con il motivo: by design).

La soluzione alternativa è quella di lanciare la tua usanza TryUpdateModel Metodo che si comporterà come ci si aspetterebbe:

protected internal bool MyTryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IValueProvider valueProvider) where TModel : class
{
    if (model == null)
    {
        throw new ArgumentNullException("model");
    }
    if (valueProvider == null)
    {
        throw new ArgumentNullException("valueProvider");
    }

    Predicate<string> propertyFilter = propertyName => new BindAttribute().IsPropertyAllowed(propertyName);
    IModelBinder binder = Binders.GetBinder(typeof(TModel));

    ModelBindingContext bindingContext = new ModelBindingContext()
    {
        // in the original method you have:
        // ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(TModel)),
        ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
        ModelName = prefix,
        ModelState = ModelState,
        PropertyFilter = propertyFilter,
        ValueProvider = valueProvider
    };
    binder.BindModel(ControllerContext, bindingContext);
    return ModelState.IsValid;
}

poi:

[HttpPost, ValidateAntiForgeryToken]
public ActionResult NewWidget(FormCollection collection) 
{
    object latestPosts = new MyApp.Models.LatestPosts();

    MyTryUpdateModel(latestPosts, null, null, null, ValueProvider);

    // latestPosts.NumPosts will be correctly bound now
    ...
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top