diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ActionResultOfT.cs b/src/Microsoft.AspNetCore.Mvc.Core/ActionResultOfT.cs index f443d78805..048c80ff52 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ActionResultOfT.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ActionResultOfT.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.Mvc.Core; using Microsoft.AspNetCore.Mvc.Infrastructure; namespace Microsoft.AspNetCore.Mvc @@ -18,6 +19,12 @@ namespace Microsoft.AspNetCore.Mvc /// The value. public ActionResult(TValue value) { + if (typeof(IActionResult).IsAssignableFrom(typeof(TValue))) + { + var error = Resources.FormatInvalidTypeTForActionResultOfT(typeof(TValue), "ActionResult"); + throw new ArgumentException(error); + } + Value = value; } @@ -27,6 +34,12 @@ namespace Microsoft.AspNetCore.Mvc /// The . public ActionResult(ActionResult result) { + if (typeof(IActionResult).IsAssignableFrom(typeof(TValue))) + { + var error = Resources.FormatInvalidTypeTForActionResultOfT(typeof(TValue), "ActionResult"); + throw new ArgumentException(error); + } + Result = result ?? throw new ArgumentNullException(nameof(result)); } diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs index c766cf5a59..1221fccdef 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs @@ -1480,6 +1480,20 @@ namespace Microsoft.AspNetCore.Mvc.Core internal static string FormatApiConventionMustBeStatic(object p0) => string.Format(CultureInfo.CurrentCulture, GetString("ApiConventionMustBeStatic"), p0); + /// + /// Invalid type parameter '{0}' specified for '{1}'. + /// + internal static string InvalidTypeTForActionResultOfT + { + get => GetString("InvalidTypeTForActionResultOfT"); + } + + /// + /// Invalid type parameter '{0}' specified for '{1}'. + /// + internal static string FormatInvalidTypeTForActionResultOfT(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("InvalidTypeTForActionResultOfT"), p0, p1); + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx index d912ecd0c5..98aa14bda6 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx +++ b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx @@ -445,4 +445,7 @@ API convention type '{0}' must be a static type. + + Invalid type parameter '{0}' specified for '{1}'. + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ActionResultOfTTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ActionResultOfTTest.cs index 2445e84677..8f5abec7e5 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ActionResultOfTTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ActionResultOfTTest.cs @@ -1,6 +1,8 @@ // 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.IO; using Microsoft.AspNetCore.Mvc.Infrastructure; using Xunit; @@ -8,6 +10,28 @@ namespace Microsoft.AspNetCore.Mvc { public class ActionResultOfTTest { + [Fact] + public void Constructor_WithValue_ThrowsForInvalidType() + { + // Arrange + var input = new FileStreamResult(Stream.Null, "application/json"); + + // Act & Assert + var ex = Assert.Throws(() => new ActionResult(value: input)); + Assert.Equal($"Invalid type parameter '{typeof(FileStreamResult)}' specified for 'ActionResult'.", ex.Message); + } + + [Fact] + public void Constructor_WithActionResult_ThrowsForInvalidType() + { + // Arrange + var actionResult = new OkResult(); + + // Act & Assert + var ex = Assert.Throws(() => new ActionResult(result: actionResult)); + Assert.Equal($"Invalid type parameter '{typeof(FileStreamResult)}' specified for 'ActionResult'.", ex.Message); + } + [Fact] public void Convert_ReturnsResultIfSet() {