NET Core:使用 HttpGet 进行过滤
NET Core: Filtering with HttpGet
我想使用 httpGet 按 makeId 过滤车辆列表。我希望使用的 URL 是:
https://localhost:5001/api/vehicle?makeId=2
下面,我将定义我用于此任务的 DTO 和控制器方法:
FilterDto
public class FilterDTO
{
public int? MakeId { get; set; }
}
下面是我的控制器中的 2 个 HTTPGet 方法 class。我希望调用第一个方法。
[HttpGet]
public async Task<IEnumerable<VehicleDTO>> Get(FilterDTO filterDto)
{
var filter = _mapper.Map<Filter>(filterDto);
var vehicles = await _vehicleRepository.GetAll(filter);
return _mapper.Map<IEnumerable<VehicleDTO>>(vehicles);
}
[HttpGet("{id}")]
public async Task<ActionResult<VehicleDTO>> Get(long id)
{
var vehicle = await _vehicleRepository.GetWithRelated(id);
if (vehicle == default)
{
return BadRequest("Vehicle not found");
}
var result = _mapper.Map<VehicleDTO>(vehicle);
return Ok(result);
}
使用上面的代码,当我调用上面的 URL 时,在 Postman 中我得到一个 400 错误,说“输入不包含任何 JSON 标记。期望输入以一个有效的 JSON 标记,当 isFinalBlock 为真时。路径:$ | LineNumber:0 | BytePositionInLine:0。”
我对 https://localhost:5001/api/vehicle
得到相同的结果
如果我像下面这样更改第一个 Get 方法,我就能得到响应:
[HttpGet]
public async Task<IEnumerable<VehicleDTO>> Get(int? makeId)
{
var filter = new Filter { MakeId = makeId};
var vehicles = await _vehicleRepository.GetAll(filter);
return _mapper.Map<IEnumerable<VehicleDTO>>(vehicles);
}
在这个(冗长的)介绍之后,我的问题是:
- 为什么HttpGet支持'int?'而不支持数据传输对象'FilterDto'?
- 我应该使用不同的动词而不是 HttpGet 吗?
- 我以后可能需要过滤一些其他类型(比如 customerId)。有什么办法可以更改方法以支持自定义对象,如 FilterDto,理想情况下无需更改动词?
看看docs。
基本支持原始类型,但是控制器不知道如何将您的网络请求数据转换为C#对象。您需要明确告诉它您希望如何根据 Web 请求创建此自定义对象。
您可能记得 HttpGet 方法只能接收原始类型(字符串、整数、短、日期时间 - 使用特定格式 -),因为参数是通过查询字符串发送的,例如:
myAddres.com/api/mymethod?id=5&filter1=value1&filter2=value2
考虑到这一点,您会发现无法发送任何对象,因为您需要使用 json 或其他表示法,请记住查询字符串有限制,因此最好使用“argument =值”表示法。
另一方面,PUT 和 POST 能够通过“正文”属性 发送它们的数据,您可以在其中使用 json 符号,这样您几乎可以创建后端端的任何对象。
如果您需要使用对象作为参数,最好使用 POST 或 PUT(POST 比 PUT 更好)。
按如下方式更改您的代码:
[HttpGet]
public async Task<IEnumerable<VehicleDTO>> Get([FromQuery] FilterDTO filterDto)
{
var filter = _mapper.Map<Filter>(filterDto);
var vehicles = await _vehicleRepository.GetAll(filter);
return _mapper.Map<IEnumerable<VehicleDTO>>(vehicles);
}
并这样称呼它:
baseUrl/Controller/Get?MarkId=1
我想使用 httpGet 按 makeId 过滤车辆列表。我希望使用的 URL 是: https://localhost:5001/api/vehicle?makeId=2
下面,我将定义我用于此任务的 DTO 和控制器方法:
FilterDto
public class FilterDTO
{
public int? MakeId { get; set; }
}
下面是我的控制器中的 2 个 HTTPGet 方法 class。我希望调用第一个方法。
[HttpGet]
public async Task<IEnumerable<VehicleDTO>> Get(FilterDTO filterDto)
{
var filter = _mapper.Map<Filter>(filterDto);
var vehicles = await _vehicleRepository.GetAll(filter);
return _mapper.Map<IEnumerable<VehicleDTO>>(vehicles);
}
[HttpGet("{id}")]
public async Task<ActionResult<VehicleDTO>> Get(long id)
{
var vehicle = await _vehicleRepository.GetWithRelated(id);
if (vehicle == default)
{
return BadRequest("Vehicle not found");
}
var result = _mapper.Map<VehicleDTO>(vehicle);
return Ok(result);
}
使用上面的代码,当我调用上面的 URL 时,在 Postman 中我得到一个 400 错误,说“输入不包含任何 JSON 标记。期望输入以一个有效的 JSON 标记,当 isFinalBlock 为真时。路径:$ | LineNumber:0 | BytePositionInLine:0。” 我对 https://localhost:5001/api/vehicle
得到相同的结果如果我像下面这样更改第一个 Get 方法,我就能得到响应:
[HttpGet]
public async Task<IEnumerable<VehicleDTO>> Get(int? makeId)
{
var filter = new Filter { MakeId = makeId};
var vehicles = await _vehicleRepository.GetAll(filter);
return _mapper.Map<IEnumerable<VehicleDTO>>(vehicles);
}
在这个(冗长的)介绍之后,我的问题是:
- 为什么HttpGet支持'int?'而不支持数据传输对象'FilterDto'?
- 我应该使用不同的动词而不是 HttpGet 吗?
- 我以后可能需要过滤一些其他类型(比如 customerId)。有什么办法可以更改方法以支持自定义对象,如 FilterDto,理想情况下无需更改动词?
看看docs。
基本支持原始类型,但是控制器不知道如何将您的网络请求数据转换为C#对象。您需要明确告诉它您希望如何根据 Web 请求创建此自定义对象。
您可能记得 HttpGet 方法只能接收原始类型(字符串、整数、短、日期时间 - 使用特定格式 -),因为参数是通过查询字符串发送的,例如:
myAddres.com/api/mymethod?id=5&filter1=value1&filter2=value2
考虑到这一点,您会发现无法发送任何对象,因为您需要使用 json 或其他表示法,请记住查询字符串有限制,因此最好使用“argument =值”表示法。
另一方面,PUT 和 POST 能够通过“正文”属性 发送它们的数据,您可以在其中使用 json 符号,这样您几乎可以创建后端端的任何对象。
如果您需要使用对象作为参数,最好使用 POST 或 PUT(POST 比 PUT 更好)。
按如下方式更改您的代码:
[HttpGet]
public async Task<IEnumerable<VehicleDTO>> Get([FromQuery] FilterDTO filterDto)
{
var filter = _mapper.Map<Filter>(filterDto);
var vehicles = await _vehicleRepository.GetAll(filter);
return _mapper.Map<IEnumerable<VehicleDTO>>(vehicles);
}
并这样称呼它:
baseUrl/Controller/Get?MarkId=1