Как получить необработанную строку запроса в качестве параметра действия контроллера через привязку модели? - PullRequest
0 голосов
/ 11 января 2020

Я хочу иметь необработанную строку запроса в качестве параметра действия контроллера:

/// <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));

Я следовал тому же логу c, что и для 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 в качестве параметра действия контроллера.

Ответы [ 2 ]

1 голос
/ 11 января 2020

Хорошо, поэтому проблемы были просто просты:

В общем, я забыл зарегистрировать фабрику соответствующего поставщика значений (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

Теперь все работает как шарм.

1 голос
/ 11 января 2020

Попробуйте двойную звездочку (**) catch-all параметр маршруты .

Что-то вроде этого должно сделать трюк, который вы хотите:

[HttpGet("wire-transfers/{**rawQueryString}")]
public ... GetAsync(string rawQueryString) { ... }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...