コードが次のように見えるアクションメソッドに整数の配列を送信しようとしています。
[HttpGet]
public async Task<IActionResult> ServicesByCategoryIds([FromQuery] int[] ids)
{
var services = await _accountsUow.GetServiceProfilesByCategoryIdsAsync(ids);
return Ok(services);
}
次のようにメソッドを呼び出します。 https:// localhost:44343/api/accounts/servicesbycategoryids?ids = 1&ids = 2
しかし、このメソッドを呼び出すと、クエリ文字列でidを渡しても、常に空の配列が取得されます。 .net core 2.1を使用しています。
私がグーグルで調べたすべてのことは、これが実際にこれが行われる方法であることを示唆しています。 。 。私はここに欠けているものがありますか?
ありがとうございました!
Array
パラメータのバインドに失敗したことは、Asp.Net Core 2.1
での既知の問題であり、記録されています クエリ文字列の配列またはリストは解析されません#7712 。
一時的な回避策として、次のようにFromQuery Name Property
を設定できます。
[HttpGet()]
[Route("ServicesByCategoryIds")]
public async Task<IActionResult> ServicesByCategoryIds([FromQuery(Name = "ids")]int[] ids)
{
return Ok();
}
アクションが1つだけの新しいWeb APIクラスを作成します。
[Produces("application/json")]
[Route("api/accounts")]
public class AccountsController : Controller
{
[HttpGet]
[Route("servicesbycategoryids")]
public IActionResult ServicesByCategoryIds([FromQuery] int[] ids)
{
return Ok();
}
}
次に、同じURLを使用します:
http:// localhost:2443/api/accounts/servicesbycategoryids?ids = 1&ids = 2
動いています。
プラメンの答えのわずかなバリエーション。
GenericTypeArguments
があるように見えるため、 GetElementType() に置き換えます。ArrayModelBinder
と衝突しないようにクラスの名前を変更しました。public class CustomArrayModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (!bindingContext.ModelMetadata.IsEnumerableType)
{
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
var value = bindingContext.ValueProvider
.GetValue(bindingContext.ModelName)
.ToString();
if (string.IsNullOrWhiteSpace(value))
{
bindingContext.Result = ModelBindingResult.Success(null);
return Task.CompletedTask;
}
var elementType = bindingContext.ModelType.GetElementType();
if (elementType == null)
{
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
var converter = TypeDescriptor.GetConverter(elementType);
var values = value.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(x => converter.ConvertFromString(Clean(x)))
.ToArray();
var typedValues = Array.CreateInstance(elementType, values.Length);
values.CopyTo(typedValues, 0);
bindingContext.Model = typedValues;
bindingContext.Result = ModelBindingResult.Success(bindingContext.Model);
return Task.CompletedTask;
}
private static string Clean(string str)
{
return str.Trim('(', ')').Trim('[', ']').Trim();
}
}
次に、IEnumerable
とともに使用します
[ModelBinder(BinderType = typeof(CustomArrayModelBinder))] IEnumerable<T> ids
... T[] ids
... List<T> ids
パラメーターは、オプションのブラケットを使用してパスまたはクエリに含めることができます。
[Route("resource/{ids}")]
resource/ids/1,2,3
resource/ids/(1,2,3)
resource/ids/[1,2,3]
[Route("resource")]
resource?ids=1,2,3
resource?ids=(1,2,3)
resource?ids=[1,2,3]
クエリ文字列ではなく、URIの一部となるカスタムモデルバインダーとIDを実装できます。
エンドポイントは次のようになります:/ api/accounts/servicesbycategoryids /(1,2)
public class ArrayModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
// Our binder works only on enumerable types
if (!bindingContext.ModelMetadata.IsEnumerableType)
{
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
// Get the inputted value through the value provider
var value = bindingContext.ValueProvider
.GetValue(bindingContext.ModelName).ToString();
// If that value is null or whitespace, we return null
if (string.IsNullOrWhiteSpace(value))
{
bindingContext.Result = ModelBindingResult.Success(null);
return Task.CompletedTask;
}
// The value isn't null or whitespace,
// and the type of the model is enumerable.
// Get the enumerable's type, and a converter
var elementType = bindingContext.ModelType.GetTypeInfo().GenericTypeArguments[0];
var converter = TypeDescriptor.GetConverter(elementType);
// Convert each item in the value list to the enumerable type
var values = value.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => converter.ConvertFromString(x.Trim()))
.ToArray();
// Create an array of that type, and set it as the Model value
var typedValues = Array.CreateInstance(elementType, values.Length);
values.CopyTo(typedValues, 0);
bindingContext.Model = typedValues;
// return a successful result, passing in the Model
bindingContext.Result = ModelBindingResult.Success(bindingContext.Model);
return Task.CompletedTask;
}
}
次に、アクションでそれを使用します。
[HttpGet("({ids})", Name="GetAuthorCollection")]
public IActionResult GetAuthorCollection(
[ModelBinder(BinderType = typeof(ArrayModelBinder))] IEnumerable<Guid> ids)
{
//enter code here
}
これを複数サイトのコースから学んだ:ASP.NET CoreでRESTful APIを構築する