Why does HttpResponseException only allow its message to be read async? - c#

I'm writing a unit test method that exercises code that, under the conditions of my test, is expected to throw an HttpResponseException with a specific response message.
The relevant portion of my test method code looks like this:
try
{
MyClassBeingTested.MyWebServiceMethodBeingTested(myParameters);
}
catch (HttpResponseException ex)
{
string errorMessage = await ex.Response.Content.ReadAsStringAsync();
Assert.IsTrue(errorMessage.Contains("My expected error message string"));
return;
}
Assert.Fail("Expected HttpResponseException didn't get thrown");
This code works, and the test passes.
However, I'd like to better understand understand why my code that reads the error message needs to be constructed this way. The HttpResponseException class only provides async access to its message. I therefore needed to get the message via ReadAsStringAsync(), instead of just being able to synchronously get the message by doing something like ex.Response.Content.Message.
I feel like I might be missing something about why the HttpResponseException class works the way it does. What is the reason that HttpResponseException does not provide synchronous access to its response message?

The HttpResponseException class only provides async access to its message.
HttpResponseException provides you synchronous access to the HTTP response message (Response), which provides you synchronous access to its content (Content). The content of an HTTP stream is what is always read asynchronously. In some uses, the content of an HTTP stream is fully existing in-memory by the time it's used; in other uses, the content of an HTTP stream is streamed over the network.
E.g., if you make an HTTP request with HttpCompletionOption.ResponseHeadersRead, then the response content will be streamed, and it's possible to check the status code and raise an exception before the content of the response actually gets to the box your code is running on.

Related

WebAssembly.JSException: TypeError: Failed to fetch when server does not response

I want to write code for case when server does not response.
I purposely shutdown backend to simulate this situation. HttpClient throws WebAssembly.JSException with message
TypeError: Failed to fetch
Is it OK?
I think it is confusing.
I afraid if I will depend from this behavior, there will be problems.
How can I properly handle this case?
The following code snippet describes how you perform an HTTP GET call to a Web Api endpoint, querying the value of IsSuccessStatusCode which indicates whether the HTTP response was successful or not. If successful, the code retrieves the data stream, deserialize it into a List<Contact>, and returns it to the calling code.
If not successful (else clause), handle failure...here you can place whatever checking you want to make, logging errors, displaying messages, etc.
What I'm trying to show here is the direction how to solve not only that issue of yours, but other exception such as NotFound ( 404 ) exception, etc.
You may also use the response.EnsureSuccessStatusCode(); in a try/catch block and handles exceptions according to your needs.
You can do all this in various manners...
public async Task<List<Contact>> GetContactsAsync()
{
var response = await httpClient.GetAsync("api/contacts");
// response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
// Handle success
var responseContent = await response.Content.ReadAsStreamAsync();
return await JsonSerializer.DeserializeAsync<List<Contact>>(responseContent);
}
else
{
// Handle failure
}
}

Are exceptions an exception to the rule about not modifying the Response after next()?

While trying to find the best approach to implementing a catch-all for any uncaught exceptions I found this.
But, while implementing it, I remembered where I read:
WARNING Don't modify the Response object after calling next()..., as the response may have already started sending and you
could cause invalid data to be sent.
pg. 580
Is this an issue when the middleware is acting as a global exception handler before the MVC middleware where it seems reasonable that if the exception middleware were invoked, no response could have been started?
Invoke on Middleware:
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
// A catch-all for uncaught exceptions...
catch (Exception exception)
{
var response = context.Response;
response.ContentType = "application/json";
response.StatusCode = (int)HttpStatusCode.InternalServerError;
await response.WriteAsync(...);
}
}
Of course, I cannot comment on the exact intention the author had in mind when writing that. But the general idea is that you shouldn’t modify a HTTP response when it has already started. This is because the response can already be sent in parts before it is completely constructed. And when you then attempt to change the request then, you will get exceptions that you cannot modify the response.
That is why when you invoke some middleware, and that middleware is expected to produce a response, then you should not modify the response; simply because it will likely fail.
If you invoke some middleware, and that middleware does not produce a response, then of course you are free to still create a response.
For exceptions in particular, middlewares usually produce the response at the very last step, e.g. MVC works with action result objects internally and only at the end those will be executed to produce an actual result on the response. So exceptions will often be triggered before a response is produced. So it is fine to modify the response if you encounter an exception.
The built-in exception handler middleware works pretty much the same btw., so that should be a sign that what you are doing is fine. You should just be aware that modifying the response could potentially fail, so you should handle that case as well, e.g. by checking the HasStarted property.

Why changing the status code after writing to the body returns 504?

In ASP.NET 5 I've seem that the following code gives an error 504 in the response:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Use((next) => {
return async (context) => {
context.Response.StatusCode = 200;
await context.Response.WriteAsync("Hello World");
context.Response.StatusCode = 201;
await context.Response.WriteAsync("Status code changed");
};
});
}
}
I know we shouldn't change the status code in this arbitrary manner, but my question here is: why changing it gives a problem? The fact is that, commenting the line that changes the status code, and using Response.WriteAsync twice, doesn't give any kind of problem, but changing the status code gives.
When we do it this returns a 504 status code. I believe it has to do with the way the response is sent to the client. It happens because when we call Respose.WriteAsync the response message starts being sent already? What's the reason for this error to occur?
Headers are sent the moment content is written to the response body stream and so you cannot change the headers again...so if you are setting the status code again, then probably an exception is being thrown in the middleware to indicate this...
BTW this exception would cause the 504 that you are seeing(like currently there is no response buffering layer which could catch these kind of exceptions and returns a 500 Internal Server with an error message)...you can put a try-catch block to capture the exception message and see what it says..

How do I get an HTTP status code from TTransport exceptions?

I'm using a thrift HttpClient (C#) to make web requests to a web server I've set up, and if that server returns something other than 200 (or 202 I imagine), my request throws a TTransport exception.
I'd like to respond to this exception based on the specific status code returned, but I don't see anything that exposes the status code in the exception's interface. Have I missed something? I know the exception message contains the status code, but I'd rather not have to parse that message to get at the status code.
If the server encounters an processing error, the recommended method is not throwing a HTTP 500. Instead, the server should signal this by means of an exception. Consider the following Thrift IDL:
exception MyProcessingError
{
1: string reason
2: string errorDetails
3: string recommendedAction
}
service FooBar {
void ProcessPayments( 1: double amount; 2: string receiver)
throws (1: MyProcessingError mpe)
}
Similar to args and struct fields, multiple exception types can be declared. The client can catch these exceptions as usual:
try
{
client.ProcessPayments( 47.11, "Dagobert");
}
catch (MyProcessingError e)
{
// process exception
}
Remarks
The server may only throw exceptions that are declared in the IDL for
the particular call.
Furthermore, oneway calls never return any value, thus no
exceptions either.

Invalid request handling in OData

Im writing an OData webservice with C# and I need some advice on how to handle invalid requests? An example of an error would be if a customer requested a service on an item they no longer own. I would idealy like to report back to the customer exactly why it is invalid as there are multiple possible reasons.
Many thanks
I would recommend using FaultContracts as part of the OperationContract. You can define them just like DataContracts, and handle exceptions just like a custom exception.
[OperationContract]
[FaultContract(typeof(ItemNotOwned))]
Item GetItem(int ItemId);
You would define ItemNotOwned as a seperate contract definition.
Check it out on MSDN: http://msdn.microsoft.com/en-us/library/ms733841.aspx#Y323
Just throw an exception with the message containing that information. The exception will be serialized to the response sent to the client. If you don't care about the response status code, any exception will do and the client will recieve 500 (Internal Server Error). If you want a specific status code throw an instance of DataServiceException.
Look at using QueryInterceptors and ChangeInterceptors
http://robbincremers.me/2012/01/24/wcf-rest-service-with-odata-and-entity-framework-with-client-context-custom-operations-and-operation-interceptors/

Categories