ASP.NET MVC 3:具有继承/多态性的 DefaultModelBinder

2024-01-06

首先,对这篇大文章(我尝试先做一些研究)以及针对同一问题的技术组合(ASP.NET MVC 3、Ninject 和 MvcContrib)表示歉意。

我正在使用 ASP.NET MVC 3 开发一个项目来处理一些客户订单。

简而言之:我有一些继承自抽象类的对象Order当向我的控制器发出 POST 请求时,我需要解析它们。如何解析正确的类型?我需要覆盖DefaultModelBinder类或者还有其他方法可以做到这一点?有人可以为我提供一些关于如何执行此操作的代码或其他链接吗?任何帮助都会很棒! 如果帖子令人困惑,我可以做任何更改以使其清晰!

因此,我有以下继承树来处理我需要处理的订单:

public abstract partial class Order {

    public Int32 OrderTypeId {get; set; }

    /* rest of the implementation ommited */
}

public class OrderBottling : Order { /* implementation ommited */ }

public class OrderFinishing : Order { /* implementation ommited */ }

这些类都是由实体框架生成的,所以我不会修改它们,因为我需要更新模型(我知道我可以扩展它们)。另外,还会有更多的订单,但都是源自Order.

我有一个通用的观点(Create.aspx)以便创建订单,并且此视图为每个继承的订单调用强类型分部视图(在本例中OrderBottling and OrderFinishing)。我定义了一个Create()GET 请求的方法和 POST 请求的其他方法OrderController班级。第二个如下:

public class OrderController : Controller
{
    /* rest of the implementation ommited */

    [HttpPost]
    public ActionResult Create(Order order) { /* implementation ommited */ }
}

现在的问题是:当我收到带有表单数据的 POST 请求时,MVC 的默认绑定器尝试实例化一个Order对象,这是可以的,因为方法的类型就是那个。但是因为Order是抽象的,它不能被实例化,而这是应该做的。

问题:我怎样才能找到具体的Order类型是由视图发送的?

我已经在 Stack Overflow 上搜索过,并在 google 上搜索了很多相关内容(我现在正在研究这个问题大约 3 天!),并找到了一些解决一些类似问题的方法,但我找不到像我真实的问题一样的东西问题。解决这个问题的两种选择:

  • 覆盖 ASP.NET MVCDefaultModelBinder并使用直接注入来发现哪种类型Order;
  • 为每个订单创建一个方法(不美观并且维护起来会有问题)。

我没有尝试第二个选项,因为我认为这不是解决问题的正确方法。对于第一个选项,我尝试使用 Ninject 解析订单类型并实例化它。我的 Ninject 模块如下所示:

private class OrdersService : NinjectModule
{
    public override void Load()
    {
        Bind<Order>().To<OrderBottling>();
        Bind<Order>().To<OrderFinishing>();
    }
}

我试图通过 Ninject 获得其中一种类型Get<>()方法,但它告诉我,解析类型的方法不止一种。所以,我知道该模块没有得到很好的实现。我也尝试为这两种类型实现这样的:Bind<Order>().To<OrderBottling>().WithPropertyInject("OrderTypeId", 2);,但它有同样的问题...实现这个模块的正确方法是什么?

我还尝试过使用 MvcContrib Model Binder。我已经这样做了:

[DerivedTypeBinderAware(typeof(OrderBottling))]
[DerivedTypeBinderAware(typeof(OrderFinishing))]
public abstract partial class Order { }

and on Global.asax.cs我已经这样做了:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterRoutes(RouteTable.Routes);

    ModelBinders.Binders.Add(typeof(Order), new DerivedTypeModelBinder());
}

但这会引发异常:System.MissingMethodException:无法创建抽象类。因此,我认为活页夹没有或无法解析为正确的类型。

非常非常感谢!

Edit:首先,感谢 Martin 和 Jason 的回答,对于延迟表示抱歉!我尝试了两种方法并且都有效!我将 Martin 的答案标记为正确,因为它更灵活并且满足了我项目的一些需求。具体来说,每个请求的 ID 都存储在数据库中,如果我仅在一个位置(数据库或类上)更改 ID,则将它们放在类上可能会破坏软件。马丁的方法在这一点上非常灵活。

@Martin:在我的代码中我改变了这一行

var concreteType = Assembly.GetExecutingAssembly().GetType(concreteTypeValue.AttemptedValue);

to

var concreteType = Assembly.GetAssembly(typeof(Order)).GetType(concreteTypeValue.AttemptedValue);

因为我的课程在另一个项目上(因此在不同的程序集中)。我分享这个是因为它似乎比仅获取无法解析外部程序集类型的执行程序集更灵活。就我而言,所有订单类都位于同一个程序集中。这不是更好,也不是一个神奇的公式,但我认为分享这个很有趣;)


我之前尝试过做类似的事情,但我得出的结论是,没有内置的东西可以处理这个问题。

我选择的选项是创建自己的模型绑定器(尽管继承自默认模型绑定器,因此代码不多)。它查找名为 xxxConcreteType 的类型名称的回发值,其中 xxx 是它绑定到的另一种类型。这意味着必须将一个字段与您尝试绑定的类型的值一起发回;在本例中,OrderConcreteType 的值为 OrderBotttle 或 OrderFinishing。

您的另一种选择是使用 UpdateModel 或 TryUpdateModel 并省略方法中的参数。您需要在调用此方法之前确定要更新哪种模型(通过参数或其他方式)并预先实例化该类,然后您可以使用任一方法来填充它

Edit:

这是代码..

public class AbstractBindAttribute : CustomModelBinderAttribute
{
    public string ConcreteTypeParameter { get; set; }

    public override IModelBinder GetBinder()
    {
        return new AbstractModelBinder(ConcreteTypeParameter);
    }

    private class AbstractModelBinder : DefaultModelBinder
    {
        private readonly string concreteTypeParameterName;

        public AbstractModelBinder(string concreteTypeParameterName)
        {
            this.concreteTypeParameterName = concreteTypeParameterName;
        }

        protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
        {
            var concreteTypeValue = bindingContext.ValueProvider.GetValue(concreteTypeParameterName);

            if (concreteTypeValue == null)
                throw new Exception("Concrete type value not specified for abstract class binding");

            var concreteType = Assembly.GetExecutingAssembly().GetType(concreteTypeValue.AttemptedValue);

            if (concreteType == null)
                throw new Exception("Cannot create abstract model");

            if (!concreteType.IsSubclassOf(modelType))
                throw new Exception("Incorrect model type specified");

            var concreteInstance = Activator.CreateInstance(concreteType);

            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => concreteInstance, concreteType);

            return concreteInstance;
        }
    }
}

将您的操作方法更改为如下所示:

public ActionResult Create([AbstractBind(ConcreteTypeParameter = "orderType")] Order order) { /* implementation ommited */ }

您需要将以下内容放入您的视图中:

@Html.Hidden("orderType, "Namespace.xxx.OrderBottling")
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ASP.NET MVC 3:具有继承/多态性的 DefaultModelBinder 的相关文章

  • Windows CE 6.0 和运行时链接到调试 DLL /MDd

    我在 x86 PC 上使用 Windows CE 6 0 R3 我已经为该平台构建了 NK bin 和 SDK 但我有一些问题需要了解如何使用 MTd 调试 DLL 构建控制台应用程序 如果我尝试构建这个 main c with MDd i
  • 不能使用函数名称距离

    以下代码可以正常编译 include
  • MSVC10 /MP 在项目中跨文件夹构建非多核

    我希望有人指出我们所遇到的错误或解决方法 使用 MP 编译项目时 似乎仅同时编译同一文件夹中的文件 我使用进程资源管理器来滑动命令行并确认行为 项目过滤器似乎对同时编译的内容没有影响 项目结构disk Folder project vcxp
  • std::async 参数的生命周期是多少?

    看来函数的参数是通过std async分享未来的生活 include
  • 是否返回 std::move (x)?

    Are std vector
  • 对无符号 8 位整数进行左移操作 [重复]

    这个问题在这里已经有答案了 我试图理解 C C 中的移位运算符 但它们给我带来了困难 我有一个无符号 8 位整数 初始化为一个值 例如 1 uint8 t x 1 根据我的理解 它在内存中的表示方式如下 0 0 0 0 0 0 0 1 现在
  • 是否可以获取指向装箱非托管值类型的指针?

    是否可以获取指向装箱非托管值类型的指针 而无需编写对每个支持的类型进行强制转换的大型 switch 语句 就像是 object val Contains a boxed unmanaged value such as int long by
  • memccpy 返回比 src 起始地址更低的内存地址

    我有一个学校项目 我必须重新编码memccpy 功能 我使用 2 个程序来检查我的代码是否正常工作 第一个是只有一个主程序的小程序 第二个程序是另一个学生开发的 可以找到here https github com yyang42 mouli
  • 为什么我在这段代码中不断得到两个相同的随机值? [复制]

    这个问题在这里已经有答案了 可能的重复 为什么我的随机数生成器在 C 中不是随机的 https stackoverflow com questions 932520 why does it appear that my random num
  • C++ 中类型信息何时向后流动?

    我刚刚看了 Stephan T Lavavej 的演讲CppCon 2018关于 类模板参数推导 在哪里某个点 https youtu be H ut6j1BYU t 941他顺便说 在 C 中 类型信息几乎永远不会向后流动 我不得不说 几
  • 如何在Phone类库项目中添加ResourceDictionary并访问它

    我正在开发一个项目 其中我有一个引用图书馆项目的子项目 在我的库项目 电话类库 中 如何创建 ResourceDictionary xaml 其中我需要添加一些样式并在 xaml 文件和 cs 文件中使用它 我需要访问 xaml 文件中的
  • 为什么 C++20 范围不只提供管道语法?

    我知道这个问题听起来很奇怪 所以这里有一些背景信息 最近 我很失望地了解到 C 20 范围内的映射缩减并不像人们所期望的那样工作 即 const double val data transform accumulate 不起作用 你必须这样
  • 验证域用户凭据

    我需要一种方法来验证 Windows 上本机 C 的用户 密码对 输入的是用户名和密码 用户可以是 DOMAIN user 格式 基本上我需要编写一个函数 如果用户 密码是有效的本地帐户 则返回 true 第1部分 如果用户 密码在给定的域
  • 函数中的重复参数检查

    我经常有调用层次结构 因为所有方法都需要相同的参数 如果我不想将它们放在实例级别 类的成员 那么我总是问我在每个方法中检查它们的有效性是否有意义 例如 public void MethodA object o if null o throw
  • std::iota 的 iota 代表什么?

    我假设 i 是增量 a 是分配 但我无法弄清楚或找到答案 而且 它看起来与非标准非常相似itoa我认为这很令人困惑 C iota is not an acronym or an initialism It is the word iota
  • C++ 项目编译为静态库,编译为动态库失败(链接器错误)。为什么?

    我有一个 VS2008 本机 C 项目 我希望将其编译为 DLL 它仅引用一个外部库 log4cplus lib 并使用其功能 当然也使用 log4cplus 的 h 文件 当我尝试将我的项目编译为静态库时 它成功了 当我尝试作为 DLL
  • 为什么 char 数组需要 strcpy 而 char star 不需要 - 在 C 中使用结构

    我对这段代码有一个误解 typedef struct EXP int x char name char lastName 40 XMP main XMP a a name eaaa a lastName strcpy a lastName
  • WPF DataGrid 选定项

    我有一个 DataGrid 用户可以通过在最后一行输入数据来添加项目 我还有一个按钮可以删除当前选定的项目 但是 当选择最后一行 空 用于添加新项目 时 最后选定的项目将保留在 SelectedItem 中 因此 如果我打开窗口 选择最后一
  • 如何在您的网站中连接两个人

    有一款名为 Verbosity 的游戏 这是一款有目的的游戏 位于此链接上www gwap com 在游戏中 他们随机连接两个玩家互相玩 游戏是玩家1应该向他的搭档 玩家2 描述一个单词 而玩家2应该猜测这个单词 我正在尝试建立一个网站来执
  • 应用非限定名称查找而不是依赖于参数的名称查找

    考虑标准 sec 3 4 1 3 中的一个示例 typedef int f namespace N struct A friend void f A operator int void g A a int i f a f is the ty

随机推荐

  • TCP 服务器未从客户端接收到正确的字节数

    我正在做一个用C语言进行TCP连接的小项目 标题中提到了我的代码的问题 以下是我的代码的上传部分 客户端 FILE fp fopen f2d rb if fp NULL perror Fail to upload client else f
  • 错误:请在 Android Studio 2.0 中选择 Android SDK

    我正在使用 Android Studio 2 0 Beta2 并且我正在尝试运行使用 google 地图 api v1 包com google android maps 作为 jar 文件 要运行这个旧项目 我需要指定早于上一个版本 23
  • Python 导入、路径、目录和模块

    首先我要说的是 我在过去的一周里做了广泛的研究 但还没有找到这些问题的实际答案 只是一些模糊的答案 并不能真正解释正在发生的事情 如果这只是因为我错过了我想要的东西 我很抱歉 请为我指出正确的方向 我的目录结构是 TestProject r
  • Spring Boot Web 应用程序错误:在名称为“dispatcherServlet”的 DispatcherServlet 中未找到带有 URI [/] 的 HTTP 请求的映射

    我检查了有关此警告的其他问题 但没有人工作 IDE Spring工具套件3 9 4 Java Oracle Java 8 当我尝试打开网页时显示错误页面 尝试本地主机 8080 https i stack imgur com FkoUo j
  • 主要 JavaScript 数据结构

    我即将参加面试 公司的核心技术之一是 JavaScript 有人告诉我 下一次面试将重点讨论 JS 数据结构 这个术语在我的任何教育中都从未出现过 我在谷歌上花了一段时间试图找到更多关于它们的信息 我能遇到的最好的事情是这个维基百科页面 h
  • PHP:open_basedir 允许的路径

    我有几个电话要打给is dir在一页上 他们一直工作没有问题 几天前 托管公司将PHP从5 2升级到5 3 从那时起 我所有的电话is dir导致以下错误 消息 Warning is dir open basedir restriction
  • OpenCV中是掩码按位与运算

    我从 python 中的 opencv 开始 我有一个关于如何应用 mask 的问题 bitwise and src1 src2 mask mask 以下哪一项描述了实现 A 全部按位 先屏蔽 src1 与掩码进行 与 运算 src2 与
  • Spring安全为所有角色名称添加了前缀“ROLE_”?

    我的网络安全配置中有以下代码 Override protected void configure HttpSecurity http throws Exception http authorizeRequests antMatchers a
  • FxCop 安装

    我正在尝试获取最新版本的 FxCop 我使用的是 Visual Studio 2010 Professional 版本 它不包含代码分析 因此我尝试使用 FxCop 进行设置 At http www microsoft com en us
  • 如何从 Python 3.10 反编译 .pyc 文件?

    我确实尝试过 uncompyle6 decompyl3 等 但它们都不适用于 3 10 现在是否有可能做到这一点 使用pycdc GitHub https github com zrax pycdc https github com zra
  • 在 Windows 上运行 MySQL 或 MariaDB 服务器的最少文件 - (便携式 MySQL/MariaDB)

    我正在寻找 MariaDB 或 MySQL 运行所需的最少文件 而无需像便携式服务器一样安装它 我更喜欢 MariaDB 而不是 MySQL 我想将它嵌入到用 Delphi 编写的软件中 我的软件将能够根据需要启动和停止服务器 我用谷歌搜索
  • Nivo 滑块:第一次显示时第一张图像缩放不成比例

    我在 div 中使用 Nivo Slider jQuery 插件 该 div 的尺寸比我正在显示的图像小 当滑块滑动到第二个图像时 图像上的图像会正确缩小 但是 当第一次显示第一个图像时 加载页面后立即 它仅在宽度上缩放 而在高度上不缩放
  • 如何重新映射 python 字典键

    我正在开发一个程序 该程序 除其他外 读取 CSV 文件 它以以下形式存储为字典数组 col1 data1a col2 data2a col1 data1b col2 data2b 对于每一行 作为其他处理的一部分 我需要将这些键重新映射到
  • 更改 UITableView 的节页眉/页脚标题而不重新加载整个表视图

    有没有办法在不调用的情况下重新加载表视图的节页眉 页脚 tableView reloadData 事实上 我想在表视图的部分页脚中显示表格视图部分中的单元格数量 表视图是可编辑的 我使用删除或插入行 insertRowsAtIndexPat
  • Android:将 PNG ByteArray 写入文件

    我已将图像文件读入 ByteArray 但如何将其写回 我的意思是将 ByteArray 保存到文件系统中的图像文件 首选 PNG 格式 我的代码从 PNG 文件到 ByteArray ByteArrayOutputStream strea
  • 使用 Quartz 跨多个无状态应用程序服务器调度单个作业

    我在负载均衡器后面有一层相同的应用程序服务器 出于操作原因 我有一个限制 即两个应用程序服务器上的应用程序配置必须相同 以便可以轻松添加和删除节点 所有应用程序服务器共享相同的数据库 应用程序服务器不会 不会集群 到目前为止 这一切都运行良
  • 在片段中初始化字体

    我有这一行 Typeface font Typeface createFromAsset getAssets fonts Delius Regular ttf but the getAssets 参数似乎带来了一些错误 它带有可怕的红线下划
  • 为什么我们要在 YARN 中配置 mapred.job.tracker?

    据我所知 YARN 被引入并取代了 JobTracker 和 TaskTracker 我看过一些Hadoop 2 6 0 2 7 0安装教程 他们正在配置mapreduce framework name作为纱线和mapred job tra
  • 在运行时调整 char[] 的大小

    我需要调整大小char array size to char array new size 在运行时 我怎样才能做到这一点 如果您正在使用std vector
  • ASP.NET MVC 3:具有继承/多态性的 DefaultModelBinder

    首先 对这篇大文章 我尝试先做一些研究 以及针对同一问题的技术组合 ASP NET MVC 3 Ninject 和 MvcContrib 表示歉意 我正在使用 ASP NET MVC 3 开发一个项目来处理一些客户订单 简而言之 我有一些继