CreatedAtRoute 传递多个路由值
CreatedAtRoute passing multiple route values
我正在尝试创建一个接受 1 个或多个模型的端点 (POST),然后将这些模型批量插入到数据库中。
一切正常,除非我尝试使用已创建对象和路由的列表调用 CreatedAtRoute
。
当我用多个 routes/models 调用 CreatedAtRoute
时,我得到一个运行时 InvalidOperationException
,没有匹配的路由。
例子
[HttpPost]
public async Task<ActionResult<IEnumerable<QaiStateModel>>> CreateQaiStateAsync(
IEnumerable<QaiStateCreationModel> inputQaiStates )
{
var qaiStates = _mapper.Map<IEnumerable<QaiState>>( inputQaiStates );
await _qaiService.AddQaiStatesAsync( qaiState ).ConfigureAwait( false );
var models = _mapper.Map<List<QaiStateModel>>( qaiState );
var ids = models.Select( m => new { qaiStateID = m.ID } );
return CreatedAtRoute( "GetQaiState", ids, models );
}
作为参考,我有以下 GET/{ID}
端点:
[HttpGet( "{qaiStateID}", Name = "GetQaiState" )]
public async Task<ActionResult<QaiStateModel>> GetQaiStateAsync( int qaiStateID )
问题
是否可以return同时URI
访问新添加的资源以及这些资源的模型表示列表?
我也不确定这是否是处理这种情况的正确方法(关于我应该 returning)。
更改 CreatedAtRoute
如下所示:
return CreatedAtRoute("GetQaiState", new { qaiStateID = ids },models);
更改 GetQaiStateAsync
方法如下:
public async Task<ActionResult<QaiStateModel>> GetQaiStateAsync(List<int> qaiStateID )
为了填充 201 响应的位置 header,return 创建的模型并通过路由传递 ID,我必须执行以下操作:
- 创建一个需要 ID 数组的新
GET
处理程序
- 创建一个
ModelBinder
来转换从路由传递的 ID 数组
- 将
POST
处理程序 CreatedAtRoute
指向此 GET
处理程序。此外,新创建的 ID's
必须连接到一个逗号分隔的列表中,该列表将传递给 CreatedAtRoute
第 1 步:
GET
处理程序现在期望通过路由传递 array
个 ID。注意指定的路线 ({ids})
。在这里我指定我想要一个用括号 ()
.
分隔的值数组
[HttpGet( "({ids})", Name = "GetQaiStateCollection" )]
public async Task<ActionResult<IEnumerable<QaiStateModel>>> GetQaiStateCollectionAsync(
[FromRoute]
[ModelBinder( BinderType = typeof( ArrayModelBinder ) )]
IEnumerable<int>? ids )
{
if ( ids is null )
return BadRequest( "Invalid ID's" );
var states = await _qaiService
.GetQaiStatesAsync( ids ).ConfigureAwait( false );
if ( ids.Count( ) != states.Count( ) )
return NotFound( "Failed to find one or more states matching the provided ID's" );
var models = _mapper.Map<IEnumerable<QaiStateModel>>( states );
return Ok( models );
}
第 2 步:
为了将路线 http://localhost:32003/QaiStateCollection/(4,2,3)
转换为 IEnumerable<int>
,必须创建自定义模型活页夹。
public class ArrayModelBinder : IModelBinder
{
public Task BindModelAsync( ModelBindingContext bindingContext )
{
// This model binder only works for enumerable types.
if ( !bindingContext.ModelMetadata.IsEnumerableType )
{
bindingContext.Result = ModelBindingResult.Failed( );
return Task.CompletedTask;
}
// Get the input value via the value provider.
var value = bindingContext.ValueProvider
.GetValue( bindingContext.ModelName ).ToString( );
if ( string.IsNullOrWhiteSpace( value ) )
{
// Returning null here will allow us to check for this
// and return a bad request.
bindingContext.Result = ModelBindingResult.Success( null );
return Task.CompletedTask;
}
var elementType = bindingContext.ModelType.GenericTypeArguments.First( );
var converter = TypeDescriptor.GetConverter( elementType );
var values = value.Split( new [ ] { "," }, StringSplitOptions.RemoveEmptyEntries )
.Select( v => converter.ConvertFromString( v.Trim( ) ) )
.ToArray( );
var typedValues = Array.CreateInstance( elementType, values.Length );
values.CopyTo( typedValues, 0 );
bindingContext.Model = typedValues;
bindingContext.Result = ModelBindingResult.Success( bindingContext.Model );
return Task.CompletedTask;
}
}
第 3 步:
在这里,ID 被连接成逗号分隔的列表并传递给 CreatedAtRoute
。新的 GET
处理程序名称也传递给 CreatedAtRoute
.
[HttpPost]
public async Task<ActionResult<IEnumerable<QaiStateModel>>> CreateQaiStateCollectionAsync(
IEnumerable<QaiStateCreationModel> inputModels )
{
var qaiStates = _mapper.Map<IEnumerable<QaiState>>( inputModels );
await _qaiService.AddQaiStateCollectionAsync( qaiStates ).ConfigureAwait( false );
var models = _mapper.Map<IEnumerable<QaiStateModel>>( qaiStates );
var ids = string.Join( ",", models.Select( m => m.ID ) );
return CreatedAtRoute( "GetQaiStateCollection", new { ids }, models );
}
我正在尝试创建一个接受 1 个或多个模型的端点 (POST),然后将这些模型批量插入到数据库中。
一切正常,除非我尝试使用已创建对象和路由的列表调用 CreatedAtRoute
。
当我用多个 routes/models 调用 CreatedAtRoute
时,我得到一个运行时 InvalidOperationException
,没有匹配的路由。
例子
[HttpPost]
public async Task<ActionResult<IEnumerable<QaiStateModel>>> CreateQaiStateAsync(
IEnumerable<QaiStateCreationModel> inputQaiStates )
{
var qaiStates = _mapper.Map<IEnumerable<QaiState>>( inputQaiStates );
await _qaiService.AddQaiStatesAsync( qaiState ).ConfigureAwait( false );
var models = _mapper.Map<List<QaiStateModel>>( qaiState );
var ids = models.Select( m => new { qaiStateID = m.ID } );
return CreatedAtRoute( "GetQaiState", ids, models );
}
作为参考,我有以下 GET/{ID}
端点:
[HttpGet( "{qaiStateID}", Name = "GetQaiState" )]
public async Task<ActionResult<QaiStateModel>> GetQaiStateAsync( int qaiStateID )
问题
是否可以return同时URI
访问新添加的资源以及这些资源的模型表示列表?
我也不确定这是否是处理这种情况的正确方法(关于我应该 returning)。
更改 CreatedAtRoute
如下所示:
return CreatedAtRoute("GetQaiState", new { qaiStateID = ids },models);
更改 GetQaiStateAsync
方法如下:
public async Task<ActionResult<QaiStateModel>> GetQaiStateAsync(List<int> qaiStateID )
为了填充 201 响应的位置 header,return 创建的模型并通过路由传递 ID,我必须执行以下操作:
- 创建一个需要 ID 数组的新
GET
处理程序 - 创建一个
ModelBinder
来转换从路由传递的 ID 数组 - 将
POST
处理程序CreatedAtRoute
指向此GET
处理程序。此外,新创建的ID's
必须连接到一个逗号分隔的列表中,该列表将传递给CreatedAtRoute
第 1 步:
GET
处理程序现在期望通过路由传递 array
个 ID。注意指定的路线 ({ids})
。在这里我指定我想要一个用括号 ()
.
[HttpGet( "({ids})", Name = "GetQaiStateCollection" )]
public async Task<ActionResult<IEnumerable<QaiStateModel>>> GetQaiStateCollectionAsync(
[FromRoute]
[ModelBinder( BinderType = typeof( ArrayModelBinder ) )]
IEnumerable<int>? ids )
{
if ( ids is null )
return BadRequest( "Invalid ID's" );
var states = await _qaiService
.GetQaiStatesAsync( ids ).ConfigureAwait( false );
if ( ids.Count( ) != states.Count( ) )
return NotFound( "Failed to find one or more states matching the provided ID's" );
var models = _mapper.Map<IEnumerable<QaiStateModel>>( states );
return Ok( models );
}
第 2 步:
为了将路线 http://localhost:32003/QaiStateCollection/(4,2,3)
转换为 IEnumerable<int>
,必须创建自定义模型活页夹。
public class ArrayModelBinder : IModelBinder
{
public Task BindModelAsync( ModelBindingContext bindingContext )
{
// This model binder only works for enumerable types.
if ( !bindingContext.ModelMetadata.IsEnumerableType )
{
bindingContext.Result = ModelBindingResult.Failed( );
return Task.CompletedTask;
}
// Get the input value via the value provider.
var value = bindingContext.ValueProvider
.GetValue( bindingContext.ModelName ).ToString( );
if ( string.IsNullOrWhiteSpace( value ) )
{
// Returning null here will allow us to check for this
// and return a bad request.
bindingContext.Result = ModelBindingResult.Success( null );
return Task.CompletedTask;
}
var elementType = bindingContext.ModelType.GenericTypeArguments.First( );
var converter = TypeDescriptor.GetConverter( elementType );
var values = value.Split( new [ ] { "," }, StringSplitOptions.RemoveEmptyEntries )
.Select( v => converter.ConvertFromString( v.Trim( ) ) )
.ToArray( );
var typedValues = Array.CreateInstance( elementType, values.Length );
values.CopyTo( typedValues, 0 );
bindingContext.Model = typedValues;
bindingContext.Result = ModelBindingResult.Success( bindingContext.Model );
return Task.CompletedTask;
}
}
第 3 步:
在这里,ID 被连接成逗号分隔的列表并传递给 CreatedAtRoute
。新的 GET
处理程序名称也传递给 CreatedAtRoute
.
[HttpPost]
public async Task<ActionResult<IEnumerable<QaiStateModel>>> CreateQaiStateCollectionAsync(
IEnumerable<QaiStateCreationModel> inputModels )
{
var qaiStates = _mapper.Map<IEnumerable<QaiState>>( inputModels );
await _qaiService.AddQaiStateCollectionAsync( qaiStates ).ConfigureAwait( false );
var models = _mapper.Map<IEnumerable<QaiStateModel>>( qaiStates );
var ids = string.Join( ",", models.Select( m => m.ID ) );
return CreatedAtRoute( "GetQaiStateCollection", new { ids }, models );
}