Add `HttpOkResult`, `HttpOkObjectResult`, and `Ok()` methods in `Controller`

- #2825
- new class names align with existing types such as `HttpNotFoundResult` and `HttpNotFoundObjectResult`
- remove similar types from WebApiCompatShim and use replacements in `ApiController`
 - `NegotiatedContentResult<T>` remains because Core doesn't have an exact replacement

nits:
- add missing periods in some `Controller` doc comments
This commit is contained in:
Doug Bunting 2015-07-21 19:22:32 -07:00
parent e91ce4560f
commit 6106375306
12 changed files with 255 additions and 161 deletions

View File

@ -0,0 +1,24 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// An <see cref="ObjectResult"/> that when executed performs content negotiation, formats the entity body, and
/// will produce a <see cref="StatusCodes.Status200OK"/> response if negotiation and formatting succeed.
/// </summary>
public class HttpOkObjectResult : ObjectResult
{
/// <summary>
/// Initializes a new instance of the <see cref="HttpOkObjectResult"/> class.
/// </summary>
/// <param name="value">The content to format into the entity body.</param>
public HttpOkObjectResult(object value)
: base(value)
{
StatusCode = StatusCodes.Status200OK;
}
}
}

View File

@ -0,0 +1,22 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// An <see cref="HttpStatusCodeResult"/> that when executed will produce an empty
/// <see cref="StatusCodes.Status200OK"/> response.
/// </summary>
public class HttpOkResult : HttpStatusCodeResult
{
/// <summary>
/// Initializes a new instance of the <see cref="HttpOkResult"/> class.
/// </summary>
public HttpOkResult()
: base(StatusCodes.Status200OK)
{
}
}
}

View File

@ -463,6 +463,33 @@ namespace Microsoft.AspNet.Mvc
return new JsonResult(data, serializerSettings);
}
/// <summary>
/// Creates a <see cref="HttpOkResult"/> object that produces an empty OK (200) response.
/// </summary>
/// <returns>The created <see cref="HttpOkResult"/> for the response.</returns>
[NonAction]
public virtual HttpOkResult Ok()
{
return new HttpOkResult();
}
/// <summary>
/// Creates an <see cref="HttpOkObjectResult"/> object that produces an OK (200) response.
/// </summary>
/// <param name="value">The content value to format in the entity body.</param>
/// <returns>The created <see cref="HttpOkObjectResult"/> for the response.</returns>
[NonAction]
public virtual HttpOkObjectResult Ok(object value)
{
var disposableValue = value as IDisposable;
if (disposableValue != null)
{
Response.RegisterForDispose(disposableValue);
}
return new HttpOkObjectResult(value);
}
/// <summary>
/// Creates a <see cref="RedirectResult"/> object that redirects to the specified <paramref name="url"/>.
/// </summary>
@ -1025,7 +1052,7 @@ namespace Microsoft.AspNet.Mvc
/// </summary>
/// <typeparam name="TModel">The type of the model object.</typeparam>
/// <param name="model">The model instance to update.</param>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful.</returns>
[NonAction]
public virtual Task<bool> TryUpdateModelAsync<TModel>([NotNull] TModel model)
where TModel : class
@ -1039,9 +1066,9 @@ namespace Microsoft.AspNet.Mvc
/// </summary>
/// <typeparam name="TModel">The type of the model object.</typeparam>
/// <param name="model">The model instance to update.</param>
/// <param name="prefix">The prefix to use when looking up values in the current <see cref="IValueProvider"/>
/// <param name="prefix">The prefix to use when looking up values in the current <see cref="IValueProvider"/>.
/// </param>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful.</returns>
[NonAction]
public virtual async Task<bool> TryUpdateModelAsync<TModel>([NotNull] TModel model,
[NotNull] string prefix)
@ -1067,7 +1094,7 @@ namespace Microsoft.AspNet.Mvc
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>.
/// </param>
/// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful.</returns>
[NonAction]
public virtual async Task<bool> TryUpdateModelAsync<TModel>([NotNull] TModel model,
[NotNull] string prefix,
@ -1105,7 +1132,7 @@ namespace Microsoft.AspNet.Mvc
/// </param>
/// <param name="includeExpressions"> <see cref="Expression"/>(s) which represent top-level properties
/// which need to be included for the current model.</param>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful.</returns>
[NonAction]
public async Task<bool> TryUpdateModelAsync<TModel>(
[NotNull] TModel model,
@ -1144,7 +1171,7 @@ namespace Microsoft.AspNet.Mvc
/// <param name="prefix">The prefix to use when looking up values in the current <see cref="IValueProvider"/>.
/// </param>
/// <param name="predicate">A predicate which can be used to filter properties at runtime.</param>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful.</returns>
[NonAction]
public async Task<bool> TryUpdateModelAsync<TModel>(
[NotNull] TModel model,
@ -1180,12 +1207,12 @@ namespace Microsoft.AspNet.Mvc
/// </summary>
/// <typeparam name="TModel">The type of the model object.</typeparam>
/// <param name="model">The model instance to update.</param>
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>.
/// </param>
/// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
/// <param name="includeExpressions"> <see cref="Expression"/>(s) which represent top-level properties
/// which need to be included for the current model.</param>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful.</returns>
[NonAction]
public async Task<bool> TryUpdateModelAsync<TModel>(
[NotNull] TModel model,
@ -1222,11 +1249,11 @@ namespace Microsoft.AspNet.Mvc
/// </summary>
/// <typeparam name="TModel">The type of the model object.</typeparam>
/// <param name="model">The model instance to update.</param>
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>.
/// </param>
/// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
/// <param name="predicate">A predicate which can be used to filter properties at runtime.</param>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful.</returns>
[NonAction]
public async Task<bool> TryUpdateModelAsync<TModel>(
[NotNull] TModel model,
@ -1263,9 +1290,9 @@ namespace Microsoft.AspNet.Mvc
/// </summary>
/// <param name="model">The model instance to update.</param>
/// <param name="modelType">The type of model instance to update.</param>
/// <param name="prefix">The prefix to use when looking up values in the current <see cref="IValueProvider"/>
/// <param name="prefix">The prefix to use when looking up values in the current <see cref="IValueProvider"/>.
/// </param>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful.</returns>
[NonAction]
public virtual async Task<bool> TryUpdateModelAsync([NotNull] object model,
[NotNull] Type modelType,
@ -1299,11 +1326,11 @@ namespace Microsoft.AspNet.Mvc
/// </summary>
/// <param name="model">The model instance to update.</param>
/// <param name="modelType">The type of model instance to update.</param>
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>.
/// </param>
/// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
/// <param name="predicate">A predicate which can be used to filter properties at runtime.</param>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful.</returns>
[NonAction]
public async Task<bool> TryUpdateModelAsync(
[NotNull] object model,
@ -1339,7 +1366,7 @@ namespace Microsoft.AspNet.Mvc
/// Validates the specified <paramref name="model"/> instance.
/// </summary>
/// <param name="model">The model to validate.</param>
/// <returns><c>true</c> if the <see cref="ModelState"/> is valid; <c>false</c> otherwise. </returns>
/// <returns><c>true</c> if the <see cref="ModelState"/> is valid; <c>false</c> otherwise.</returns>
[NonAction]
public virtual bool TryValidateModel([NotNull] object model)
{
@ -1352,7 +1379,7 @@ namespace Microsoft.AspNet.Mvc
/// <param name="model">The model to validate.</param>
/// <param name="prefix">The key to use when looking up information in <see cref="ModelState"/>.
/// </param>
/// <returns><c>true</c> if the <see cref="ModelState"/> is valid;<c>false</c> otherwise. </returns>
/// <returns><c>true</c> if the <see cref="ModelState"/> is valid;<c>false</c> otherwise.</returns>
[NonAction]
public virtual bool TryValidateModel([NotNull] object model, string prefix)
{

View File

@ -1,27 +0,0 @@
// Copyright (c) .NET Foundation. 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;
using Microsoft.Framework.Internal;
namespace System.Web.Http
{
/// <summary>
/// Represents an action result that performs content negotiation and returns an <see cref="HttpStatusCode.OK"/>
/// response when it succeeds.
/// </summary>
/// <typeparam name="T">The type of content in the entity body.</typeparam>
public class OkNegotiatedContentResult<T> : NegotiatedContentResult<T>
{
/// <summary>
/// Initializes a new instance of the <see cref="OkNegotiatedContentResult{T}"/> class with the values
/// provided.
/// </summary>
/// <param name="content">The content value to negotiate and format in the entity body.</param>
public OkNegotiatedContentResult([NotNull] T content)
: base(HttpStatusCode.OK, content)
{
}
}
}

View File

@ -1,22 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc;
namespace System.Web.Http
{
/// <summary>
/// An action result that returns an empty <see cref="StatusCodes.Status200OK"/> response.
/// </summary>
public class OkResult : HttpStatusCodeResult
{
/// <summary>
/// Initializes a new instance of the <see cref="OkResult"/> class.
/// </summary>
public OkResult()
: base(StatusCodes.Status200OK)
{
}
}
}

View File

@ -295,25 +295,25 @@ namespace System.Web.Http
}
/// <summary>
/// Creates an <see cref="OkResult"/> (200 OK).
/// Creates an <see cref="HttpOkResult"/> (200 OK).
/// </summary>
/// <returns>An <see cref="OkResult"/>.</returns>
/// <returns>An <see cref="HttpOkResult"/>.</returns>
[NonAction]
public virtual OkResult Ok()
public virtual HttpOkResult Ok()
{
return new OkResult();
return new HttpOkResult();
}
/// <summary>
/// Creates an <see cref="OkNegotiatedContentResult{T}"/> (200 OK) with the specified values.
/// Creates an <see cref="HttpOkObjectResult"/> (200 OK) with the specified values.
/// </summary>
/// <typeparam name="T">The type of content in the entity body.</typeparam>
/// <param name="content">The content value to negotiate and format in the entity body.</param>
/// <returns>An <see cref="OkNegotiatedContentResult{T}"/> with the specified values.</returns>
/// <returns>An <see cref="HttpOkObjectResult"/> with the specified values.</returns>
[NonAction]
public virtual OkNegotiatedContentResult<T> Ok<T>([NotNull] T content)
public virtual HttpOkObjectResult Ok<T>(T content)
{
return new OkNegotiatedContentResult<T>(content);
return new HttpOkObjectResult(content);
}
/// <summary>

View File

@ -0,0 +1,99 @@
// Copyright (c) .NET Foundation. 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.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Microsoft.Framework.Logging.Testing;
using Microsoft.Framework.OptionsModel;
using Xunit;
namespace Microsoft.AspNet.Mvc
{
public class HttpOkObjectResultTest
{
public static TheoryData<object> ValuesData
{
get
{
return new TheoryData<object>
{
null,
"Test string",
new Person
{
Id = 274,
Name = "George",
}
};
}
}
[Theory]
[MemberData(nameof(ValuesData))]
public void HttpOkObjectResult_InitializesStatusCodeAndValue(object value)
{
// Arrange & Act
var result = new HttpOkObjectResult(value);
// Assert
Assert.Equal(StatusCodes.Status200OK, result.StatusCode);
Assert.Same(value, result.Value);
}
[Theory]
[MemberData(nameof(ValuesData))]
public async Task HttpOkObjectResult_SetsStatusCode(object value)
{
// Arrange
var result = new HttpOkObjectResult(value);
var httpContext = new DefaultHttpContext
{
RequestServices = CreateServices(),
};
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
// Act
await result.ExecuteResultAsync(actionContext);
// Assert
Assert.Equal(StatusCodes.Status200OK, httpContext.Response.StatusCode);
}
private IServiceProvider CreateServices()
{
var services = new ServiceCollection();
services.Add(new ServiceDescriptor(
typeof(ILogger<ObjectResult>),
new Logger<ObjectResult>(NullLoggerFactory.Instance)));
var optionsAccessor = new MockMvcOptionsAccessor();
optionsAccessor.Options.OutputFormatters.Add(new JsonOutputFormatter());
services.Add(new ServiceDescriptor(typeof(IOptions<MvcOptions>), optionsAccessor));
var bindingContext = new ActionBindingContext
{
OutputFormatters = optionsAccessor.Options.OutputFormatters,
};
var bindingContextAccessor = new MockScopedInstance<ActionBindingContext>
{
Value = bindingContext,
};
services.Add(new ServiceDescriptor(typeof(IScopedInstance<ActionBindingContext>), bindingContextAccessor));
return services.BuildServiceProvider();
}
private class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
}
}

View File

@ -1,23 +1,32 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. 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.Http;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Routing;
using Xunit;
namespace System.Web.Http
namespace Microsoft.AspNet.Mvc
{
public class OkResultTest
public class HttpOkResultTest
{
[Fact]
public async Task OkResult_SetsStatusCode()
public void HttpOkResult_InitializesStatusCode()
{
// Arrange & Act
var result = new HttpOkResult();
// Assert
Assert.Equal(StatusCodes.Status200OK, result.StatusCode);
}
[Fact]
public async Task HttpOkResult_SetsStatusCode()
{
// Arrange
var context = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
var result = new OkResult();
var result = new HttpOkResult();
// Act
await result.ExecuteResultAsync(context);

View File

@ -739,7 +739,7 @@ namespace Microsoft.AspNet.Mvc.Test
[Fact]
public void HttpUnauthorized_SetsStatusCode()
{
// Arrange
// Arrange
var controller = new TestableController();
// Act
@ -804,6 +804,45 @@ namespace Microsoft.AspNet.Mvc.Test
Times.Once());
}
[Fact]
public void Ok_SetsStatusCode()
{
// Arrange
var controller = new TestableController();
// Act
var result = controller.Ok();
// Assert
Assert.IsType<HttpOkResult>(result);
Assert.Equal(StatusCodes.Status200OK, result.StatusCode);
}
[Fact]
public void Ok_WithIDisposableObject_RegistersForDispose()
{
// Arrange
var mockHttpContext = new Mock<DefaultHttpContext>();
mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>()));
var controller = new TestableController()
{
ActionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor())
};
var input = new DisposableObject();
// Act
var result = controller.Ok(input);
// Assert
Assert.IsType<HttpOkObjectResult>(result);
Assert.Equal(StatusCodes.Status200OK, result.StatusCode);
Assert.Same(input, result.Value);
mockHttpContext.Verify(
x => x.Response.RegisterForDispose(It.IsAny<IDisposable>()),
Times.Once());
}
[Fact]
public void BadRequest_SetsStatusCode()
{

View File

@ -1,77 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if DNX451
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.Logging;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
namespace System.Web.Http
{
public class OkNegotiatedContentResultTest
{
[Fact]
public async Task OkNegotiatedContentResult_SetsStatusCode()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = CreateServices();
var stream = new MemoryStream();
httpContext.Response.Body = stream;
var context = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
var result = new OkNegotiatedContentResult<Product>(new Product());
// Act
await result.ExecuteResultAsync(context);
// Assert
Assert.Equal(StatusCodes.Status200OK, context.HttpContext.Response.StatusCode);
}
private IServiceProvider CreateServices()
{
var services = new Mock<IServiceProvider>(MockBehavior.Strict);
var options = new MvcOptions();
options.OutputFormatters.Add(new JsonOutputFormatter());
var optionsAccessor = new Mock<IOptions<MvcOptions>>();
optionsAccessor.SetupGet(o => o.Options)
.Returns(options);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters };
mockActionBindingContext
.SetupGet(o => o.Value)
.Returns(bindingContext);
services.Setup(o => o.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.Returns(mockActionBindingContext.Object);
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor.Object);
services.Setup(s => s.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
return services.Object;
}
private class Product
{
public int Id { get; set; }
public string Name { get; set; }
};
}
}
#endif

View File

@ -290,7 +290,7 @@ namespace System.Web.Http
var result = controller.Ok();
// Assert
Assert.Equal(200, Assert.IsType<OkResult>(result).StatusCode);
Assert.Equal(200, Assert.IsType<HttpOkResult>(result).StatusCode);
}
@ -305,8 +305,8 @@ namespace System.Web.Http
var result = controller.Ok(product);
// Assert
var okResult = Assert.IsType<OkNegotiatedContentResult<Product>>(result);
Assert.Same(product, okResult.Content);
var okResult = Assert.IsType<HttpOkObjectResult>(result);
Assert.Same(product, okResult.Value);
}
[Fact]

View File

@ -51,7 +51,7 @@ namespace BasicWebSite.Controllers
[RequireHttps]
public IActionResult HttpsOnlyAction()
{
return new HttpStatusCodeResult(StatusCodes.Status200OK);
return Ok();
}
public Task ActionReturningTask()