diff --git a/src/Microsoft.AspNet.Mvc.Core/ActionResults/RedirectResult.cs b/src/Microsoft.AspNet.Mvc.Core/ActionResults/RedirectResult.cs
new file mode 100644
index 0000000000..c9e6bf1ef5
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Core/ActionResults/RedirectResult.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNet.DependencyInjection;
+using Microsoft.AspNet.Mvc.Core;
+
+namespace Microsoft.AspNet.Mvc
+{
+ public class RedirectResult : IActionResult
+ {
+ public RedirectResult(string url)
+ : this(url, permanent: false)
+ {
+ }
+
+ public RedirectResult(string url, bool permanent)
+ {
+ if (string.IsNullOrEmpty(url))
+ {
+ throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, "url");
+ }
+
+ Permanent = permanent;
+ Url = url;
+ }
+
+ public bool Permanent { get; private set; }
+
+ public string Url { get; private set; }
+
+ public async Task ExecuteResultAsync([NotNull] ActionContext context)
+ {
+ // It is redirected directly to the input URL.
+ // We would use the context to construct the full URL,
+ // only when relative URLs are supported. (Issue - WEBFX-202)
+ context.HttpContext.Response.Redirect(Url, Permanent);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.Core/Controller.cs b/src/Microsoft.AspNet.Mvc.Core/Controller.cs
index 14584a8afe..f652bc911a 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Controller.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Controller.cs
@@ -1,5 +1,7 @@
-using System.Text;
+using System;
+using System.Text;
using Microsoft.AspNet.Abstractions;
+using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
@@ -97,5 +99,25 @@ namespace Microsoft.AspNet.Mvc
{
return Result.Json(value);
}
+
+ public virtual RedirectResult Redirect(string url)
+ {
+ if (string.IsNullOrEmpty(url))
+ {
+ throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, "url");
+ }
+
+ return new RedirectResult(url);
+ }
+
+ public virtual RedirectResult RedirectPermanent(string url)
+ {
+ if (string.IsNullOrEmpty(url))
+ {
+ throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, "url");
+ }
+
+ return new RedirectResult(url, permanent: true);
+ }
}
}
diff --git a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs
index 862d4280d6..a81a357d42 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs
@@ -250,6 +250,22 @@ namespace Microsoft.AspNet.Mvc.Core
return string.Format(CultureInfo.CurrentCulture, GetString("DefaultControllerFactory_ActionDescriptorMustBeReflected"), p0);
}
+ ///
+ /// The value cannot be null or empty.
+ ///
+ internal static string ArgumentCannotBeNullOrEmpty
+ {
+ get { return GetString("ArgumentCannotBeNullOrEmpty"); }
+ }
+
+ ///
+ /// The value cannot be null or empty.
+ ///
+ internal static string FormatArgumentCannotBeNullOrEmpty()
+ {
+ return GetString("ArgumentCannotBeNullOrEmpty");
+ }
+
///
/// The '{0}' property of '{1}' must not be null.
///
@@ -267,7 +283,7 @@ namespace Microsoft.AspNet.Mvc.Core
}
///
- /// The '{0}' must return a non null '{1}'.
+ /// The '{0}' must return a non-null '{1}'.
///
internal static string MethodMustReturnNotNullValue
{
@@ -275,7 +291,7 @@ namespace Microsoft.AspNet.Mvc.Core
}
///
- /// The '{0}' must return a non null '{1}'.
+ /// The '{0}' must return a non-null '{1}'.
///
internal static string FormatMethodMustReturnNotNullValue(object p0, object p1)
{
@@ -287,7 +303,7 @@ namespace Microsoft.AspNet.Mvc.Core
var value = _resourceManager.GetString(name);
System.Diagnostics.Debug.Assert(value != null);
-
+
if (formatterNames != null)
{
for (var i = 0; i < formatterNames.Length; i++)
diff --git a/src/Microsoft.AspNet.Mvc.Core/Resources.resx b/src/Microsoft.AspNet.Mvc.Core/Resources.resx
index 7698b726e2..4ee4643c8b 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Resources.resx
+++ b/src/Microsoft.AspNet.Mvc.Core/Resources.resx
@@ -162,6 +162,9 @@
The action descriptor must be of type '{0}'.
+
+ The value cannot be null or empty.
+
The '{0}' property of '{1}' must not be null.
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs
index 25cf8e4432..0fa90f45a5 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs
@@ -1,5 +1,7 @@
-using Microsoft.AspNet.Mvc.ModelBinding;
+using System;
+using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
+using Microsoft.AspNet.Testing;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core
@@ -27,5 +29,59 @@ namespace Microsoft.AspNet.Mvc.Core
Assert.Equal("property", controller.ViewBag.Another);
Assert.Equal("property", controller.ViewData["Another"]);
}
+
+ [Fact]
+ public void Redirect_Temporary_SetsSameUrl()
+ {
+ // Arrange
+ var controller = new Controller();
+
+ // Act
+ var result = controller.Redirect("sample\\url");
+
+ // Assert
+ Assert.False(result.Permanent);
+ Assert.Equal("sample\\url", result.Url);
+ }
+
+ [Fact]
+ public void Redirect_Permanent_SetsSameUrl()
+ {
+ // Arrange
+ var controller = new Controller();
+
+ // Act
+ var result = controller.RedirectPermanent("sample\\url");
+
+ // Assert
+ Assert.True(result.Permanent);
+ Assert.Equal("sample\\url", result.Url);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void Redirect_NullOrEmptyUrl_Throws(string url)
+ {
+ // Arrange
+ var controller = new Controller();
+
+ // Act & Assert
+ ExceptionAssert.ThrowsArgument(
+ () => controller.Redirect(url: url), "url", "The value cannot be null or empty");
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void RedirectPermanent_NullOrEmptyUrl_Throws(string url)
+ {
+ // Arrange
+ var controller = new Controller();
+
+ // Act & Assert
+ ExceptionAssert.ThrowsArgument(
+ () => controller.RedirectPermanent(url: url), "url", "The value cannot be null or empty");
+ }
}
}