Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

when PUT and receive 204 NoContent AutoWrapper will intercepted an Unhandle error. #30

Closed
larssonsun opened this issue Feb 17, 2020 · 13 comments
Labels
bug

Comments

@larssonsun
Copy link

@larssonsun larssonsun commented Feb 17, 2020

After sending a PUT request, when the server receive 204 NoContent it will intercepted an error

Put Action in ProductController.cs:

[HttpPut("{productId}")]
        public async Task<IActionResult> UpdateProduct(Guid productId, [FromBody]ProductUpdateDTO productUpdateDTO)
        {
            if (productUpdateDTO == null)
            {
                return BadRequest();
            }

            if (!ModelState.IsValid)
            {
                return new UnprocessableEntityObjectResult(ModelState); // larsson:如果要自定义422之外的响应则需要新建一个类继承UnprocessableEntityObjectResult
            }

            var result = await _repository.TryGetProduct(productId);
            if (!result.hasProduct)
            {
                return NotFound();
            }

            _mapper.Map(productUpdateDTO, result.product);
            _repository.UpdateProduct(result.product);

            if (!await _unitOfWork.SaveAsync())
            {
                return StatusCode(500, "Updating product field.");
            }

            return NoContent();
        }

startup.cs:

...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseApiResponseAndExceptionWrapper(new AutoWrapperOptions { ShowStatusCode = true });

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
...

error:

fail: AutoWrapper.AutoWrapperMiddleware[0]
      [500]: Unhandled Exception occurred. Unable to process the request.
System.InvalidOperationException: Writing to the response body is invalid for responses with status code 204.
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowWritingToResponseBodyNotSupported()
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.Advance(Int32 bytes)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponsePipeWriter.Advance(Int32 bytes)
   at Microsoft.AspNetCore.Http.HttpResponseWritingExtensions.Write(HttpResponse response, String text, Encoding encoding)
   at Microsoft.AspNetCore.Http.HttpResponseWritingExtensions.WriteAsync(HttpResponse response, String text, Encoding encoding, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.HttpResponseWritingExtensions.WriteAsync(HttpResponse response, String text, CancellationToken cancellationToken)
   at AutoWrapper.AutoWrapperMembers.WriteFormattedResponseToHttpContext(HttpContext context, Int32 code, String jsonString, Boolean isError)
   at AutoWrapper.AutoWrapperMembers.HandleNotSuccessRequestAsync(HttpContext context, Object body, Int32 code)
   at AutoWrapper.Base.WrapperBase.InvokeAsyncBase(HttpContext context, AutoWrapperMembers awm)
info: AutoWrapper.AutoWrapperMiddleware[0]
      Source:[::1] Request: PUT http localhost:5000/product/c632690e-1784-45b9-9e98-69ad427575c3  {
        "name":"aaaaa",
        "description":"bbb.",
        "isonsale":false,
        "createtime":"2020-2-17"
} Responded with [204] in 157ms
fail: Microsoft.AspNetCore.Server.Kestrel[13]
      Connection id "0HLTJBD08K61J", Request id "0HLTJBD08K61J:00000002": An unhandled exception was thrown by the application.
System.InvalidOperationException: StatusCode cannot be set because the response has already started.
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowResponseAlreadyStartedException(String value)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.set_StatusCode(Int32 value)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.Microsoft.AspNetCore.Http.Features.IHttpResponseFeature.set_StatusCode(Int32 value)
   at Microsoft.AspNetCore.Http.DefaultHttpResponse.set_StatusCode(Int32 value)
   at AutoWrapper.AutoWrapperMembers.WriteFormattedResponseToHttpContext(HttpContext context, Int32 code, String jsonString, Boolean isError)
   at AutoWrapper.AutoWrapperMembers.HandleExceptionAsync(HttpContext context, Exception exception)
   at AutoWrapper.Base.WrapperBase.InvokeAsyncBase(HttpContext context, AutoWrapperMembers awm)
   at AutoWrapper.AutoWrapperMiddleware.InvokeAsync(HttpContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
@proudmonkey

This comment has been minimized.

Copy link
Owner

@proudmonkey proudmonkey commented Feb 18, 2020

hi @larssonsun,

I'll look into this. Thank for your continued feedback! I appreciate it.

@arhen

This comment has been minimized.

Copy link
Contributor

@arhen arhen commented Feb 18, 2020

I got similar error to thhis too when trying to response with NoContent() althoug the process is successful.

connection id "0HLTK3N5ROEON", Request id "0HLTK3N5ROEON:00000001": An unhandled exception was thrown by the application.
System.InvalidOperationException: StatusCode cannot be set because the response has already started.
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowResponseAlreadyStartedException(String value)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.set_StatusCode(Int32 value)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.Microsoft.AspNetCore.Http.Features.IHttpResponseFeature.set_StatusCode(Int32 value)
   at Microsoft.AspNetCore.Http.DefaultHttpResponse.set_StatusCode(Int32 value)
   at AutoWrapper.AutoWrapperMembers.WriteFormattedResponseToHttpContext(HttpContext context, Int32 code, String jsonString, Boolean isError)
   at AutoWrapper.AutoWrapperMembers.HandleExceptionAsync(HttpContext context, Exception exception)
   at AutoWrapper.Base.WrapperBase.InvokeAsyncBase(HttpContext context, AutoWrapperMembers awm)
   at AutoWrapper.AutoWrapperMiddleware.InvokeAsync(HttpContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

@proudmonkey

This comment has been minimized.

Copy link
Owner

@proudmonkey proudmonkey commented Feb 18, 2020

Guys,

What version you are at? I'm trying to replicate the issue to no avail. Here's the logs i'm getting:

2020-02-17T22:29:07.6686562-06:00 [INF] () Starting web host
2020-02-17T22:29:09.4620893-06:00 [INF] (AutoWrapper.AutoWrapperMiddleware) Source:[::1] Request: GET https localhost:44321/api/values   Responded with [404] in 250ms
2020-02-17T22:29:13.7926189-06:00 [INF] (AutoWrapper.AutoWrapperMiddleware) Source:[::1] Request: PUT https localhost:44321/api/v1/persons/1  {
  "firstName": "Vianne Maverich",
  "lastName": "Durano",
  "dateOfBirth": "2019-09-27T23:27:50.076Z"
} Responded with [204] in 271ms
2020-02-17T22:29:14.6501480-06:00 [INF] (AutoWrapper.AutoWrapperMiddleware) Source:[::1] Request: PUT https localhost:44321/api/v1/persons/1  {
  "firstName": "Vianne Maverich",
  "lastName": "Durano",
  "dateOfBirth": "2019-09-27T23:27:50.076Z"
} Responded with [204] in 15ms
2020-02-17T22:29:16.3375676-06:00 [INF] (AutoWrapper.AutoWrapperMiddleware) Source:[::1] Request: PUT https localhost:44321/api/v1/persons/1  {
  "firstName": "Vianne Maverich",
  "lastName": "Durano",
  "dateOfBirth": "2019-09-27T23:27:50.076Z"
} Responded with [204] in 12ms

@arhen

This comment has been minimized.

Copy link
Contributor

@arhen arhen commented Feb 18, 2020

What version you are at? I'm trying to replicate the issue to no avail. Here's the logs i'm getting:

V3.1

@proudmonkey

This comment has been minimized.

Copy link
Owner

@proudmonkey proudmonkey commented Feb 18, 2020

I mean version of AutoWrapper. :)

@arhen

This comment has been minimized.

Copy link
Contributor

@arhen arhen commented Feb 18, 2020

Guys,

What version you are at? I'm trying to replicate the issue to no avail. Here's the logs i'm getting:

2020-02-17T22:29:07.6686562-06:00 [INF] () Starting web host
2020-02-17T22:29:09.4620893-06:00 [INF] (AutoWrapper.AutoWrapperMiddleware) Source:[::1] Request: GET https localhost:44321/api/values   Responded with [404] in 250ms
2020-02-17T22:29:13.7926189-06:00 [INF] (AutoWrapper.AutoWrapperMiddleware) Source:[::1] Request: PUT https localhost:44321/api/v1/persons/1  {
  "firstName": "Vianne Maverich",
  "lastName": "Durano",
  "dateOfBirth": "2019-09-27T23:27:50.076Z"
} Responded with [204] in 271ms
2020-02-17T22:29:14.6501480-06:00 [INF] (AutoWrapper.AutoWrapperMiddleware) Source:[::1] Request: PUT https localhost:44321/api/v1/persons/1  {
  "firstName": "Vianne Maverich",
  "lastName": "Durano",
  "dateOfBirth": "2019-09-27T23:27:50.076Z"
} Responded with [204] in 15ms
2020-02-17T22:29:16.3375676-06:00 [INF] (AutoWrapper.AutoWrapperMiddleware) Source:[::1] Request: PUT https localhost:44321/api/v1/persons/1  {
  "firstName": "Vianne Maverich",
  "lastName": "Durano",
  "dateOfBirth": "2019-09-27T23:27:50.076Z"
} Responded with [204] in 12ms

Are you using return NoContent() at the end?

@arhen

This comment has been minimized.

Copy link
Contributor

@arhen arhen commented Feb 18, 2020

I mean version of AutoWrapper. :)

Last version, 3.0

@proudmonkey

This comment has been minimized.

Copy link
Owner

@proudmonkey proudmonkey commented Feb 18, 2020

Are you using return NoContent() at the end?

Yes:

[Route("{id:long}")]
[HttpPut]
public async Task<IActionResult> Put(long id, [FromBody] PersonDTO dto)
{
            return NoContent();
}

I also tried with GET.

@arhen

This comment has been minimized.

Copy link
Contributor

@arhen arhen commented Feb 18, 2020

Are you using return NoContent() at the end?

Yes:

[Route("{id:long}")]
[HttpPut]
public async Task<IActionResult> Put(long id, [FromBody] PersonDTO dto)
{
            return NoContent();
}

I also tried with GET.

This is weird. I also tried it using get and got same error.
I also try to build AutoWrapper from source code and still got same error.
I've tracked the error and explain it a little bit on my PR.

Are you using VS? I'm using Rider. Maybe there are difference debug level information beetween those 2 IDE?

@proudmonkey

This comment has been minimized.

Copy link
Owner

@proudmonkey proudmonkey commented Feb 18, 2020

Are you using VS?

Yes.

I don't know what's going on but I've merged your PR. Thank you. It should be included in the next release.

@proudmonkey proudmonkey added the bug label Feb 18, 2020
@proudmonkey

This comment has been minimized.

Copy link
Owner

@proudmonkey proudmonkey commented Feb 18, 2020

@arhen

Just an FYI, I've updated the conditional check from your PR:

From this:

 if (context.Response.StatusCode != Status304NotModified && context.Response.StatusCode != Status204NoContent)

To this:

 if (context.Response.StatusCode != Status304NotModified || context.Response.StatusCode != Status204NoContent)

The OR conditional statement makes sense as the StatusCodes will be evaluated one at each request.

@proudmonkey

This comment has been minimized.

Copy link
Owner

@proudmonkey proudmonkey commented Feb 26, 2020

Just released a new version that comes with a fix for this issue. You can find it here: AutoWrapper Now Supports Problem Details For Your ASP.NET Core APIs

Thank you so much for all your suggestions!

@arhen

This comment has been minimized.

Copy link
Contributor

@arhen arhen commented Feb 26, 2020

Finally, ProblemDetails 💃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants
You can’t perform that action at this time.