2

リクエスト本文を読み取り、行ごとに分割して、コントローラーアクションの文字列配列パラメーターに渡す独自の入力フォーマッターを作成しようとしています。


これは機能します(本体全体を文字列として渡します):

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvcCore(options =>
    {
        options.InputFormatters.Add(new MyInputFormatter());
    }
}


MyInputFormatter.cs

public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
    using (StreamReader reader = new StreamReader(context.HttpContext.Request.Body))
    {
        return InputFormatterResult.Success(await reader.ReadToEndAsync());
    }
}

MyController.cs

[HttpPost("/foo", Name = "Foo")]
public IActionResult Bar([FromBody] string foo)
{
    return Ok(foo);
}

これは機能しません (パラメーター foo が null です):

MyInputFormatter.cs

public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
    List<string> input = new List<string>();

    using (StreamReader reader = new StreamReader(context.HttpContext.Request.Body))
    {
        while (!reader.EndOfStream)
        {
            string line = (await reader.ReadLineAsync()).Trim();
            input.Add(line);
        }
    }

    return InputFormatterResult.Success(input.ToArray());
}

MyController.cs

[HttpPost("/foo", Name = "Foo")]
public IActionResult Bar([FromBody] string[] foo)
{
    return Ok(string.Join(" ", foo));
}

違いは、コントローラーでは文字列の代わりに文字列の配列を受け入れるようになり、フォーマッターでは入力を 1 行ずつ読み取り、最終的に配列として返すことです。


私は何が欠けていますか?:/


編集:多かれ少なかれ、私のフォーマッタが実際にどのように見えるか(違いがある場合):

    public class MyInputFormatter : InputFormatter
    {
        public MyInputFormatter()
        {
            this.SupportedMediaTypes.Add(new MediaTypeHeaderValue(MimeType.URI_LIST)); // "text/uri-list"
        }

        public override bool CanRead(InputFormatterContext context)
        {
            if (context == null) throw new ArgumentNullException(nameof(context)); // breakpoint here not reached

            if (context.HttpContext.Request.ContentType == MimeType.URI_LIST)
                return true;

            return false;
        }

        protected override bool CanReadType(Type dataType)
        {
            return typeof(string[]).IsAssignableFrom(dataType); // breakpoint here not reached
        }

        public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
        {
            List<string> input = new List<string>(); // breakpoint here not reached

            using (StreamReader reader = new StreamReader(context.HttpContext.Request.Body))
            {
                while (!reader.EndOfStream)
                {
                    string line = (await reader.ReadLineAsync()).Trim();

                    if (string.IsNullOrEmpty(line))
                    {
                        continue;
                    }

                    if (!line.StartsWith("foo-"))
                    {
                        return InputFormatterResult.Failure();
                    }

                    input.Add(line.Substring("foo-".Length));
                }
            }

            return InputFormatterResult.Success(input.ToArray());
        }
4

2 に答える 2

0

リクエストハンドラーメソッドでコードを使用してテスト入力フォーマッターを作成しましたが、正常に動作します。これは次のようになります。

public class TestInputFormatter : IInputFormatter
{
    public bool CanRead(InputFormatterContext context) => true;

    public async Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
    {
        List<string> input = new List<string>();

        using (StreamReader reader = new StreamReader(context.HttpContext.Request.Body))
        {
            while (!reader.EndOfStream)
            {
                string line = (await reader.ReadLineAsync()).Trim();
                input.Add(line);
            }
        }

        return InputFormatterResult.Success(input.ToArray());
    }
}

コードで間違っている可能性があるのは、入力フォーマッタの登録だけです。ドキュメンテーションは次のように述べています:フォーマッタは、挿入した順に評価されます。最初のものが優先されます。 そのように登録してみてください:

options.InputFormatters.Insert(0, new TestInputFormatter());

私のテストプロジェクトでは、まさにそのような登録で機能します。呼び出すoptions.InputFormatters.Addと、入力フォーマッタ コレクションの最後に追加され、おそらくそのコレクションの最初にある他の入力フォーマッタによってリクエストが処理されるためです。

于 2019-08-05T21:50:38.540 に答える