如何通过模型绑定将原始查询字符串作为控制器操作参数?
How to have the raw query string as a controller action parameter via model binding?
我想将原始查询字符串作为控制器操作参数:
/// <summary>
/// Return filtered wire transfers
/// </summary>
[HttpGet("wire-transfers")]
[ProducesResponseType(typeof(LoadResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public Task<ActionResult<ProxyLoadResult>> GetAsync(
[BearerTokenFromHeader] string bearerToken,
[RawQueryString] string rawQueryString,
CancellationToken cancellationToken = default) =>
this.TryCatchRefitCallExceptionAsync(
() => _memberCreditorWireTransfersService
.GetAsync(bearerToken, rawQueryString, cancellationToken));
我遵循与 BearerTokenFromHeaderAttribute
相同的逻辑:
RawQueryStringAttribute.cs
:
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)]
public class RawQueryStringAttribute : Attribute, IBindingSourceMetadata, IModelNameProvider
{
public BindingSource BindingSource =>
RawQueryStringBindingSource.Instance;
public string? Name { get; set; }
}
RawQueryStringBindingSource.cs
:
public static class RawQueryStringBindingSource
{
public const string Id = "RawQueryString";
public const string Name = Id;
public static readonly BindingSource Instance = new BindingSource(
Id,
Name,
isGreedy: false,
isFromRequest: true);
}
RawQueryStringValueProvider.cs
:
public class RawQueryStringValueProvider : BindingSourceValueProvider
{
public RawQueryStringValueProvider(BindingSource bindingSource, string rawQueryString) : base(bindingSource) =>
RawQueryString = rawQueryString;
private string RawQueryString { get; }
public override bool ContainsPrefix(string prefix) =>
false;
public override ValueProviderResult GetValue(string key) =>
string.IsNullOrEmpty(key)
? new ValueProviderResult(RawQueryString)
: ValueProviderResult.None;
}
RawQueryStringValueProviderFactory.cs
:
public class RawQueryStringValueProviderFactory : IValueProviderFactory
{
public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
{
var rawQueryString = context.ActionContext.HttpContext.Request?.QueryString.Value;
context.ValueProviders.Add(
new RawQueryStringValueProvider(RawQueryStringBindingSource.Instance,
rawQueryString!));
return Task.CompletedTask;
}
}
但是当控制器动作被调用时:
http://localhost:5000/api/v1/wire-transfers?requireTotalCount=true&skip=0&take=5
我收到以下错误:
{
"errors":{
"rawQueryString":[
"The rawQueryString field is required."
]
},
"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title":"One or more validation errors occurred.",
"status":400,
"traceId":"|dd22ddb4-44ebc27fb1cbc9ba."
}
不确定真正理解为什么,有什么想法吗?
另外为了避免误会,如果我这样做的话:
/// <summary>
/// Return filtered wire transfers
/// </summary>
[HttpGet("wire-transfers")]
[ProducesResponseType(typeof(LoadResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public Task<ActionResult<ProxyLoadResult>> GetAsync(
[BearerTokenFromHeader] string bearerToken,
CancellationToken cancellationToken = default) =>
this.TryCatchRefitCallExceptionAsync(
() => _memberCreditorWireTransfersService
.GetAsync(bearerToken, this.Request.QueryString.Value, cancellationToken));
同样的请求工作正常...
我的观点是我只想将 this.Request.QueryString.Value
作为控制器操作参数。
尝试双星号 (**) catch-all
参数 routes。
像这样的东西应该可以达到你想要的效果:
[HttpGet("wire-transfers/{**rawQueryString}")]
public ... GetAsync(string rawQueryString) { ... }
好吧,问题很简单:
基本上是忘了注册相关的value provider factory(facepalm)...
public void ConfigureServices(IServiceCollection services)
{
// ...
services
.AddMvc(options =>
{
options.EnableEndpointRouting = false;
options.Filters.Add<Filters.LogApiIoContentsActionFilter>();
options.ValueProviderFactories.Add(new BearerTokenValueProviderFactory());
options.ValueProviderFactories.Add(new RawQueryStringValueProviderFactory());
}).AddNewtonsoftJson();
// ...
}
我已经为 BearerTokenFromHeaderAttribute
...做了,但忘记为 RawQueryStringAttribute
做
现在一切都很顺利。
我想将原始查询字符串作为控制器操作参数:
/// <summary>
/// Return filtered wire transfers
/// </summary>
[HttpGet("wire-transfers")]
[ProducesResponseType(typeof(LoadResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public Task<ActionResult<ProxyLoadResult>> GetAsync(
[BearerTokenFromHeader] string bearerToken,
[RawQueryString] string rawQueryString,
CancellationToken cancellationToken = default) =>
this.TryCatchRefitCallExceptionAsync(
() => _memberCreditorWireTransfersService
.GetAsync(bearerToken, rawQueryString, cancellationToken));
我遵循与 BearerTokenFromHeaderAttribute
相同的逻辑:
RawQueryStringAttribute.cs
:
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)]
public class RawQueryStringAttribute : Attribute, IBindingSourceMetadata, IModelNameProvider
{
public BindingSource BindingSource =>
RawQueryStringBindingSource.Instance;
public string? Name { get; set; }
}
RawQueryStringBindingSource.cs
:
public static class RawQueryStringBindingSource
{
public const string Id = "RawQueryString";
public const string Name = Id;
public static readonly BindingSource Instance = new BindingSource(
Id,
Name,
isGreedy: false,
isFromRequest: true);
}
RawQueryStringValueProvider.cs
:
public class RawQueryStringValueProvider : BindingSourceValueProvider
{
public RawQueryStringValueProvider(BindingSource bindingSource, string rawQueryString) : base(bindingSource) =>
RawQueryString = rawQueryString;
private string RawQueryString { get; }
public override bool ContainsPrefix(string prefix) =>
false;
public override ValueProviderResult GetValue(string key) =>
string.IsNullOrEmpty(key)
? new ValueProviderResult(RawQueryString)
: ValueProviderResult.None;
}
RawQueryStringValueProviderFactory.cs
:
public class RawQueryStringValueProviderFactory : IValueProviderFactory
{
public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
{
var rawQueryString = context.ActionContext.HttpContext.Request?.QueryString.Value;
context.ValueProviders.Add(
new RawQueryStringValueProvider(RawQueryStringBindingSource.Instance,
rawQueryString!));
return Task.CompletedTask;
}
}
但是当控制器动作被调用时:
http://localhost:5000/api/v1/wire-transfers?requireTotalCount=true&skip=0&take=5
我收到以下错误:
{
"errors":{
"rawQueryString":[
"The rawQueryString field is required."
]
},
"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title":"One or more validation errors occurred.",
"status":400,
"traceId":"|dd22ddb4-44ebc27fb1cbc9ba."
}
不确定真正理解为什么,有什么想法吗?
另外为了避免误会,如果我这样做的话:
/// <summary>
/// Return filtered wire transfers
/// </summary>
[HttpGet("wire-transfers")]
[ProducesResponseType(typeof(LoadResult), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public Task<ActionResult<ProxyLoadResult>> GetAsync(
[BearerTokenFromHeader] string bearerToken,
CancellationToken cancellationToken = default) =>
this.TryCatchRefitCallExceptionAsync(
() => _memberCreditorWireTransfersService
.GetAsync(bearerToken, this.Request.QueryString.Value, cancellationToken));
同样的请求工作正常...
我的观点是我只想将 this.Request.QueryString.Value
作为控制器操作参数。
尝试双星号 (**) catch-all
参数 routes。
像这样的东西应该可以达到你想要的效果:
[HttpGet("wire-transfers/{**rawQueryString}")]
public ... GetAsync(string rawQueryString) { ... }
好吧,问题很简单:
基本上是忘了注册相关的value provider factory(facepalm)...
public void ConfigureServices(IServiceCollection services)
{
// ...
services
.AddMvc(options =>
{
options.EnableEndpointRouting = false;
options.Filters.Add<Filters.LogApiIoContentsActionFilter>();
options.ValueProviderFactories.Add(new BearerTokenValueProviderFactory());
options.ValueProviderFactories.Add(new RawQueryStringValueProviderFactory());
}).AddNewtonsoftJson();
// ...
}
我已经为 BearerTokenFromHeaderAttribute
...做了,但忘记为 RawQueryStringAttribute
现在一切都很顺利。