从浏览器中的地址行执行时获取 415 不支持的媒体类型,将 JSON 作为 .NET Core 3 中的路由参数
Getting 415 Unsupported media type when executing from address line in browser provifing JSON as parameter for route in .NET Core 3
我正在执行 URL
https://localhost:44310/api/Licensee/{"name":"stan"}
在我浏览器的地址字段中,出现错误
"title": "Unsupported Media Type", "status": 415
其中is described为
... the origin server is refusing to service the request because the payload
is in a format not supported by this method on the target resource.
建议的问题是
... due to the request's indicated Content-Type or Content-Encoding, or as a result of inspecting the data ...
我无法真正控制 header 浏览器提供的内容。由于预期用途,我不能依赖 Postman 或 Web 应用程序。它需要从 URL 行中执行。该参数的结构会有所不同,具体取决于应用的搜索条件。
控制器看起来像这样。
[HttpGet("{parameters}")]
public async Task<ActionResult> GetLicensee(LicenseeParameters parameters)
{
return Ok(await Licensee.GetLicenseeByParameters(parameters));
}
我考虑用 [Consumes("application/json")] 装饰控制器,但发现 something dicouraging it. I tried to add JSON converter as suggested and but couldn't really work out what option to set, fumbling according to ,不确定我是否在咆哮正确的树开始。
services.AddControllers()
.AddJsonOptions(_ =>
{
_.JsonSerializerOptions.AllowTrailingCommas = true;
_.JsonSerializerOptions.PropertyNamingPolicy = null;
_.JsonSerializerOptions.DictionaryKeyPolicy = null;
_.JsonSerializerOptions.PropertyNameCaseInsensitive = false;
});
我的备用选项是使用查询字符串指定特定搜索所需的选项。但是,我现在更愿意使用带参数的 object。
我该如何解决这个问题(或至少进一步排除故障)?
The reason is that there might be a loooot of parameters and I don't want to refactor the controller's signature each time
实际上,您不必每次都更改控制器的签名。 ASP.NET 核心模型绑定器能够自动绑定来自查询字符串的对象。例如,假设您有一个简单的控制器:
[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"}]}
以上两种方法都适合我。但我个人建议您使用第一个,因为它是内置功能。
我正在执行 URL
https://localhost:44310/api/Licensee/{"name":"stan"}
在我浏览器的地址字段中,出现错误
"title": "Unsupported Media Type", "status": 415
其中is described为
... the origin server is refusing to service the request because the payload is in a format not supported by this method on the target resource.
建议的问题是
... due to the request's indicated Content-Type or Content-Encoding, or as a result of inspecting the data ...
我无法真正控制 header 浏览器提供的内容。由于预期用途,我不能依赖 Postman 或 Web 应用程序。它需要从 URL 行中执行。该参数的结构会有所不同,具体取决于应用的搜索条件。
控制器看起来像这样。
[HttpGet("{parameters}")]
public async Task<ActionResult> GetLicensee(LicenseeParameters parameters)
{
return Ok(await Licensee.GetLicenseeByParameters(parameters));
}
我考虑用 [Consumes("application/json")] 装饰控制器,但发现 something dicouraging it. I tried to add JSON converter as suggested
services.AddControllers()
.AddJsonOptions(_ =>
{
_.JsonSerializerOptions.AllowTrailingCommas = true;
_.JsonSerializerOptions.PropertyNamingPolicy = null;
_.JsonSerializerOptions.DictionaryKeyPolicy = null;
_.JsonSerializerOptions.PropertyNameCaseInsensitive = false;
});
我的备用选项是使用查询字符串指定特定搜索所需的选项。但是,我现在更愿意使用带参数的 object。
我该如何解决这个问题(或至少进一步排除故障)?
The reason is that there might be a loooot of parameters and I don't want to refactor the controller's signature each time
实际上,您不必每次都更改控制器的签名。 ASP.NET 核心模型绑定器能够自动绑定来自查询字符串的对象。例如,假设您有一个简单的控制器:
[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"}]}
以上两种方法都适合我。但我个人建议您使用第一个,因为它是内置功能。