deleted duplicate action results in WebapiCompatShim

This commit is contained in:
Ajay Bhargav Baaskaran 2015-01-05 13:18:34 -08:00
parent bc6833ee72
commit 51567194dc
12 changed files with 52 additions and 459 deletions

View File

@ -56,9 +56,15 @@ namespace Microsoft.AspNet.Mvc
/// <inheritdoc />
protected override void OnFormatting([NotNull] ActionContext context)
{
var request = context.HttpContext.Request;
var urlHelper = UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
var url = urlHelper.Action(ActionName, ControllerName, RouteValues);
var url = urlHelper.Action(
ActionName,
ControllerName,
RouteValues,
request.Scheme,
request.Host.ToUriComponent());
if (string.IsNullOrEmpty(url))
{

View File

@ -59,9 +59,10 @@ namespace Microsoft.AspNet.Mvc
/// <inheritdoc />
protected override void OnFormatting([NotNull] ActionContext context)
{
var request = context.HttpContext.Request;
var urlHelper = UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
var url = urlHelper.RouteUrl(RouteName, RouteValues);
var url = urlHelper.RouteUrl(RouteName, RouteValues, request.Scheme, request.Host.ToUriComponent());
if (string.IsNullOrEmpty(url))
{

View File

@ -1,22 +0,0 @@
// 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 Microsoft.AspNet.Mvc;
namespace System.Web.Http
{
/// <summary>
/// An action result that returns an empty <see cref="HttpStatusCode.BadRequest"/> response.
/// </summary>
public class BadRequestResult : HttpStatusCodeResult
{
/// <summary>
/// Initializes a new instance of the <see cref="BadRequestResult"/> class.
/// </summary>
public BadRequestResult()
: base((int)HttpStatusCode.BadRequest)
{
}
}
}

View File

@ -1,65 +0,0 @@
// 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.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.Framework.DependencyInjection;
using ShimResources = Microsoft.AspNet.Mvc.WebApiCompatShim.Resources;
namespace System.Web.Http
{
/// <summary>
/// Represents an action result that performs route generation and content negotiation and returns a
/// <see cref="HttpStatusCode.Created"/> response when content negotiation succeeds.
/// </summary>
/// <typeparam name="T">The type of content in the entity body.</typeparam>
public class CreatedAtRouteNegotiatedContentResult<T> : NegotiatedContentResult<T>
{
/// <summary>
/// Initializes a new instance of the <see cref="CreatedAtRouteNegotiatedContentResult{T}"/> class with the
/// values provided.
/// </summary>
/// <param name="routeName">The name of the route to use for generating the URL.</param>
/// <param name="routeValues">The route data to use for generating the URL.</param>
/// <param name="content">The content value to negotiate and format in the entity body.</param>
/// <param name="formatters">The formatters to use to negotiate and format the content.</param>
public CreatedAtRouteNegotiatedContentResult(
[NotNull] string routeName,
[NotNull] IDictionary<string, object> routeValues,
[NotNull] T content)
: base(HttpStatusCode.Created, content)
{
RouteName = routeName;
RouteValues = routeValues;
}
/// <summary>
/// Gets the name of the route to use for generating the URL.
/// </summary>
public string RouteName { get; private set; }
/// <summary>
/// Gets the route data to use for generating the URL.
/// </summary>
public IDictionary<string, object> RouteValues { get; private set; }
/// <inheritdoc />
public override Task ExecuteResultAsync(ActionContext context)
{
var request = context.HttpContext.Request;
var urlHelper = context.HttpContext.RequestServices.GetService<IUrlHelper>();
var url = urlHelper.RouteUrl(RouteName, RouteValues, request.Scheme, request.Host.ToUriComponent());
if (url == null)
{
throw new InvalidOperationException(ShimResources.FormatCreatedAtRoute_RouteFailed(RouteName));
}
context.HttpContext.Response.Headers.Add("Location", new string[] { url });
return base.ExecuteResultAsync(context);
}
}
}

View File

@ -1,52 +0,0 @@
// 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.Threading.Tasks;
using Microsoft.AspNet.Mvc;
namespace System.Web.Http
{
/// <summary>
/// Represents an action result that performs route generation and content negotiation and returns a
/// <see cref="HttpStatusCode.Created"/> response when content negotiation succeeds.
/// </summary>
/// <typeparam name="T">The type of content in the entity body.</typeparam>
public class CreatedNegotiatedContentResult<T> : NegotiatedContentResult<T>
{
/// <summary>
/// Initializes a new instance of the <see cref="CreatedNegotiatedContentResult{T}"/> class with the values
/// provided.
/// </summary>
/// <param name="location">The location at which the content has been created.</param>
/// <param name="content">The content value to negotiate and format in the entity body.</param>
public CreatedNegotiatedContentResult(Uri location, T content)
: base(HttpStatusCode.Created, content)
{
Location = location;
}
/// <summary>
/// Gets the location at which the content has been created.
/// </summary>
public Uri Location { get; private set; }
/// <inheritdoc />
public override Task ExecuteResultAsync(ActionContext context)
{
string location;
if (Location.IsAbsoluteUri)
{
location = Location.AbsoluteUri;
}
else
{
location = Location.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped);
}
context.HttpContext.Response.Headers.Add("Location", new string[] { location });
return base.ExecuteResultAsync(context);
}
}
}

View File

@ -21,15 +21,10 @@ namespace System.Web.Http
public NegotiatedContentResult(HttpStatusCode statusCode, T content)
: base(content)
{
StatusCode = statusCode;
StatusCode = (int)statusCode;
Content = content;
}
/// <summary>
/// Gets the HTTP status code for the response message.
/// </summary>
public HttpStatusCode StatusCode { get; private set; }
/// <summary>
/// Gets the content value to negotiate and format in the entity body.
/// </summary>

View File

@ -1,7 +1,6 @@
// 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 System.Security.Principal;
@ -10,7 +9,6 @@ using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.WebApiCompatShim;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;
using Newtonsoft.Json;
@ -146,54 +144,54 @@ namespace System.Web.Http
}
/// <summary>
/// Creates a <see cref="CreatedNegotiatedContentResult{T}"/> (201 Created) with the specified values.
/// Creates a <see cref="CreatedResult"/> (201 Created) with the specified values.
/// </summary>
/// <typeparam name="T">The type of content in the entity body.</typeparam>
/// <param name="location">
/// The location at which the content has been created. Must be a relative or absolute URL.
/// </param>
/// <param name="content">The content value to negotiate and format in the entity body.</param>
/// <returns>A <see cref="CreatedNegotiatedContentResult{T}"/> with the specified values.</returns>
/// <param name="content">The content value to format in the entity body.</param>
/// <returns>A <see cref="CreatedResult"/> with the specified values.</returns>
[NonAction]
public virtual CreatedNegotiatedContentResult<T> Created<T>([NotNull] string location, [NotNull] T content)
public virtual CreatedResult Created([NotNull] string location, object content)
{
return Created<T>(new Uri(location, UriKind.RelativeOrAbsolute), content);
return new CreatedResult(location, content);
}
/// <summary>
/// Creates a <see cref="CreatedNegotiatedContentResult{T}"/> (201 Created) with the specified values.
/// Creates a <see cref="CreatedResult"/> (201 Created) with the specified values.
/// </summary>
/// <typeparam name="T">The type of content in the entity body.</typeparam>
/// <param name="location">The location at which the content has been created.</param>
/// <param name="content">The content value to negotiate and format in the entity body.</param>
/// <returns>A <see cref="CreatedNegotiatedContentResult{T}"/> with the specified values.</returns>
/// <param name="content">The content value to format in the entity body.</param>
/// <returns>A <see cref="CreatedResult"/> with the specified values.</returns>
[NonAction]
public virtual CreatedNegotiatedContentResult<T> Created<T>([NotNull] Uri location, [NotNull] T content)
public virtual CreatedResult Created([NotNull] Uri uri, object content)
{
return new CreatedNegotiatedContentResult<T>(location, content);
string location;
if (uri.IsAbsoluteUri)
{
location = uri.AbsoluteUri;
}
else
{
location = uri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped);
}
return Created(location, content);
}
/// <summary>
/// Creates a <see cref="CreatedAtRouteNegotiatedContentResult{T}"/> (201 Created) with the specified values.
/// Creates a <see cref="CreatedAtRouteResult"/> (201 Created) with the specified values.
/// </summary>
/// <typeparam name="T">The type of content in the entity body.</typeparam>
/// <param name="routeName">The name of the route to use for generating the URL.</param>
/// <param name="routeValues">The route data to use for generating the URL.</param>
/// <param name="content">The content value to negotiate and format in the entity body.</param>
/// <returns>A <see cref="CreatedAtRouteNegotiatedContentResult{T}"/> with the specified values.</returns>
/// <param name="content">The content value to format in the entity body.</param>
/// <returns>A <see cref="CreatedAtRouteResult"/> with the specified values.</returns>
[NonAction]
public virtual CreatedAtRouteNegotiatedContentResult<T> CreatedAtRoute<T>(
public virtual CreatedAtRouteResult CreatedAtRoute(
[NotNull] string routeName,
object routeValues,
[NotNull] T content)
object content)
{
var values = routeValues as IDictionary<string, object>;
if (values == null)
{
values = new RouteValueDictionary(routeValues);
}
return new CreatedAtRouteNegotiatedContentResult<T>(routeName, values, content);
return new CreatedAtRouteResult(routeName, routeValues, content);
}
/// <summary

View File

@ -138,7 +138,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
Assert.Equal("/ActionResultsVerification/GetDummy/1", response.Headers.Location.OriginalString);
Assert.Equal("http://localhost/ActionResultsVerification/GetDummy/1", response.Headers.Location.OriginalString);
Assert.Equal("{\"SampleInt\":10,\"SampleString\":\"Foo\"}", await response.Content.ReadAsStringAsync());
}
@ -158,7 +158,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
Assert.Equal("/ActionResultsVerification/GetDummy/1", response.Headers.Location.OriginalString);
Assert.Equal("http://localhost/ActionResultsVerification/GetDummy/1", response.Headers.Location.OriginalString);
Assert.Equal("{\"SampleInt\":10,\"SampleString\":\"Foo\"}", await response.Content.ReadAsStringAsync());
}
@ -178,7 +178,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
Assert.Equal("/foo/ActionResultsVerification/GetDummy/1", response.Headers.Location.OriginalString);
Assert.Equal("http://localhost/foo/ActionResultsVerification/GetDummy/1", response.Headers.Location.OriginalString);
Assert.Equal("{\"SampleInt\":10,\"SampleString\":\"Foo\"}", await response.Content.ReadAsStringAsync());
}
}

View File

@ -1,28 +0,0 @@
// 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.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.PipelineCore;
using Microsoft.AspNet.Routing;
using Xunit;
namespace System.Web.Http
{
public class BadRequestResultTest
{
[Fact]
public async Task BadRequestResult_SetsStatusCode()
{
// Arrange
var context = new ActionContext(new RouteContext(new DefaultHttpContext()), new ActionDescriptor());
var result = new BadRequestResult();
// Act
await result.ExecuteResultAsync(context);
// Assert
Assert.Equal(400, context.HttpContext.Response.StatusCode);
}
}
}

View File

@ -1,130 +0,0 @@
// 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.
#if ASPNET50
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.PipelineCore;
using Microsoft.AspNet.Routing;
using Moq;
using Xunit;
namespace System.Web.Http
{
public class CreatedAtRouteNegotiatedContentResultTest
{
[Fact]
public async Task CreatedAtRouteNegotiatedContentResult_SetsStatusCode()
{
// Arrange
var urlHelper = new Mock<IUrlHelper>(MockBehavior.Strict);
urlHelper
.Setup(u => u.RouteUrl(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns("http://contoso.com/api/Products/5");
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = CreateServices(urlHelper.Object);
var stream = new MemoryStream();
httpContext.Response.Body = stream;
var context = new ActionContext(new RouteContext(httpContext), new ActionDescriptor());
var result = new CreatedAtRouteNegotiatedContentResult<Product>(
"api_route",
new RouteValueDictionary(new { controller = "Products", id = 5 }),
new Product());
// Act
await result.ExecuteResultAsync(context);
// Assert
Assert.Equal(201, context.HttpContext.Response.StatusCode);
}
[Fact]
public async Task CreatedAtRouteNegotiatedContentResult_SetsLocation()
{
// Arrange
var urlHelper = new Mock<IUrlHelper>(MockBehavior.Strict);
urlHelper
.Setup(u => u.RouteUrl(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns("http://contoso.com/api/Products/5");
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = CreateServices(urlHelper.Object);
var stream = new MemoryStream();
httpContext.Response.Body = stream;
var context = new ActionContext(new RouteContext(httpContext), new ActionDescriptor());
var result = new CreatedAtRouteNegotiatedContentResult<Product>(
"api_route",
new RouteValueDictionary(new { controller = "Products", id = 5 }),
new Product());
// Act
await result.ExecuteResultAsync(context);
// Assert
Assert.Equal("http://contoso.com/api/Products/5", httpContext.Response.Headers["Location"]);
}
[Fact]
public async Task CreatedAtRouteNegotiatedContentResult_Fails()
{
// Arrange
var urlHelper = new Mock<IUrlHelper>(MockBehavior.Strict);
urlHelper
.Setup(u => u.RouteUrl(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns((string)null);
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = CreateServices(urlHelper.Object);
var stream = new MemoryStream();
httpContext.Response.Body = stream;
var context = new ActionContext(new RouteContext(httpContext), new ActionDescriptor());
var result = new CreatedAtRouteNegotiatedContentResult<Product>(
"api_route",
new RouteValueDictionary(new { controller = "Products", id = 5 }),
new Product());
// Act
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await result.ExecuteResultAsync(context));
// Assert
Assert.Equal("Failed to generate a URL using route 'api_route'.", ex.Message);
}
private IServiceProvider CreateServices(IUrlHelper urlHelper)
{
var services = new Mock<IServiceProvider>(MockBehavior.Strict);
services
.Setup(s => s.GetService(typeof(IUrlHelper)))
.Returns(urlHelper);
var formatters = new Mock<IOutputFormattersProvider>(MockBehavior.Strict);
formatters
.SetupGet(f => f.OutputFormatters)
.Returns(new List<IOutputFormatter>() { new JsonOutputFormatter(), });
services
.Setup(s => s.GetService(typeof(IOutputFormattersProvider)))
.Returns(formatters.Object);
return services.Object;
}
private class Product
{
public int Id { get; set; }
public string Name { get; set; }
};
}
}
#endif

View File

@ -1,111 +0,0 @@
// 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.
#if ASPNET50
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.PipelineCore;
using Microsoft.AspNet.Routing;
using Moq;
using Xunit;
namespace System.Web.Http
{
public class CreatedNegotiatedContentResultTest
{
[Fact]
public async Task CreatedNegotiatedContentResult_SetsStatusCode()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = CreateServices();
var stream = new MemoryStream();
httpContext.Response.Body = stream;
var uri = new Uri("http://contoso.com");
var context = new ActionContext(new RouteContext(httpContext), new ActionDescriptor());
var result = new CreatedNegotiatedContentResult<Product>(uri, new Product());
// Act
await result.ExecuteResultAsync(context);
// Assert
Assert.Equal(201, context.HttpContext.Response.StatusCode);
}
[Fact]
public async Task CreatedNegotiatedContentResult_SetsLocation_Uri()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = CreateServices();
var stream = new MemoryStream();
httpContext.Response.Body = stream;
var uri = new Uri("http://contoso.com");
var context = new ActionContext(new RouteContext(httpContext), new ActionDescriptor());
var result = new CreatedNegotiatedContentResult<Product>(uri, new Product());
// Act
await result.ExecuteResultAsync(context);
// Assert
Assert.Equal("http://contoso.com/", httpContext.Response.Headers["Location"]);
}
[Theory]
[InlineData("http://contoso.com/Api/Products")]
[InlineData("/Api/Products")]
[InlineData("Products")]
public async Task CreatedNegotiatedContentResult_SetsLocation_String(string uri)
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = CreateServices();
var stream = new MemoryStream();
httpContext.Response.Body = stream;
var context = new ActionContext(new RouteContext(httpContext), new ActionDescriptor());
var result = new CreatedNegotiatedContentResult<Product>(
new Uri(uri, UriKind.RelativeOrAbsolute),
new Product());
// Act
await result.ExecuteResultAsync(context);
// Assert
Assert.Equal(uri, httpContext.Response.Headers["Location"]);
}
private IServiceProvider CreateServices()
{
var services = new Mock<IServiceProvider>(MockBehavior.Strict);
var formatters = new Mock<IOutputFormattersProvider>(MockBehavior.Strict);
formatters
.SetupGet(f => f.OutputFormatters)
.Returns(new List<IOutputFormatter>() { new JsonOutputFormatter(), });
services
.Setup(s => s.GetService(typeof(IOutputFormattersProvider)))
.Returns(formatters.Object);
return services.Object;
}
private class Product
{
public int Id { get; set; }
public string Name { get; set; }
};
}
}
#endif

View File

@ -1,6 +1,7 @@
// 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 System.Security.Claims;
@ -104,16 +105,16 @@ namespace System.Web.Http
// Arrange
var controller = new ConcreteApiController();
var uri = new Uri("http://contoso.com");
var uri = new Uri("http://contoso.com/");
var product = new Product();
// Act
var result = controller.Created(uri, product);
// Assert
var created = Assert.IsType<CreatedNegotiatedContentResult<Product>>(result);
Assert.Same(product, created.Content);
Assert.Same(uri, created.Location);
var created = Assert.IsType<CreatedResult>(result);
Assert.Same(product, created.Value);
Assert.Equal(uri.OriginalString, created.Location);
}
[Theory]
@ -131,9 +132,9 @@ namespace System.Web.Http
var result = controller.Created(uri, product);
// Assert
var created = Assert.IsType<CreatedNegotiatedContentResult<Product>>(result);
Assert.Same(product, created.Content);
Assert.Equal(uri, created.Location.OriginalString);
var created = Assert.IsType<CreatedResult>(result);
Assert.Same(product, created.Value);
Assert.Equal(uri, created.Location);
}
[Fact]
@ -148,8 +149,8 @@ namespace System.Web.Http
var result = controller.CreatedAtRoute("api_route", new { controller = "Products" }, product);
// Assert
var created = Assert.IsType<CreatedAtRouteNegotiatedContentResult<Product>>(result);
Assert.Same(product, created.Content);
var created = Assert.IsType<CreatedAtRouteResult>(result);
Assert.Same(product, created.Value);
Assert.Equal("api_route", created.RouteName);
Assert.Equal("Products", created.RouteValues["controller"]);
}
@ -167,11 +168,11 @@ namespace System.Web.Http
var result = controller.CreatedAtRoute("api_route", values, product);
// Assert
var created = Assert.IsType<CreatedAtRouteNegotiatedContentResult<Product>>(result);
Assert.Same(product, created.Content);
var created = Assert.IsType<CreatedAtRouteResult>(result);
Assert.Same(product, created.Value);
Assert.Equal("api_route", created.RouteName);
Assert.Equal("Products", created.RouteValues["controller"]);
Assert.Same(values, created.RouteValues);
Assert.Equal<KeyValuePair<string, object>>(values, created.RouteValues);
}
[Fact]
@ -200,7 +201,7 @@ namespace System.Web.Http
// Assert
var contentResult = Assert.IsType<NegotiatedContentResult<Product>>(result);
Assert.Equal(HttpStatusCode.Found, contentResult.StatusCode);
Assert.Equal((int)HttpStatusCode.Found, contentResult.StatusCode);
Assert.Equal(content, contentResult.Value);
}