本文介绍了模型绑定-外部装配体中的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在程序集中有一个类型,它不是核心库引用的,而是从Web应用程序引用的.例如

I have a type in an assembly which isn't referenced by the core library but is referenced from the web application. e.g.

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

现在我在核心库中有以下代码:

Now i have the following code in the core library:

[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属性也不会更新.

The code is quite self explanatory but latestPosts.NumPosts property never updates even though the value exists in the form collection.

如果有人能帮助解释为什么它不起作用以及是否有替代方法,我将不胜感激.

I'd appreciate it if someone could help explain why this does not work and whether there is an alternative method.

谢谢

推荐答案

您的问题与该类型在另一个程序集中还是正在使用Activator.Create动态创建它无关.以下代码以一种非常简化的方式说明了该问题:

Your problem has nothing to do with the fact that the type is in another assembly or that you are dynamically creating it with Activator.Create. The following code illustrates the issue in a much simplified way:

[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()来确定模型类型,如此连接问题(其原因如下:by design)

The problem stems from the fact that Controller.TryUpdateModel<TModel> uses typeof(TModel) instead of model.GetType() to determine the model type as explained in this connect issue (which is closed with the reason: by design).

解决方法是滚动自定义的TryUpdateModel方法,该方法的行为将与您期望的一样:

The workaround is to roll your custom TryUpdateModel method which will behave as you would expect:

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

然后:

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

这篇关于模型绑定-外部装配体中的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 10:02