Question

J'ai un type dans un assemblage qui n'est pas référencé par la bibliothèque de base mais qui est référencé à partir de l'application Web. par exemple

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

Maintenant, j'ai le code suivant dans la bibliothèque de base:

[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);
}

Le code est assez explicite mais la propriété des derniers.

J'apprécierais que quelqu'un puisse aider à expliquer pourquoi cela ne fonctionne pas et s'il existe une méthode alternative.

Merci

Était-ce utile?

La solution

Votre problème n'a rien à voir avec le fait que le type se trouve dans un autre assemblage ou que vous le créez dynamiquement avec Activator.Create. Le code suivant illustre le problème d'une manière bien simplifiée:

[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
    ...
}

Le problème découle du fait que Controller.TryUpdateModel<TModel> les usages typeof(TModel) à la place de model.GetType() Pour déterminer le type de modèle comme expliqué dans Ce problème de connexion (qui est fermé avec la raison: by design).

La solution de contournement est de rouler votre coutume TryUpdateModel Méthode qui se comportera comme vous vous en doutez:

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;
}

et alors:

[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
    ...
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top