为自定义类型创建自定义模型绑定器

2023-12-27

在 ASP.NET CORE 1.1 项目中,我有以下模型:

public class GetProductsModel {
  public OrderExpression OrderBy { get; set; }
}

OrderExpression 是一个具有以下方法的类:

Boolean TryParse(String value, out OrderExpression expression)

该方法创建一个OrderExpression实例来自String并可以使用:

OrderExpression expression;

Boolean parsed = OrderExpression.TryParse(value, out expression);

如何为类型属性创建自定义模型绑定器OrderExpression?


我假设您的请求数据中有一个属性orderBy您想要绑定到OrderExpression using OrderExpression.TryParse.

让我们假设你的OrderExpression类如下所示,我在其中提供了一个非常简单的实现TryParse method:

public class OrderExpression
{
    public string RawValue { get; set; }
    public static bool TryParse(string value, out OrderExpression expr)
    {
        expr = new OrderExpression { RawValue = value };
        return true;
    }
}

然后您可以创建一个模型绑定器,它基本上获取原始字符串值并调用OrderExpression.TryParse:

public class OrderExpressionBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {            
        var values = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (values.Length == 0) return Task.CompletedTask;

        // Attempt to parse
        var stringValue = values.FirstValue;
        OrderExpression expression;
        if (OrderExpression.TryParse(stringValue, out expression))
        {
            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, expression, stringValue);
            bindingContext.Result = ModelBindingResult.Success(expression);
        }

        return Task.CompletedTask;
    }
}

您还需要一个新的模型活页夹提供程序,它仅返回您的新活页夹OrderExpression type:

public class OrderExpressionBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        return context.Metadata.ModelType == typeof(OrderExpression) ? new OrderExpressionBinder() : null;
    }
}

// It should be registered in your Startup class, adding it to the ModelBinderProviders collection:
services.AddMvc(opts => {
    opts.ModelBinderProviders.Insert(0, new OrderExpressionBinderProvider());
});

完成此操作后,您将能够绑定OrderExpression控制器动作的参数。类似于以下示例:

[HttpPost]
public IActionResult Products([FromBody]OrderExpression orderBy) 
{
    return Ok();
}

$.ajax({
    method: 'POST', 
    dataType: 'json', 
    url: '/home/products', 
    data: {orderby: 'my orderby expression'}
});

然而,您还需要做一些其他事情才能发送 json 并将其绑定到复杂的模型,例如GetProductsModel其内部包含一个OrderExpression。我正在谈论这样一个场景:

[HttpPost]
public IActionResult Products([FromBody]GetProductsModel model)
{
    return Ok();
}

public class GetProductsModel
{
    public OrderExpression OrderBy { get; set; }
}

$.ajax({
    method: 'POST', 
    dataType: 'json', 
    contentType: 'application/json; charset=utf-8', 
    url: '/home/products', 
    data: JSON.stringify({orderby: 'my orderby expression'})
});

在这种情况下,ASP.Net Core 将仅使用 Newtonsoft.Json 作为 InputFormatter,并将接收到的 json 转换为GetProductsModel模型,而不尝试使用新的OrderExpressionBinderProvider对于内部属性。

幸运的是,您还可以告诉 Newtonsoft.Json 如何格式化属性OrderExpression通过创建 JsonConverter 键入:

public class OrderExpressionJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(OrderExpression);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var stringValue = reader.Value?.ToString();
        OrderExpression expression;
        if (OrderExpression.TryParse(stringValue, out expression))
        {
            return expression;
        }
        return null;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

应该在您的 Startup 类中注册:

services.AddMvc(opts => {
    opts.ModelBinderProviders.Insert(0, new OrderExpressionBinderProvider());

}).AddJsonOptions(opts => {
    opts.SerializerSettings.Converters.Add(new OrderExpressionJsonConverter());
});

现在您终于能够处理这两种情况了:)

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

为自定义类型创建自定义模型绑定器 的相关文章

随机推荐

  • 如何从 python 脚本更改当前目录?

    我正在尝试实现我自己的 cd 命令版本 该命令向用户提供可供选择的硬编码目录列表 并且用户必须输入与列表中的条目相对应的数字 该程序名为my cd py现在 应该有效地将用户 cd 到所选目录 其工作原理示例 some directory
  • 获取数组中零和非零元素的索引

    我需要找到数组的零元素和非零元素的索引 换句话说 我想从中找到互补索引numpy nonzero 我知道这样做的方法如下 indices zero numpy nonzero array 0 indices nonzero numpy no
  • Django - 将字段添加到查询集中以存储计算结果

    我对 Django 很陌生 来自 PHP 世界 我试图在计算后向查询集中 添加 一个字段 但不知道该怎么做 在 PHP 中 我只需在数组中添加一列并将我的内容存储在其中 这是我的代码 def id mystuff details mystu
  • Haskell - 是否存在替换功能?

    我必须创建三个函数来替换扁平字符串和列表 我不知道是否有像其他语言那样的替换功能 但不幸的是我搜索过但没有成功 所以我的尝试还很薄弱 第一个功能 replace String gt String gt String gt String re
  • 在 TypeScript 中导入音频文件

    我在 TypeScript React 应用程序 使用 create react app 制作 中导入音频文件时遇到问题 我正在尝试像这样导入文件 import note from audio note1s mp3 但我收到了 TypeSc
  • 使用 React Hooks 的倒计时器

    所以定时器起作用了 如果我硬编码this state使用特定的倒计时数字 计时器在页面加载后开始倒计时 我希望时钟在单击按钮时开始倒计时 并具有改变时间的功能null of the state到一个随机生成的数字 我对 React 有点陌生
  • 哪个会使 Class 文件更大? import java.awt.*,还是一堆或单个导入语句? [复制]

    这个问题在这里已经有答案了 好的 如果我有一个项目使用 import java awt Graphics import java awt Graphics2D import java awt Dimension import java aw
  • PyCaffe中的layer模块在哪里定义

    我正在修改一个Caffe教程 http nbviewer jupyter org github BVLC caffe blob master examples pascal multilabel with datalayer ipynb实现
  • 检查父类中是否存在类

    我想检查某个元素的父元素之一中是否存在某个类 我不想使用任何库 只想使用普通 JS 在下面的示例中 如果相关元素位于以 the class 作为类名的元素的子元素中的某个位置 则应返回 true 我认为 jQuery 会是这样的 if th
  • bitbake:构建系统如何选择多个层提供的配方

    元层提供配方 meta recipes graphics x11 common xserver nodm init bb 元 oe 层提供配方 meta oe recipes graphics xserver nodm init xserv
  • 在生产应用程序中使用谷歌凭据的最佳方法是什么?

    我正在为 STT 构建 C net 应用程序 并且正在手动创建凭据 我发现文档对我来说非常混乱 我不知道如何正确添加凭据 我添加了一个项目 创建了一个 json 凭证并下载并保存在一个文件夹中 并手动指向它GoogleCredential获
  • 为什么以及何时使用 LINQ? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我从未在我的任何项目中使用过 LINQ 我一直在我的商业应用程序项目中使用 ado net OR 工具 所以我想知道 LINQ 有什么好处 为什
  • Python OpenCV 多处理 cv2.VideoCapture mp4

    我想运行一些mp4进程内的视频 但只有摄像头有效 软件卡住 没有错误消息 我已经尝试过这两种方法 但发现它无法运行 打印是代码被卡住的地方 import cv2 import multiprocessing dispW 640 dispH
  • SQL Server 2008 域更改

    在不久的将来 我的组织将不得不更改其中一台 SQL 服务器的计算机名称和 Windows 域 服务器运行SQL Server 2008企业版 操作系统为Windows Server 2008标准版 我找到了处理机器名称更改的良好参考资料 但
  • 致命错误:在第 146 行 ...\..\Abstract.php 中找不到类“Mage_Enterprise_Giftwrapping_Block_Adminhtml_Product_Helper_Form_Config”

    我正在将 magento 企业版迁移到社区版 我就快完成了 但后端几乎没有问题 如果我转到 管理产品 并单击任何产品 我会收到此错误 致命错误 在第 146 行 lib Varien Data Form Abstract php 中找不到类
  • Windows 中的 Visual Studio Code 命令无法正常工作

    我的问题是 在 Windows 上手动将 VS Code 命令行添加到 PATH 时 如何才能使其正常工作 在 Visual Studio Code 内部 我首先尝试使用复选框 安装到 PATH 来安装它 但是当我输入code在命令提示符中
  • 从文本中解析子字符串

    我正在编写一个宏 用于将 LDAP 格式的名称列表转换为 名字 姓氏 区域 对于那些不知道 LDAP 是什么样子的人 如下所示 CNN 约翰 史密斯 区域 OU 法律 DC 示例 DC 命令 在 Excel VBA 中 我似乎无法使用 st
  • 如何触发附加到 ZF2 中共享事件管理器的事件?

    附加到 本地 事件管理器的事件 public class myClass implements EventManagerAwareInterface public function construct this gt getEventMan
  • 在 WIN32 中的“BUTTON”类窗口上显示位图

    Edit 我认为在创建子窗口 即我的按钮 期间不会发送 WM CREATE 消息 因此 通过在 WM CREATE 期间调用 SendMessage 我将向尚未创建的窗口发送一条消息 目前的解决方案是在 WM SHOWWINDOW 消息期间
  • 为自定义类型创建自定义模型绑定器

    在 ASP NET CORE 1 1 项目中 我有以下模型 public class GetProductsModel public OrderExpression OrderBy get set OrderExpression 是一个具有