Unauthorized returns text/html instead of application/json - c#

I have a controller action in my WebAPI server that returns a 401 Unauthorized. The action also returns other error status codes such as 401, 409 and 500 as well as 200. All status codes add a DTO serialized to JSON all are working as expected.
For 401 I'm doing:
return Unauthorized(new UnauthorizedError() {
Id = 1, //int
Error = Error.UserNotFound, //enum
Message = "User not found" //string
});
The clients handles the 401 and reads the content as Unauthorized:
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
var result = await response.Content.ReadAsAsync<UnauthorizedError>(ct);
}
But just for these status code, I'm getting an exception:
No MediaTypeFormatter is available to read an object of type 'UnauthorizedError' from content with media type 'text/html'.
The app is running in IIS. Might it be the case that IIS is overriding the response type for 401? Is there a way to force a json response type on this action?

Related

HttpClient receives 401 Response using NTLM authentication

I have a C# Windows application running on .NET 4.6.1. It is posting a SOAP message to a server using NTLM authentication. It is expecting a 200 response, but receives the 401 response instead. Here is the code:
HttpClientHandler handler = new HttpClientHandler
{
Credentials = CredentialManager.GetCredentials();
};
HttpClient client = new HttpClient(handler);
using (HttpResponseMessage response = await client.PostAsync(uri, soapMessage, CancelToken))
{
string soapResponse = await response.Content.ReadAsStringAsync();
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
Parse(soapResponse);
}
}
I know that there is always a 401 response sent in order to retrieve the credentials, but I thought that the HttpResponse was supposed to contain the final response, in this case a 200 message. However, the response.StatusCode is always the 401 Unauthorized message, even though the developer on the server side assures me that immediately after the 401 message, a 200 message is sent. How can I get the 200 response and ignore the 401 response?

Losing error message with Http Status code 503 in System.net.Http library

We have 2 backend services communicating with each other, both of them are using .net framework with System.net.Http library
One of them returns HTTP status code 503 with some response message("data is not available") when certain condition is met, as shown below in the screenshot
the controller code implementation looks like this:
HttpResponseMessage response = new HttpResponseMessage { StatusCode = HttpStatusCode.ServiceUnavailable, ReasonPhrase = "XXXXXX data is currently not available XXXXXXXXX" };
response.Content = new StringContent("XXXXXX is currently not available XXXXXXXXXX");
return response;
the other service which is calling this API is consuming the response and gets this WebException, which is desired case but the problem is, we lose the message("data is not available") being sent from the first service, when I tried to print the response in the debug window, it showed the following result :
HttpWebResponse aresponse = request.GetResponse() as HttpWebResponse;
'HttpWebResponse aresponse = request.GetResponse() as HttpWebResponse' threw an exception of type 'System.Net.WebException'
Data: {System.Collections.ListDictionaryInternal}
HResult: -2146233079
HelpLink: null
InnerException: null
Message: "The remote server returned an error: (503) Server Unavailable."
Response: {System.Net.HttpWebResponse}
Source: "System"
StackTrace: null
Status: ProtocolError
TargetSite: null
As shown in the output message is not what I sent from the first service. It's the default message for HTTP status code 503.
Is there a way for me to read the response content from the WebException?
Found the solution, you can read the response from the System.net.WebException
catch(WebException ex)
{
HttpWebResponse errorResponse = webException.Response as HttpWebResponse;
var statusDescription = errorResponse.StatusDescription;
if(statusDescription.Contains("XXXXX"))
{
// Added the condition here
}
}

LearnUPON - I'm getting 404 response when call my Insert API

I'm going to implement Learn Upon API into my .NET MVC application, they gave cURL and I have to convert these cURL URL into the web request in C# for getting or sending data to the third party Learn Upon API server thing is that Listing API, Delete API was working fine but Create & Update API always returns The remote server returned an error: (404) Not Found.
cURL sample given by Learn Upon:
curl -X POST -H "Content-Type: application/json" --user 988d4f1313f881e5ac6bfdfc7f54244aab : 905a12r3a0c -d '{"User": {"last_name" : "Upon",
"first_name" : "Learn", "email" : "learnuponapi#samplelearningco.com", "password" : "password1", "language" : "en", "membership_type" : "Member"
}}' https://yourdomain.learnupon.com/api/v1/users
As per above cURL, I have written below web request call for API calls, and this pattern worked in Listing/Delete API.
POST Model:
{
"first_name": "Krishna",
"last_name": "Patel",
"email": "krishna.patel#test.com",
"password": "1234567890",
"language": "en",
"membership_type": "Member",
"username":"krishna.patel"
}
Create API Code:
[System.Web.Http.HttpPost]
public IHttpActionResult CreateUser(UserModel mdlUser)
{
string content = "";
try
{
if (ModelState.IsValid)
{
// target url given by Learn Upon, Unique for each account
string yourTarget = "https://{domain}/api/v1/users";
string josnUserModel = JsonConvert.SerializeObject(mdlUser);
josnUserModel = "{\"User\":" + josnUserModel + "}";
WebRequest yourWebRequest = WebRequest.Create(yourTarget);
yourWebRequest.Method = "POST";
// Establish credentials (if necessary)
CredentialCache yourCredentials = new CredentialCache();
yourCredentials.Add(new Uri(yourTarget), "Basic", new NetworkCredential(username, password));
// Set your credentials for your request
yourWebRequest.Credentials = yourCredentials;
// Add basic authentication headers (if necessary)
yourWebRequest.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(new ASCIIEncoding().GetBytes(String.Format("{0}:{1}", username, password))));
yourWebRequest.Headers.Add("data", josnUserModel);
WebResponse yourWebResponse = yourWebRequest.GetResponse();
string s = yourWebResponse.ToString();
// Get your response stream
using (var reponseStream = yourWebResponse.GetResponseStream())
{
// Build a reader to read your stream
using (var responseReader = new StreamReader(reponseStream, Encoding.UTF8))
{
// Get your result here
content = responseReader.ReadToEnd();
JObject json = JObject.Parse(content);
return Ok(json);
}
}
}
else
{
return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
}
}
catch (Exception ex)
{
return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message));
}
}
API Returns:
{
"Message": "The remote server returned an error: (404) Not Found."
}
Note: Above message comes from the exception catch block, every time exception occurs and return 404 response.
Are you sending any data in the POST request body?
It looks to me, as someone with very little C# experience, as if you're sending the mdlUser data as a HTTP Request Header (called data), and not sending anything in the POST body. There are a few examples of making a POST request in this question: How to make HTTP POST web request
That's likely to be the 404 problem (or, at least, the first one!). The exception you're catching is a legitimate exception (4xx is mostly considered an non-normal state). If you want to capture a 404 (which can be a legitimate response for the LearnUpon API when, for example, checking if a user exists in your portal), look at this question: How can I catch a 404?
Finally, feel free to reach out to your LearnUpon support team. We might not have all the answers a developer needs, but we can normally point you in the right direction.
Disclaimer: I work with LearnUpon.

Returning the Web API response in JSON format

I am trying sending a response from the API as a JSON. Currently we are calling other web service multiple times consuming it and send all the responses together as a JSON. The called web service returns response as a JSON. And below is what I am doing
List<Models.DTO.RootObject> i_response = new List<Models.TO.RootObject>();
public async Task<IHttpActionResult> Get()
{
.....
foreach (int req_id in reqIdLst)
{
using (var client_request = new HttpClient())
{
string request_Uri = BaseURL_iLab;
Uri uri_request = new Uri(request_Uri);
client_request.BaseAddress = uri_request;
client_request.DefaultRequestHeaders.Accept.Clear();
client_request.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client_request.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
var request_response = await client_request.GetAsync(uri_request);
var responsefile = await request_response.Content.ReadAsStringAsync();
var request_returnDataObj = JsonConvert.DeserializeObject<Models.DTO.RootObject>(responsefile);
i_response.Add(request_returnDataObj);
}}
return Ok(i_response);
}}
But my above code throws error when debugging as
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content
type 'application/xml; charset=utf-8'.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace/>
<InnerException>
I am not sure how to send as a JSON instead of a XML.
Something we did where I work was to create a custom class that extends ExceptionFilterAttribute. Call it something like WebApiExceptionFilterAttribute. Create an override for OnException and set the context.Response appropriately based on the exception. You can also set the HttpStatusCode if the exception indicates a specific result, such as NotFound, Forbidden, or BadRequest, instead of just InternalServerError.
Then, in Global.asax, in Application_Start(), add GlobalConfiguration.Configuration.Filters.Add(new WebApiExceptionFilterAttribute());
Finally, when defining an ApiController, add a [WebApiExceptionFilterAttribute] annotation to the class definition.

Server validation - response message?

I am coding server validation with C# and HttpResponseMessage. I need to send response back to the client with certain message, that the data sent is not valid. Which response code should I choose from this list?
https://msdn.microsoft.com/en-us/library/system.net.httpstatuscode(v=vs.110).aspx
Could I also customize the message so that I know which field got invalid data?
Note: MVC 4, Visual Studio 2010.
Here is my post function:
// POST api/Default1
[HttpPost]
public HttpResponseMessage PostUserProfile(HttpRequestMessage req)
{
UserProfile up = new UserProfile();
string jsonContent = req.Content.ReadAsStringAsync().Result;
if (ModelState.IsValid)
{
up = JsonConvert.DeserializeObject<UserProfile>(jsonContent);
if (up.userName.Length <= 50 &&
up.email.Length <= 60)
{
db.UserProfiles.Add(up);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, up);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = up.UserId }));
return response;
}
else
{
// finish the server validation
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.InternalServerError, up);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = up.UserId }));
return response;
}
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
Some people suggested BadRequest which is Http message 400:
Equivalent to HTTP status 400. BadRequest indicates that the request could not be understood by the server. BadRequest is sent when no other error is applicable, or if the exact error is unknown or does not have its own error code.
I don't think its suitable in this case since the browser does not see it as error, as if I sent OK message back to the client.
I think NotFound is more appropriate:
Equivalent to HTTP status 404. NotFound indicates that the requested resource does not exist on the server.
The browser sees it as error and therefore sent to the error handler in the jQuery AJAX object. So you can properly handle it, i.e update some message box in the html to let the user know that the server/database simply does not contain that resource or row in the table.

Categories

Resources