__Scenario__:
User has a Katana based selfhosted application and is making a request to a non-existing controller
__Issue__:
Response body does not have the detailed error message that Web API usually gives for these kind of scenarios. This would also effect any response headers that might have been added to the response.
__Reason__:
We introduced something called "Soft" 404 to handle scenarios where Web API shouldn't respond directly to the client, but instead invoke any middleware registered 'after' Web API.
In the logic that we currently have, we are eagerly discarding the response body(which would have had the error message that i am expecting) if its a "Soft" 404 and then checking for presence of any registered middleware and invoking it. But if there was no middleware registered, then we should ideally be returing back the correct response, which is including the response body.
__Expected__: {"Message":"No HTTP resource was found that matches the request URI 'http://localhost:14459/api/doesnotexist'.","MessageDetail":"No type was found that matches the controller named 'doesnotexist'."}
__Actual__: No body
__Attached__ a katana selfhost repro.
__HttpMessageHandlerAdapter__ source code(Notice the condition _if (IsSoftNotFound(request, response))_):
```
HttpResponseMessage response = null;
bool callNext = false;
try
{
response = await _messageInvoker.SendAsync(request, owinRequest.CallCancelled);
// Handle null responses
if (response == null)
{
throw Error.InvalidOperation(OwinResources.SendAsync_ReturnedNull);
}
// Handle soft 404s where no route matched - call the next component
if (IsSoftNotFound(request, response))
{
callNext = true;
}
else
{
if (response.Content != null && _bufferPolicySelector.UseBufferedOutputStream(response))
{
response = await BufferResponseBodyAsync(request, response);
}
FixUpContentLengthHeaders(response);
await SendResponseMessageAsync(response, owinResponse);
}
}
finally
{
// Note that the HttpRequestMessage is explicitly NOT disposed. Disposing it would close the input stream
// and prevent cascaded components from accessing it. The server MUST handle any necessary cleanup upon
// request completion.
request.DisposeRequestResources();
if (response != null)
{
response.Dispose();
}
}
// Call the next component if no route matched
if (callNext && Next != null)
{
await Next.Invoke(context);
}
```
Comments: Each piece of middleware is unaware of the other middleware around it - there is no handshaking between them. If there isn't a Web API route that handles the request then Web API gives up and lets the next middleware handle it.
User has a Katana based selfhosted application and is making a request to a non-existing controller
__Issue__:
Response body does not have the detailed error message that Web API usually gives for these kind of scenarios. This would also effect any response headers that might have been added to the response.
__Reason__:
We introduced something called "Soft" 404 to handle scenarios where Web API shouldn't respond directly to the client, but instead invoke any middleware registered 'after' Web API.
In the logic that we currently have, we are eagerly discarding the response body(which would have had the error message that i am expecting) if its a "Soft" 404 and then checking for presence of any registered middleware and invoking it. But if there was no middleware registered, then we should ideally be returing back the correct response, which is including the response body.
__Expected__: {"Message":"No HTTP resource was found that matches the request URI 'http://localhost:14459/api/doesnotexist'.","MessageDetail":"No type was found that matches the controller named 'doesnotexist'."}
__Actual__: No body
__Attached__ a katana selfhost repro.
__HttpMessageHandlerAdapter__ source code(Notice the condition _if (IsSoftNotFound(request, response))_):
```
HttpResponseMessage response = null;
bool callNext = false;
try
{
response = await _messageInvoker.SendAsync(request, owinRequest.CallCancelled);
// Handle null responses
if (response == null)
{
throw Error.InvalidOperation(OwinResources.SendAsync_ReturnedNull);
}
// Handle soft 404s where no route matched - call the next component
if (IsSoftNotFound(request, response))
{
callNext = true;
}
else
{
if (response.Content != null && _bufferPolicySelector.UseBufferedOutputStream(response))
{
response = await BufferResponseBodyAsync(request, response);
}
FixUpContentLengthHeaders(response);
await SendResponseMessageAsync(response, owinResponse);
}
}
finally
{
// Note that the HttpRequestMessage is explicitly NOT disposed. Disposing it would close the input stream
// and prevent cascaded components from accessing it. The server MUST handle any necessary cleanup upon
// request completion.
request.DisposeRequestResources();
if (response != null)
{
response.Dispose();
}
}
// Call the next component if no route matched
if (callNext && Next != null)
{
await Next.Invoke(context);
}
```
Comments: Each piece of middleware is unaware of the other middleware around it - there is no handshaking between them. If there isn't a Web API route that handles the request then Web API gives up and lets the next middleware handle it.