GVKun编程网logo

HttpPost 多次执行 async .FromSqlRaw 即使它在 Web 应用程序中只调用一次

4

如果您想了解HttpPost多次执行async.FromSqlRaw即使它在Web应用程序中只调用一次的知识,那么本篇文章将是您的不二之选。同时我们将深入剖析ASP.NETCore3.1WebApiH

如果您想了解HttpPost 多次执行 async .FromSqlRaw 即使它在 Web 应用程序中只调用一次的知识,那么本篇文章将是您的不二之选。同时我们将深入剖析ASP.NET Core 3.1 Web Api HttpPost Action 参数无法接收 axios application/json HttpPost 传递数据、asp.net-mvc – [HttpPost] public ActionResult Create(FormCollection collection)VERSUS [HttpPost] public ActionResult Create(Dinner dinner)、Async / Await, Task.Run(async() => await), await Task.Run(()=>), await Task.Run(async() => await) 区别、C# 5.0 async void vs async Task的各个方面,并给出实际的案例分析,希望能帮助到您!

本文目录一览:

HttpPost 多次执行 async .FromSqlRaw 即使它在 Web 应用程序中只调用一次

HttpPost 多次执行 async .FromSqlRaw 即使它在 Web 应用程序中只调用一次

如何解决HttpPost 多次执行 async .FromSqlRaw 即使它在 Web 应用程序中只调用一次

我有一个 .NET 5/aspnetcore/blazor 服务器 Web 应用程序,应用程序的前端/后端通过应用程序内的 API 层进行通信。

当我在前端调用 API 时,该调用只发出一次(我已经验证了这一点),但在 HttpPost 任务中,dbContext 被查询多次(在我的情况下,每个 API 调用 4 次)。不知道为什么会发生这种情况,希望社区提供任何形式的见解。

这是我的 .razor 文件。如果我在异步 API 请求上设置断点,它只会执行一次。

private async Task FetchData()
{
    var result = await Client.GetData(_page,_pageSize);
}

这是我的数据访问代码。如果我在 var response = await _dbContext.Data.FromsqlRaw 上设置断点,它会被击中 4 次。

[HttpPost("/Api/Data/GetData")]
public async Task<IActionResult> GetData([FromQuery] int currentPage,[FromQuery] int currentPageSize)
{
    PagedResponse<List<DataDto>> pagedData = new PagedResponse<List<DataDto>>(new List<DataDto>(),currentPage,currentPageSize);

    var route = Request.Path.Value;
    var filterOut = new PaginationFilter(currentPage,currentPageSize,null,null);
    int countResult = 0;

    //////////////////////////////////////////////////////////////////////////////////////////
    //get paginated set
    //////////////////////////////////////////////////////////////////////////////////////////
    try
    {
        sqlParameter[] parameters =
        {
                new sqlParameter
                {
                    sqlDbType = sqlDbType.Int,Direction = ParameterDirection.Input,ParameterName = "pageNumber",Value = currentPage
                },new sqlParameter
                {
                    sqlDbType = sqlDbType.Int,ParameterName = "pageSize",Value = currentPageSize
                },Direction = ParameterDirection.Output,ParameterName = "countResult",Value = countResult
                }
            };

        var response = await _dbContext.Data.FromsqlRaw("Execute dbo.sp_GetDataForFilter @pageNumber,@pageSize,@countResult OUTPUT",parameters).AsNoTracking().ToListAsync();
        countResult = (int)parameters.Where(x => x.ParameterName == "countResult").FirstOrDefault().Value;

        List<DataDto> responseDto = new List<DataDto>();
        foreach (var item in response)
        {
            responseDto.Add(new DataDto(item));
        }

        //////////////////////////////////////////////////////////////////////////////////////////
        //build pagedReponse
        //////////////////////////////////////////////////////////////////////////////////////////
        pagedData = PaginationHelper.CreatePagedReponse(responseDto,filterOut,countResult,_uriService,route);
        return Ok(pagedData);
    }
    catch (Exception e)
    {
        //Handle error
    }
}

编辑(每个 Henk)---------

这是我的AuthorizationMessageHandler

class AuthorizationMessageHandler : DelegatingHandler
{
    private readonly AppStateService _appState;
    private readonly ILogger<AuthorizationMessageHandler> _logger;

    public AuthorizationMessageHandler(
        AppStateService appState,ILogger<AuthorizationMessageHandler> logger)
    {
        _appState = appState;
        _logger = logger;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)
    {
        HttpResponseMessage httpResponseMessage;
        try
        {
            if (string.IsNullOrWhiteSpace(_appState?.AuthenticationCookie) == false)
            {
                request.Headers.Add(HeaderNames.Cookie,_appState.AuthenticationCookie);
            }

            httpResponseMessage = await base.SendAsync(request,cancellationToken);
            httpResponseMessage.EnsureSuccessstatusCode();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex,"Failed to run http query {RequestUri}",request.RequestUri);
            throw;
        }

        return httpResponseMessage;
    }
}

这里是我在 Startup.cs

中初始化 Http 的地方
private static void InitializeHttp(IServiceCollection services,ServiceConfiguration serviceConfiguration)
{
    services.AddTransient<AuthorizationMessageHandler>();

    AsyncRetryPolicy<HttpResponseMessage> retryPolicy = HttpPolicyExtensions
        .HandleTransientHttpError()
        .Or<TimeoutRejectedException>()
        .WaitAndRetryAsync(serviceConfiguration.Http.Retry,_ => TimeSpan.FromMilliseconds(serviceConfiguration.Http.Wait));

    AsyncTimeoutPolicy<HttpResponseMessage> timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromMilliseconds(serviceConfiguration.Http.Timeout));

    // discover all Iapiclient implementations and configure a Refit http client for each.
    var apiclientInterfaceType = typeof(Iapiclient);
    var types = AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(t => t.GetTypes())
        .Where(t => apiclientInterfaceType.IsAssignableFrom(t) && t.IsInterface);

    foreach (var type in types)
    {
        // We have to do this nonsense,because there is a bug in AddRefitClient (non-generic version)
        // where it does not properly register the client.
        MethodInfo method = typeof(Refit.HttpClientFactoryExtensions).getmethods()
            .FirstOrDefault(m =>
                m.Name.Equals(nameof(Refit.HttpClientFactoryExtensions.AddRefitClient),StringComparison.OrdinalIgnoreCase) &&
                m.IsGenericmethod);
        MethodInfo generic = method?.MakeGenericmethod(type);

        IHttpClientBuilder builder = (IHttpClientBuilder)generic?.Invoke(null,new object[] { services,null });

        builder.ConfigureHttpClient(c => c.BaseAddress = new Uri(serviceConfiguration.Application.BaseUrl))
            .AddPolicyHandler(retryPolicy)
            .AddPolicyHandler(timeoutPolicy)
            .AddHttpMessageHandler<AuthorizationMessageHandler>();
    }
}

ASP.NET Core 3.1 Web Api HttpPost Action 参数无法接收 axios application/json HttpPost 传递数据

ASP.NET Core 3.1 Web Api HttpPost Action 参数无法接收 axios application/json HttpPost 传递数据

如何解决ASP.NET Core 3.1 Web Api HttpPost Action 参数无法接收 axios application/json HttpPost 传递数据

我曾经使用 Controller 而不是 ApiController,今天我尝试使用 ApiController 并发现以下问题。

ASP.NET Core Web Api HttpPost Action 参数无法接收 axios application/json 后传递数据

asp.net 核心 api 代码

  1. [ApiController]
  2. [Route("[controller]")]
  3. public class TestController : ControllerBase
  4. {
  5. [HttpPost]
  6. public async Task<IActionResult> Post(string json)
  7. {
  8. return this.Ok();
  9. }
  10. }

前端

  1. var json = ''{"json_data":"{\\"value\\":\\"hello world\\"}'';
  2. axios.post(''Test'',{"json": json})
  3. .then(function (response) {
  4. console.log(response);
  5. })
  6. .catch(function (error) {
  7. console.log(error);
  8. });

实际请求

  1. Accept:application/json,text/plain,*/*
  2. Accept-Encoding: gzip,deflate,br
  3. Content-Type: application/json;charset=UTF-8
  4. Request Payload :
  5. {"json_data":"{\\"value\\":\\"hello world\\"}

实际动作json参数数据为null 预期接收数据:{"json_data":"{\\"value\\":\\"hello world\\"}


更新

我尝试了下面的代码,我得到 rawValue value = {"json_data":"{\\"value\\":\\"hello world\\"} 但 json value = null

  1. [HttpPost]
  2. public async Task<IActionResult> Post(string json)
  3. {
  4. using (StreamReader reader = new StreamReader(Request.Body,Encoding.UTF8))
  5. {
  6. string rawValue = await reader.ReadToEndAsync();
  7. }
  8. }

解决方法

公共异步任务发布(字符串json)

如果您想从前端使用数据进行 HTTP 请求并将其正确绑定到 string-type ACTION 参数,您可以尝试实现并使用自定义纯文本输入格式化程序。

  1. public class TextPlainInputFormatter : TextInputFormatter
  2. {
  3. public TextPlainInputFormatter()
  4. {
  5. SupportedMediaTypes.Add("text/plain");
  6. SupportedEncodings.Add(UTF8EncodingWithoutBOM);
  7. SupportedEncodings.Add(UTF16EncodingLittleEndian);
  8. }
  9. protected override bool CanReadType(Type type)
  10. {
  11. return type == typeof(string);
  12. }
  13. public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context,Encoding encoding)
  14. {
  15. string data = null;
  16. using (var streamReader = new StreamReader(context.HttpContext.Request.Body))
  17. {
  18. data = await streamReader.ReadToEndAsync();
  19. }
  20. return InputFormatterResult.Success(data);
  21. }
  22. }

配置和添加自定义格式化程序支持

  1. services.AddControllers(opt => opt.InputFormatters.Insert(0,new TextPlainInputFormatter()));

前端代码

  1. const headers = {
  2. ''Content-Type'': ''text/plain''
  3. };
  4. var json = ''{"json_data":"{\\"value\\":\\"hello world\\"}'';
  5. axios.post(''test'',json,{ headers: headers })
  6. .then(function (response) {
  7. //...

测试结果

enter image description here

,

更新:

Demo Source Code Link

我终于用[FromBody]System.Text.Json.JsonElement解决了问题

  1. [HttpPost]
  2. [Route("TestUsingFromBodyAttribute")]
  3. public object TestUsingFromBodyAttribute([FromBody] System.Text.Json.JsonElement content)
  4. {
  5. return content;
  6. }

因为 axios 默认Content-Type: application/x-www-form-urlencoded 需要更新Content-Type'': ''application/json,否则系统会显示415 unsupported media type

image

然后它不能使用string类型或系统会显示400 bad request

image

因为asp.net核心检查Content-Type'': ''application/json并使用[FromBody]会自动转换为json对象(System.Text.Json.JsonElement),所以不能使用字符串类型。 image

如果不想编辑axios default Content-Type: application/x-www-form-urlencoded,必须设置reqeust data is object not string

image

阅读:

  • https://weblog.west-wind.com/posts/2017/sep/14/accepting-raw-request-body-content-in-aspnet-core-api-controllers

早期回答:

现在我用Request.Body而不是Action Parameter来解决这个问题,但是我还是不知道为什么它做不到。

  1. [HttpPost]
  2. public async Task<IActionResult> Post()
  3. {
  4. string json = null;
  5. using (StreamReader reader = new StreamReader(Request.Body,Encoding.UTF8))
  6. {
  7. json = await reader.ReadToEndAsync();
  8. }
  9. //..etc
  10. }
,

您应该使用 FromBodyAttribute 进行正确映射。

asp.net-mvc – [HttpPost] public ActionResult Create(FormCollection collection)VERSUS [HttpPost] public ActionResult Create(Dinner dinner)

asp.net-mvc – [HttpPost] public ActionResult Create(FormCollection collection)VERSUS [HttpPost] public ActionResult Create(Dinner dinner)

在Scott Hanselman的书(第1章)中,他为我们提供了两个实现[HttpPost] for Create action方法的选项.

第一个依赖于TryUpdateModel来根据传入的表单字段更新模型对象.当传入的表单字段包含无效输入时,ModelState.IsValid将设置为false.

[HttpPost]
        public ActionResult Create(FormCollection collection)
        {
            Dinner dinner = new Dinner();

            if (TryUpdateModel(dinner))
            {
                dinnerRepository.Add(dinner);

                dinnerRepository.Save();

                return RedirectToAction("Details",new { id = dinner.DinnerId });
            }
            else
                return View(dinner);

        }

第二种方法是利用作为Create action方法arg传递的模型如下:

[HttpPost]
        public ActionResult Create(Dinner dinner)
        {
            if (ModelState.IsValid)
            {
                dinnerRepository.Add(dinner);

                dinnerRepository.Save();

                return RedirectToAction("Details",new { id = dinner.DinnerId });
            }
            else
                return View(dinner);
        }

哪一个更适合在生产中使用?

解决方法@H_301_23@
如果所有必需的数据都在Request.Form,路由数据或URL查询字符串中,那么您可以使用模型绑定,如第二个示例中所示.

模型绑定器创建您的晚餐对象,并通过匹配属性名称使用请求中的数据填充它.

您可以使用“白名单”,“黑名单”,前缀和标记界面自定义绑定过程.
只要确保你没有无意中绑定值 – 请参阅此link.

Async / Await, Task.Run(async() => await), await Task.Run(()=>), await Task.Run(async() => await) 区别

Async / Await, Task.Run(async() => await), await Task.Run(()=>), await Task.Run(async() => await) 区别

如何解决Async / Await, Task.Run(async() => await), await Task.Run(()=>), await Task.Run(async() => await) 区别

嗨,我是 Xamarin 开发人员

我有一些关于使用异步编程的问题

当我调用 Webservice 时,我通常使用 async/await。

但是,如果它只使用一个线程(UI),那么在 UI 更改时会导致一些问题。

例如,在获取价值之前先处理代码,有时会挂起UI

我阅读了一些关于异步编程的文档或博客。这表明您可以解决使用 Task.RUN 时的问题

但是很难知道我的编程水平.....

这是一些例子,你能解释一下有什么不同吗?

notificationVos = await Task.Run(() => wSSmartConsoleCommon.getScmessage<NotificationVo>());

notificationVos = Task.Run(() => wSSmartConsoleCommon.getScmessage<NotificationVo>());

notificationVos = await wSSmartConsoleCommon.getScmessage<NotificationVo>());

notificationVos = await Task.Run(async() => await wSSmartConsoleCommon.getScmessage<NotificationVo>());

C# 5.0 async void vs async Task

C# 5.0 async void vs async Task

 1  private void button1_Click(object sender, EventArgs e)
 2         {
 3             TestReturnsVoid();//会在UI Thread抛出异常,导致程序崩溃
 4         }
 5 
 6         private void button2_Click(object sender, EventArgs e)
 7         {
 8             TestReturnsTask();//会在另外一个线程抛出异常,类似TheadPool的效果
 9         }
10 
11         private async void TestReturnsVoid()
12         {
13             await Test();
14         }
15 
16         private async Task TestReturnsTask()
17         {
18             await Test();
19         }
20 
21         private async Task Test()
22         {
23             throw new NotImplementedException();
24         }

结论
1. async void 仅仅推荐用在UI event handler
2.总是处理事件 : TaskScheduler.UnobservedTaskException

 

我们今天的关于HttpPost 多次执行 async .FromSqlRaw 即使它在 Web 应用程序中只调用一次的分享已经告一段落,感谢您的关注,如果您想了解更多关于ASP.NET Core 3.1 Web Api HttpPost Action 参数无法接收 axios application/json HttpPost 传递数据、asp.net-mvc – [HttpPost] public ActionResult Create(FormCollection collection)VERSUS [HttpPost] public ActionResult Create(Dinner dinner)、Async / Await, Task.Run(async() => await), await Task.Run(()=>), await Task.Run(async() => await) 区别、C# 5.0 async void vs async Task的相关信息,请在本站查询。

本文标签: