'Consuming a Web API in ASP.NET MVC using HttpClient. The response message is not what is sent back to the client from the web api

To consume a Web API in ASP.NET MVC server side I am using 'HttpClient'. HttpClient sends a request to the Web API and receives a response. Then I convert the response data that came from the Web API to a model and then render it into a view.

The problem is when there is an error in the web api, my client is not receiving the custom error message that was sent. The web api sends a status code = 400 and a ReasonPhrase with my custom message, but when it gets to the client, it is a status code = 500 and the ReasonPhrase = 'Internal Server error'.

Why?

Web api code - the WebApi2Controller method called by the client which calls a data access layer then sends result back to client:

    [HttpPost] 
    [Route("getbloggersinfo/{argsData}/")]
    public IHttpActionResult GetBloggersInfo(ArgsToPassToApi argsToPassToApi)
    {
        IHttpActionResult httpActionResult;
        HttpResponseMessage httpResponseMessage;

        try
        {
            BloggerInfoResults bloggerInfoResults = new BloggerInfoResults();

            bloggerInfoResults = dataAccessLayer.GetBloggersInfo(argsToPassToApi.UserName, argsToPassToApi.IpAddress);

            httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK, bloggerInfoResults);
        }
        catch (Exception ex)
        {
            httpResponseMessage = Request.CreateResponse(HttpStatusCode.BadRequest);

            httpResponseMessage.ReasonPhrase = ex.Message;
        }

        httpActionResult = ResponseMessage(httpResponseMessage);

        return httpActionResult;
    }

The web api code - the data access layer method called by the WebApi2Controller:

        public BloggerInfoResults GetBloggersInfo(string userName, string ipAddress)
    {
        string userFriendlyMessage = "Unable to get the Blogger's info. We have been notified and are working to resolve this. Please do not continue.";

        BloggerInfoResults bloggerInfoResults = new BloggerInfoResults();
        SqlDataReader bloggerInfoDataReader = null;

        try
        {
            dbFunc.OpenDB();

            SqlCommand cmd = new SqlCommand("dbo.GetBloggersInfo", dbFunc.objConn);
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Clear();

            cmd.Parameters.AddWithValue("@a_UserName", userName);
            cmd.Parameters.AddWithValue("@a_IpAddress", ipAddress);

            bloggerInfoDataReader = cmd.ExecuteReader();

            while (bloggerInfoDataReader.Read())
            { 
                bloggerInfoResults.UserId = Convert.ToInt32(bloggerInfoDataReader["UserId"]);
                bloggerInfoResults.UserName = bloggerInfoDataReader["UserName"].ToString();
                bloggerInfoResults.HasProfileSwitch = Convert.ToBoolean(bloggerInfoDataReader["HasProfileSwitch"]);
            }

            return bloggerInfoResults;
        }
        catch (SqlException sqlex)
        {
            if (sqlex.Message.Contains("Critical"))
            {
                // A "critical" error coming from the stored procedure.

                currentDateTime = DateTime.Now;
                sendAlertEmailResult = SendAlertEmailToStaff(currentDateTime, userName, ipAddress);

                if (sendAlertEmailResult == "")
                {
                    // The alert email was sent successfully. 

                    // Throw - for setting the UI. Send a user friendly message.
                    throw new Exception(userFriendlyMessage);
                }
                else
                {
                    // Not sent successfully. I have no choice but to send the verbose message as it was NOT stored in the error log and I will need to see it 
                    // when debugging.
                    // Throw - for setting the UI.
                    throw new Exception(criticalErrorPrepend + "Error in DataAccessLayer/GetBloggersInfo(). Sending an alert email for the initial sql exception error: " + sqlex.Message + ". Now getting this error: " + sendAlertEmailResult);
                }
            }
            else
            {
                // Not coming from the stored procedure. Like if the stored procedure above was not named properly, does not exist, parameter missing, etc.

                errorMessage = "Sql Exception Error in DataAccessLayer/GetBloggersInfo(). Using 'GetBloggersInfo' s/p. Error: " + sqlex.Message;

                // Log the error and send an alert email.
                currentDateTime = DateTime.Now;
                processErrorLogAndSendAlertEmailResult = ProcessErrorLogAndSendAlertEmail(currentDateTime, userName, errorMessage, additionalInfoForLog, ipAddress);

                if (processErrorLogAndSendAlertEmailResult != "")
                {
                    // Throw - for setting the UI.
                    throw new Exception(criticalErrorPrepend + "Error in DataAccessLayer/GetBloggersInfo(). Using 'GetBloggersInfo' s/p. Logging the initial sql exception error: " + sqlex.Message + ". Now getting this error: " + processErrorLogAndSendAlertEmailResult);
                }
                else
                {
                    // Throw - for setting the UI. Send a user friendly message.
                    throw new Exception(userFriendlyMessage);
                }
            }
        }
        catch (Exception ex)
        {
            errorMessage = "Error in DataAccessLayer/GetBloggersInfo(). Using 'GetBloggersInfo' s/p. Error: " + ex.Message;

            // Log the error and send an alert email.
            currentDateTime = DateTime.Now;
            processErrorLogAndSendAlertEmailResult = ProcessErrorLogAndSendAlertEmail(currentDateTime, userName, errorMessage, additionalInfoForLog, ipAddress);

            if (processErrorLogAndSendAlertEmailResult != "")
            {
                // Throw - for setting the UI.
                throw new Exception(criticalErrorPrepend + "Error in DataAccessLayer/GetBloggersInfo(). Using 'GetBloggersInfo' s/p. Logging the initial error: " + ex.Message + ". Now getting this error: " + processErrorLogAndSendAlertEmailResult);
            }
            else
            {
                // Throw - for setting the UI. Send a user friendly message.
                throw new Exception(userFriendlyMessage);
            }
        }
        finally
        {
            if (bloggerInfoDataReader != null)
            {
                // Close the reader.
                bloggerInfoDataReader.Close();
            }

            // Close the database.
            dbFunc.CloseDB();
        }
    }     

The custom message being thrown (throw new Exception (....)) from the data access layer method back to the WebApi2Controller method (my custom message):

enter image description here

The error being sent to the client from the WebApi2Controller (a status code = 400 and ReasonPhrase with my custom message):

enter image description here

The client code which calls the web api controller method using httpclient:

    public async Task<BloggerInfoResults> GetBloggersInfo(string userName, string webApiUrl, string myIpAddress)
    {
        try
        {
            BloggerInfoResults bloggerInfoResults = new BloggerInfoResults();
            ArgsToPassToApi argsToPassToApi = new ArgsToPassToApi();

            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(webApiUrl);

                argsToPassToApi.UserName = userName;
                argsToPassToApi.IpAddress = myIpAddress;

                string restOfUrl = "/api/profileandblog/getbloggersinfo/" + argsToPassToApi + "/";
                client.DefaultRequestHeaders.Clear();

                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                string payLoad = JsonConvert.SerializeObject(argsToPassToApi);

                HttpContent argsData = new StringContent(payLoad, Encoding.UTF8, "application/json");

                HttpResponseMessage response = await client.PostAsync(restOfUrl, argsData);

                if (response.IsSuccessStatusCode)
                {
                    var entry = response.Content.ReadAsStringAsync().Result;
                    bloggerInfoResults = JsonConvert.DeserializeObject<BloggerInfoResults>(entry);
                }
                else
                {
                    // The web api sent an error response.
                    bloggerInfoResults.ApiErrorMessage = "Web api error. Reason: " + response.ReasonPhrase;
                }

                // Return the model.
                return bloggerInfoResults;
            }
        }
        catch (Exception)
        {
            throw;
        }
    }

The error being received (a status code = 400 and the ReasonPhrase = 'Internal Server error'.):

enter image description here



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source