c# - 从浏览器中的地址行执行时获取 415 不受支持的媒体类型,提供 JSON 作为 .NET Core 3 中路由的参数
问题描述
我正在执行 URL
https://localhost:44310/api/Licensee/{"name":"stan"}
在我的浏览器的地址字段中,出现错误
“标题”:“不支持的媒体类型”,“状态”:415
这被描述为
...源服务器拒绝为请求提供服务,因为有效负载的格式不受目标资源上此方法的支持。
建议的故障排除是
...由于请求指示的 Content-Type 或 Content-Encoding,或由于检查数据...
我无法真正控制浏览器提供的标题。由于预期用途,我不能依赖 Postman 或 Web 应用程序。它需要从 URL 行执行。该参数的结构会有所不同,具体取决于应用的搜索条件。
控制器看起来像这样。
[HttpGet("{parameters}")]
public async Task<ActionResult> GetLicensee(LicenseeParameters parameters)
{
return Ok(await Licensee.GetLicenseeByParameters(parameters));
}
我考虑用[Consumes("application/json")]来装饰控制器,但发现有些东西让它感到沮丧。我尝试按照此处和此处的建议添加 JSON 转换器,但无法真正确定要设置的选项,根据this摸索,不确定我是否从正确的树开始。
services.AddControllers()
.AddJsonOptions(_ =>
{
_.JsonSerializerOptions.AllowTrailingCommas = true;
_.JsonSerializerOptions.PropertyNamingPolicy = null;
_.JsonSerializerOptions.DictionaryKeyPolicy = null;
_.JsonSerializerOptions.PropertyNameCaseInsensitive = false;
});
我的备份选项是使用查询字符串指定特定搜索所需的选项。但是,我现在更喜欢使用带参数的对象。
我该如何解决这个问题(或至少进一步排除故障)?
解决方案
原因是可能有很多参数,我不想每次都重构控制器的签名
实际上,您不必每次都更改控制器的签名。ASP.NET Core 模型绑定器能够自动绑定来自查询字符串的对象。例如,假设您有一个简单的控制器:
[HttpGet("/api/licensee")] public IActionResult GetLicensee([FromQuery]LicenseeParameters parameters) { return Json(parameters); }
第一次 DTO 是:
public class LicenseeParameters { public string Name {get;set;} public string Note {get;set;} }
您需要发送如下 HTTP 请求:
GET /api/licensee?name=stan¬e=it+works
后来你决定改变
LicenseeParameters
:public class LicenseeParameters { public string Name {get;set;} public string Note {get;set;} public List<SubNode> Children{get;set;} // a complex array }
您不必更改控制器签名。只需以这种方式发送有效载荷:
GET /api/licensee?name=stan¬e=it+works&children[0].nodeName=it&children[1].nodeName=minus
转换为 :
.
表示属性并[]
表示集合或字典。如果您确实想在 URL 中发送一个 json 字符串,您需要创建一个自定义模型绑定器。
internal class LicenseeParametersModelBinder : IModelBinder { private readonly JsonSerializerOptions _jsonOpts; public LicenseeParametersModelBinder(IOptions<JsonSerializerOptions> jsonOpts) { this._jsonOpts = jsonOpts.Value; } public Task BindModelAsync(ModelBindingContext bindingContext) { var name= bindingContext.FieldName; var type = bindingContext.ModelType; try{ var json= bindingContext.ValueProvider.GetValue(name).FirstValue; var obj = JsonSerializer.Deserialize(json,type, _jsonOpts); bindingContext.Result = ModelBindingResult.Success(obj); } catch (JsonException ex){ bindingContext.ModelState.AddModelError(name,$"{ex.Message}"); } return Task.CompletedTask; } }
并注册模型绑定如下:
[HttpGet("/api/licensee/{parameters}")] public IActionResult GetLicensee2([ModelBinder(typeof(LicenseeParametersModelBinder))]LicenseeParameters parameters) { return Json(parameters); }
最后,您可以在 URL 中发送一个 json(假设属性名称不区分大小写):
GET /api/licensee/{"name":"stan","note":"it works","children":[{"nodeName":"it"},{"nodeName":"minus"}]}
以上两种方法都对我有用。但我个人建议您使用第一个,因为它是内置功能。
推荐阅读
- node.js - .save() 不是函数(猫鼬)
- macos - 在 Inline::C 中链接 macos 的框架
- java - 当 TextInputEditText 为空时,TextInputLayout 框笔划不显示
- go - 如何从 Golang 包中的文档中恢复结构,Bleve
- jquery - 由于 SET 语句,SQL 查询失败
- postgresql - 如何启动具有有效初始设置的 postgres docker 容器?
- angular - 应该已经选择了第一个条目并在页面加载时显示其内容,该怎么做?
- node.js - 首次连接时无法连接到服务器 [localhost:27017] [错误:在 TCPConnectWrap.afterConnect 处连接 ECONNREFUSED ---- [as oncomplete]
- python - 有没有办法为 Python 列表中的单个元素着色?
- c - 为什么只有第一个字母转换为小写字母?