【问题标题】:Strongly typed view resolves wrong type when posted back to action with inherited model当使用继承的模型发布回操作时,强类型视图会解析错误的类型
【发布时间】:2013-04-03 23:06:06
【问题描述】:

我正在为我正在为大学电子邮件系统构建的网站上的用户帐户系统开发多类型用户配置文件编辑器。

我有 3 个视图模型 AdministratorFacultyStudent,它们继承自 Person 类。当它们使用EditorForModel() 在视图中显示时,它们显示正确的编辑器就好了,但是当我向控制器提交更改时,它们被解析为基类(我已经使用 Visual Studio 调试器验证了这一点)而不是正确提交的视图模型班级。因此,当它到达操作方法时,我会丢失重要的编辑器数据。在将其发布回控制器而不为每种模型类型创建完全独立的视图时,如何使其解析正确的类型?

【问题讨论】:

  • 毫无疑问,您必须为此编写自定义模型绑定器。
  • 如果不编写自定义模型绑定器就不能使用继承类型,那么编辑器的意义何在
  • 不是 EditorFor 调用决定了传递给 Action 方法的内容。当模型绑定器查看方法的签名时,它说“哦,看,Person 对象,我将创造其中之一……”。请记住,服务器接收的所有内容都是表单发布的值。没有(默认)方法可以通知客户端编辑器模板类型。
  • 试试这个:当你尝试使用var vm = editorModelVM as Administrator 获取Administrator 视图模型时,vm 是返回空值还是实例值?也许你只需要向上转型,这就是我的意思。

标签: c# asp.net .net asp.net-mvc asp.net-mvc-4


【解决方案1】:

我想出了以下解决方案:

public class InheritanceBinder : DefaultModelBinder
    {

        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var modelType = bindingContext.ModelType;
            object model = modelType.Assembly.CreateInstance(modelType.FullName);

            var inheritedtypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => model.GetType().IsAssignableFrom(t)).ToList();
            HttpRequestBase req = controllerContext.HttpContext.Request;
            var keys = req.Form.Keys.Cast<string>().Where(q => q != "__RequestVerificationToken").ToList();



            List<KeyValuePair<Type, int>> matches = new List<KeyValuePair<Type,int>>();

            inheritedtypes.ForEach(t => {
                int p_matches = 0;

                Array.ForEach(t.GetProperties(), item =>
                {
                    if (keys.Any(key => item.Name == key))
                        p_matches++;
                });

                matches.Add(new KeyValuePair<Type, int>(t, p_matches));
            });




            var bestmatches = matches.Where(q => q.Value == matches.Max(s => s.Value));
            if (!bestmatches.Any())
                throw new TargetInvocationException("Could not determine model to bind based on the form values provided", null);

            var usematch = bestmatches.First().Key;

            object bindObj = Activator.CreateInstance(usematch);



            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => bindObj, usematch);

            return base.BindModel(controllerContext, bindingContext);
        }


    }

【讨论】:

    【解决方案2】:

    您确定您在操作方法中所期望的模型不是 Person 类型吗? 这可能会导致您出现问题。

    【讨论】:

    • 它应该是一种被接收的人,但它是错误类型的人,即我正在发布一个学生并且接收的人丢失了与学生相关的数据
    • 这是正常的,因为默认的模型绑定器是使用你的操作方法的参数类型来创建一个对象。
    猜你喜欢
    • 1970-01-01
    • 2012-10-02
    • 2019-01-08
    • 2012-06-09
    • 1970-01-01
    • 2016-05-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多