0

I have a custom middleware class in asp.net web api which processes and sends a response to the client. It is class controller action which actually return a response.

During execution of this GetT function in controller it breaks and returns a ninternal server error 500. We want to handle the internal error 500 and what the exception type was. We still want to send status code 500 error but with a custom error message in the original Response.

Class TResponse, apart from sending data, also sends whether it succeeds or not and some other message can be set if there was a 500 error. But we still want to send this TResponse even after 500 error.

Controller/Action:

public async Task<ActionResult<TResponse>> GetT(TRequest request)
{
.............
    TResponse response = await _tService.GetT(request);
.......
    return Ok(response).
}


public class ResponseMiddleware : IMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var originalBodyStream = context.Response.Body;

        try
        {
            using var memoryStream = new MemoryStream();
            context.Response.Body = memoryStream;

            await next(context);

            memoryStream.Position = 0;
            var reader = new StreamReader(memoryStream);
            var responseBody = await reader.ReadToEndAsync();

            memoryStream.Position = 0;
            await memoryStream.CopyToAsync(originalBodyStream);

            var requestTelemetry = context.Features.Get<RequestTelemetry>();
            requestTelemetry?.Properties.Add("ResponseBody", responseBody);
            Log.Information(responseBody);
        }
    
        catch (Exception ex)
        {
            string exType = ex.GetType().ToString();
            context.Response.StatusCode = 500;
            if (exType=="sql") //Data query error
            {
                context.Response.ContentType = "application/json";

                TResponse response = new TResponse();
               // ???????????
        }
        finally
        {
          context.Response.Body = originalBodyStream;
        }
    }
}

So in the catch block of the InvokeAsync(), I added a try catch block to handle 500 error. I am facing a challenge how to convert a TResponse (after settiing some info on it for 500 related error) object into original body response which somehow gets processed through memory stream just like when there is no error.

In Short, how to handle 500 error and send TResponse from catch block?

I think we want to execute the same line of code in InvokeAsync() even after handling 500 error in order to send correct response.

1
  • Hi @user21225864, you should provide the sample project, so that we could help you narrow down the issue. Please don't forget to hide your sensitive info. Commented Feb 17, 2023 at 3:01

1 Answer 1

-1

Hi @user21225864 you mentioned you want to send status code 500 for internal server error which means exception accrued on server side. To return a custom response this might be one approach. Regardless of where you catch exception. Custom response is returned if exception accrued or not.

Controller:

 [HttpGet]
    [Route("[action]")]
    [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List<CompanyDto>))]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> GetAll()
    {
        var companies = await _compService.GetAllAsync();
        return Ok(companies);
    }

CompanyService:

public async Task<ServiceResponse<List<CompanyDto>>> GetAllAsync()
    {

        ServiceResponse<List<CompanyDto>> _response = new();

        List<CompanyDto> _listCompanyDto = new List<CompanyDto>();

        try
        {

            //Get set of records  from repo
            var CompanyList = await _compRepo.GetAllAsync();

            var CompanyListDto = new List<CompanyDto>();

            foreach (var item in CompanyList)
            {
                CompanyListDto.Add(_mapper.Map<CompanyDto>(item));
            }

            
            _response.Success = true;
            _response.Message = "OK";
            _response.Data = CompanyListDto;

            return _response;

        }
        catch (Exception)
        {
            _response.Success = false;
            _response.Message = "Error";
            _response.Error = "Ininternal server error 500";
            
        }

        return _response;
    }

Custom Response:

/// <summary>
/// Generic wraper around web api service responce.   
/// </summary>
/// <typeparam name="T"></typeparam>
public class ServiceResponse<T>
{

    public T? Data { get; set; }
    public bool Success { get; set; } 
    public string? Message { get; set; } 
    public string? Error { get; set; } 
    
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks Manik. Didn't work . Here response Code Details 500 Undocumented Error: response status is 500 Response headers content-length: 0 date: Fri,17 Feb 2023 01:46:07 GMT server: Kestrel Any idea, why response header is blank. ?
I think response coming blank because it was not sent to memory stream. I think response for 500 error should be written same like when there was no error, Here I don't think the response can be using response.WriteAsync from middleware itself. it won't work. you custom response should be added in ResponseBody property.
I think there should be an exception filter outside of middleware. any thought ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.