2012-02-21 25 views
2

我在程序集中有一个未被核心库引用但是从Web应用程序引用的类型。例如模型绑定 - 键入外部程序集

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财产从未即使价值形态集合中存在更新。

如果有人能够帮助解释为什么这不起作用以及是否有其他方法,我将不胜感激。

感谢

回答

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解释模型类型(其与原因关闭的事实茎: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; 
} 

然后:

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

由于工作一种享受! – nfplee 2012-02-22 14:13:37

+0

雅谢谢! – Rookian 2012-06-22 08:43:51

+0

当我面对这样的解决方案时,我意识到我离成为一名真正优秀的程序员非常遥远。在这个问题上失去了一天。非常感谢你。 – Alexandre 2014-06-12 12:54:36