Adding HttpResponseException to WebApi Shim.
This commit is contained in:
parent
d915994f0b
commit
ebf64ce4e3
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
||||
{
|
||||
public class HttpResponseException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpResponseException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="statusCode">The status code of the response.</param>
|
||||
public HttpResponseException(HttpStatusCode statusCode)
|
||||
: this(new HttpResponseMessage(statusCode))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpResponseException"/> class.
|
||||
/// </summary>
|
||||
/// <param name="response">The response message.</param>
|
||||
public HttpResponseException([NotNull] HttpResponseMessage response)
|
||||
: base(Resources.HttpResponseExceptionMessage)
|
||||
{
|
||||
Response = response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="HttpResponseMessage"/> to return to the client.
|
||||
/// </summary>
|
||||
public HttpResponseMessage Response { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
||||
{
|
||||
/// <summary>
|
||||
/// An action filter which sets <see cref="ActionExecutedContext.Result"/> to an <see cref="ObjectResult"/>
|
||||
/// if the exception type is <see cref="HttpResponseException"/>.
|
||||
/// This filter runs immediately after the action.
|
||||
/// </summary>
|
||||
public class HttpResponseExceptionActionFilter : IActionFilter, IOrderedFilter
|
||||
{
|
||||
// Return a high number by default so that it runs closest to the action.
|
||||
public int Order { get; set; } = int.MaxValue - 10;
|
||||
|
||||
public void OnActionExecuting([NotNull] ActionExecutingContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnActionExecuted([NotNull] ActionExecutedContext context)
|
||||
{
|
||||
var httpResponseException = context.Exception as HttpResponseException;
|
||||
if (httpResponseException != null)
|
||||
{
|
||||
var request = context.HttpContext.GetHttpRequestMessage();
|
||||
var response = httpResponseException.Response;
|
||||
|
||||
if (response != null && response.RequestMessage == null)
|
||||
{
|
||||
response.RequestMessage = request;
|
||||
}
|
||||
|
||||
var objectResult = new ObjectResult(response)
|
||||
{
|
||||
DeclaredType = typeof(HttpResponseMessage)
|
||||
};
|
||||
|
||||
context.Result = objectResult;
|
||||
|
||||
// Its marked as handled as in webapi because an HttpResponseException
|
||||
// was considered as a 'success' response.
|
||||
context.ExceptionHandled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -138,6 +138,22 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("MaxHttpCollectionKeyLimitReached"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.
|
||||
/// </summary>
|
||||
internal static string HttpResponseExceptionMessage
|
||||
{
|
||||
get { return GetString("HttpResponseExceptionMessage"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.
|
||||
/// </summary>
|
||||
internal static string FormatHttpResponseExceptionMessage()
|
||||
{
|
||||
return GetString("HttpResponseExceptionMessage");
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -141,4 +141,7 @@
|
|||
<data name="MaxHttpCollectionKeyLimitReached" xml:space="preserve">
|
||||
<value>The number of keys in a NameValueCollection has exceeded the limit of '{0}'. You can adjust it by modifying the MaxHttpCollectionKeys property on the '{1}' class.</value>
|
||||
</data>
|
||||
<data name="HttpResponseExceptionMessage" xml:space="preserve">
|
||||
<value>Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -25,6 +25,9 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
options.ApplicationModelConventions.Add(new WebApiOverloadingGlobalModelConvention());
|
||||
options.ApplicationModelConventions.Add(new WebApiRoutesGlobalModelConvention(area: DefaultAreaName));
|
||||
|
||||
// Add an action filter for handling the HttpResponseException.
|
||||
options.Filters.Add(new HttpResponseExceptionActionFilter());
|
||||
|
||||
// Add a model binder to be able to bind HttpRequestMessage
|
||||
options.ModelBinders.Insert(0, new HttpRequestMessageModelBinder());
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,78 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
Assert.Equal(expected, formatters);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ActionThrowsHttpResponseException_WithStatusCode()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync(
|
||||
"http://localhost/api/Blog/HttpResponseException/ThrowsHttpResponseExceptionWithHttpStatusCode");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(string.Empty, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ActionThrowsHttpResponseException_WithResponse()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync(
|
||||
"http://localhost/api/Blog/HttpResponseException"+
|
||||
"/ThrowsHttpResponseExceptionWithHttpResponseMessage?message=send some message");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("send some message", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ActionThrowsHttpResponseException_EnsureGlobalHttpresponseExceptionActionFilter_IsInvoked()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync(
|
||||
"http://localhost/api/Blog/HttpResponseException/ThrowsHttpResponseExceptionEnsureGlobalFilterRunsLast");
|
||||
|
||||
// Assert
|
||||
// Ensure we do not get a no content result.
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(string.Empty, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ActionThrowsHttpResponseException_EnsureGlobalFilterConvention_IsApplied()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync(
|
||||
"http://localhost/api/Blog/"+
|
||||
"HttpResponseException/ThrowsHttpResponseExceptionInjectAFilterToHandleHttpResponseException");
|
||||
|
||||
// Assert
|
||||
// Ensure we do get a no content result.
|
||||
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(string.Empty, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApiController_CanValidateCustomObjectWithPrefix_Fails()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNet.PipelineCore;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
||||
{
|
||||
public class HttpResponseExceptionActionFilterTest
|
||||
{
|
||||
[Fact]
|
||||
public void OnActionExecuting_IsNoOp()
|
||||
{
|
||||
// Arrange
|
||||
var filter = new HttpResponseExceptionActionFilter();
|
||||
var context = new ActionExecutingContext(new ActionContext(
|
||||
new DefaultHttpContext(),
|
||||
new RouteData(),
|
||||
actionDescriptor: Mock.Of<ActionDescriptor>()),
|
||||
filters: Mock.Of<IList<IFilter>>(),
|
||||
actionArguments: new Dictionary<string, object>());
|
||||
|
||||
// Act
|
||||
filter.OnActionExecuting(context);
|
||||
|
||||
// Assert
|
||||
Assert.Null(context.Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OrderIsSetToMaxValue()
|
||||
{
|
||||
// Arrange
|
||||
var filter = new HttpResponseExceptionActionFilter();
|
||||
var expectedFilterOrder = int.MaxValue - 10;
|
||||
|
||||
// Act & Assert
|
||||
Assert.Equal(expectedFilterOrder, filter.Order);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnActionExecuted_HandlesExceptionAndReturnsObjectResult()
|
||||
{
|
||||
// Arrange
|
||||
var filter = new HttpResponseExceptionActionFilter();
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Request.Method = "GET";
|
||||
|
||||
var context = new ActionExecutedContext(
|
||||
new ActionContext(
|
||||
httpContext,
|
||||
new RouteData(),
|
||||
actionDescriptor: Mock.Of<ActionDescriptor>()),
|
||||
filters: null);
|
||||
context.Exception = new HttpResponseException(HttpStatusCode.BadRequest);
|
||||
|
||||
// Act
|
||||
filter.OnActionExecuted(context);
|
||||
|
||||
// Assert
|
||||
Assert.True(context.ExceptionHandled);
|
||||
var result = Assert.IsType<ObjectResult>(context.Result);
|
||||
Assert.Equal(typeof(HttpResponseMessage), result.DeclaredType);
|
||||
var response = Assert.IsType<HttpResponseMessage>(result.Value);
|
||||
Assert.NotNull(response.RequestMessage);
|
||||
Assert.Equal(context.HttpContext.GetHttpRequestMessage(), response.RequestMessage);
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
||||
{
|
||||
public class HttpResponseExceptionTest
|
||||
{
|
||||
[Fact]
|
||||
[ReplaceCulture]
|
||||
public void Constructor_SetsResponseProperty()
|
||||
{
|
||||
// Arrange and Act
|
||||
var response = new HttpResponseMessage();
|
||||
var exception = new HttpResponseException(response);
|
||||
|
||||
// Assert
|
||||
Assert.Same(response, exception.Response);
|
||||
Assert.Equal("Processing of the HTTP request resulted in an exception."+
|
||||
" Please see the HTTP response returned by the 'Response' "+
|
||||
"property of this exception for details.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture]
|
||||
public void Constructor_SetsResponsePropertyWithGivenStatusCode()
|
||||
{
|
||||
// Arrange and Act
|
||||
var exception = new HttpResponseException(HttpStatusCode.BadGateway);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.BadGateway, exception.Response.StatusCode);
|
||||
Assert.Equal("Processing of the HTTP request resulted in an exception."+
|
||||
" Please see the HTTP response returned by the 'Response' "+
|
||||
"property of this exception for details.",
|
||||
exception.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
"dependencies": {
|
||||
"Microsoft.AspNet.Mvc": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-*",
|
||||
"Microsoft.AspNet.Testing": "1.0.0-*",
|
||||
"Moq": "4.2.1312.1622",
|
||||
"Xunit.KRunner": "1.0.0-*"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Web.Http;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.WebApiCompatShim;
|
||||
|
||||
namespace WebApiCompatShimWebSite
|
||||
{
|
||||
public class HttpResponseExceptionController : ApiController
|
||||
{
|
||||
[HttpGet]
|
||||
public object ThrowsHttpResponseExceptionWithHttpStatusCode()
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.BadRequest);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public object ThrowsHttpResponseExceptionWithHttpResponseMessage(string message)
|
||||
{
|
||||
var httpResponse = new HttpResponseMessage();
|
||||
httpResponse.Content = new StringContent(message);
|
||||
throw new HttpResponseException(httpResponse);
|
||||
}
|
||||
|
||||
[TestActionFilter]
|
||||
[HttpGet]
|
||||
public object ThrowsHttpResponseExceptionEnsureGlobalFilterRunsLast()
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.BadRequest);
|
||||
}
|
||||
|
||||
// Runs before the HttpResponseExceptionActionFilter's OnActionExecuted.
|
||||
[TestActionFilter(Order = int.MaxValue)]
|
||||
[HttpGet]
|
||||
public object ThrowsHttpResponseExceptionInjectAFilterToHandleHttpResponseException()
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.BadRequest);
|
||||
}
|
||||
}
|
||||
|
||||
public class TestActionFilterAttribute : ActionFilterAttribute
|
||||
{
|
||||
public override void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
if (!context.ExceptionHandled)
|
||||
{
|
||||
var httpResponseException = context.Exception as HttpResponseException;
|
||||
if (httpResponseException != null)
|
||||
{
|
||||
context.Result = new NoContentResult();
|
||||
context.ExceptionHandled = true;
|
||||
|
||||
// Null it out so that next filter do not handle it.
|
||||
context.Exception = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
|
|
@ -16,10 +17,9 @@ namespace WebApiCompatShimWebSite
|
|||
app.UseServices(services =>
|
||||
{
|
||||
services.AddMvc(configuration);
|
||||
|
||||
services.AddWebApiConventions();
|
||||
});
|
||||
|
||||
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
// This route can't access any of our webapi controllers
|
||||
|
|
|
|||
Loading…
Reference in New Issue