我在程序集中有一个类型,它没有被核心库引用,但是从Web应用程序引用。 e.g。
namespace MyApp.Models {
public class LatestPosts {
public int NumPosts { get; set; }
}
}
现在我在核心库中有以下代码:
[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);
}
代码非常自我解释,但即使表格集合中存在该值,latestPosts.NumPosts属性也不会更新。
如果有人可以帮助解释为什么这不起作用以及是否有替代方法,我会很感激。
由于
答案 0 :(得分:3)
您的问题与此类型在另一个程序集中或您使用Activator.Create
动态创建它的事实无关。以下代码以简化的方式说明了该问题:
[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
...
}
问题源于Controller.TryUpdateModel<TModel>
使用typeof(TModel)
代替model.GetType()
来确定模型类型的事实,如this connect issue中所述(其结果原因为:{ {1}})。
解决方法是推送自定义by design
方法,该方法的行为与您期望的一样:
TryUpdateModel
然后:
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;
}