'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):
The error being sent to the client from the WebApi2Controller (a status code = 400 and ReasonPhrase with my custom message):
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'.):
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|



