Modèle de liaison - Type dans un assemblage externe
-
28-10-2019 - |
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
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
...
}