diff --git a/src/Microsoft.AspNet.Mvc.Core/ActionContext.cs b/src/Microsoft.AspNet.Mvc.Core/ActionContext.cs
index b76135615c..c44b071fe1 100644
--- a/src/Microsoft.AspNet.Mvc.Core/ActionContext.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/ActionContext.cs
@@ -12,6 +12,17 @@ namespace Microsoft.AspNet.Mvc
///
public class ActionContext
{
+ ///
+ /// Creates a empty .
+ ///
+ ///
+ /// The default constructor is provided for unit test purposes only.
+ ///
+ public ActionContext()
+ {
+ ModelState = new ModelStateDictionary();
+ }
+
///
/// Creates a new .
///
@@ -56,23 +67,44 @@ namespace Microsoft.AspNet.Mvc
}
///
- /// Gets the for the selected action.
+ /// Gets or sets the for the selected action.
///
- public ActionDescriptor ActionDescriptor { get; }
+ ///
+ /// The property setter is provided for unit test purposes only.
+ ///
+ public ActionDescriptor ActionDescriptor
+ {
+ get; set;
+ }
///
- /// Gets the for the current request.
+ /// Gets or sets the for the current request.
///
- public HttpContext HttpContext { get; }
+ ///
+ /// The property setter is provided for unit test purposes only.
+ ///
+ public HttpContext HttpContext
+ {
+ get; set;
+ }
///
/// Gets the .
///
- public ModelStateDictionary ModelState { get; }
+ public ModelStateDictionary ModelState
+ {
+ get;
+ }
///
- /// Gets the for the current request.
+ /// Gets or sets the for the current request.
///
- public RouteData RouteData { get; }
+ ///
+ /// The property setter is provided for unit test purposes only.
+ ///
+ public RouteData RouteData
+ {
+ get; set;
+ }
}
-}
+}
\ 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 3220131163..4350b2fb62 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Controller.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Controller.cs
@@ -20,6 +20,7 @@ namespace Microsoft.AspNet.Mvc
{
private DynamicViewData _viewBag;
private ViewDataDictionary _viewData;
+ private ActionContext _actionContext;
public IServiceProvider Resolver
{
@@ -69,8 +70,32 @@ namespace Microsoft.AspNet.Mvc
}
}
+ ///
+ /// Gets or sets the object.
+ ///
+ ///
+ /// activates this property while activating controllers. If user codes
+ /// directly instantiate controllers, the getter returns an empty .
+ ///
[Activate]
- public ActionContext ActionContext { get; set; }
+ public ActionContext ActionContext
+ {
+ get
+ {
+ // This should run only for the controller unit test scenarios
+ _actionContext = _actionContext ?? new ActionContext();
+ return _actionContext;
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ _actionContext = value;
+ }
+ }
[Activate]
public ActionBindingContext BindingContext { get; set; }
@@ -822,7 +847,7 @@ namespace Microsoft.AspNet.Mvc
}
///
- /// Updates the specified instance using values from the controller's current
+ /// Updates the specified instance using values from the controller's current
/// and a .
///
/// The type of the model object.
@@ -847,7 +872,7 @@ namespace Microsoft.AspNet.Mvc
}
///
- /// Updates the specified instance using the and a
+ /// Updates the specified instance using the and a
/// .
///
/// The type of the model object.
@@ -882,14 +907,14 @@ namespace Microsoft.AspNet.Mvc
}
///
- /// Updates the specified instance using values from the controller's current
+ /// Updates the specified instance using values from the controller's current
/// and a .
///
/// The type of the model object.
/// The model instance to update.
/// The prefix to use when looking up values in the current .
///
- /// (s) which represent top-level properties
+ /// (s) which represent top-level properties
/// which need to be included for the current model.
/// A that on completion returns true if the update is successful
[NonAction]
@@ -920,7 +945,7 @@ namespace Microsoft.AspNet.Mvc
}
///
- /// Updates the specified instance using values from the controller's current
+ /// Updates the specified instance using values from the controller's current
/// and a .
///
/// The type of the model object.
@@ -957,7 +982,7 @@ namespace Microsoft.AspNet.Mvc
}
///
- /// Updates the specified instance using the and a
+ /// Updates the specified instance using the and a
/// .
///
/// The type of the model object.
@@ -965,7 +990,7 @@ namespace Microsoft.AspNet.Mvc
/// The prefix to use when looking up values in the
///
/// The used for looking up values.
- /// (s) which represent top-level properties
+ /// (s) which represent top-level properties
/// which need to be included for the current model.
/// A that on completion returns true if the update is successful
[NonAction]
@@ -997,7 +1022,7 @@ namespace Microsoft.AspNet.Mvc
}
///
- /// Updates the specified instance using the and a
+ /// Updates the specified instance using the and a
/// .
///
/// The type of the model object.
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs
index 70145c2af7..88e8dbfd2e 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerTests.cs
@@ -1277,7 +1277,7 @@ namespace Microsoft.AspNet.Mvc.Test
var binder = new Mock();
var controller = GetController(binder.Object, provider: null);
controller.BindingContext.ValidatorProvider = provider.Object;
-
+
// Act
var result = controller.TryValidateModel(model, "Prefix");
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerUnitTestabilityTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerUnitTestabilityTests.cs
index ad2aee496f..409045d2cf 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerUnitTestabilityTests.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerUnitTestabilityTests.cs
@@ -5,7 +5,11 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
+using Microsoft.AspNet.Http;
+using Microsoft.AspNet.Mvc.ModelBinding;
+using Microsoft.AspNet.Routing;
using Microsoft.AspNet.WebUtilities;
+using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc
@@ -424,6 +428,83 @@ namespace Microsoft.AspNet.Mvc
Assert.Throws(() => controller.Redirect_Action(null));
}
+ [Fact]
+ public void ControllerActionContext_ReturnsNotNull()
+ {
+ // Arrange && Act
+ var controller = new TestabilityController();
+
+ // Assert
+ Assert.NotNull(controller.ActionContext);
+ Assert.NotNull(controller.ActionContext.ModelState);
+ Assert.Null(controller.ActionContext.ActionDescriptor);
+ Assert.Null(controller.ActionContext.HttpContext);
+ Assert.Null(controller.ActionContext.RouteData);
+ }
+
+ [Fact]
+ public void ActionContextDefaultConstructor_CanBeUsedForControllerActionContext()
+ {
+ // Arrange
+ var actionContext = new ActionContext();
+ var controller = new TestabilityController();
+
+ // Act
+ controller.ActionContext = actionContext;
+
+ // Assert
+ Assert.Equal(actionContext.HttpContext, controller.Context);
+ Assert.Equal(actionContext.RouteData, controller.RouteData);
+ Assert.Equal(actionContext.ModelState, controller.ModelState);
+ }
+
+ [Fact]
+ public void ActionContextSetters_CanBeUsedWithControllerActionContext()
+ {
+ // Arrange
+ var actionDescriptor = new Mock();
+ var httpContext = new Mock();
+ var routeData = new Mock();
+
+ var actionContext = new ActionContext()
+ {
+ ActionDescriptor = actionDescriptor.Object,
+ HttpContext = httpContext.Object,
+ RouteData = routeData.Object,
+ };
+
+ var controller = new TestabilityController();
+
+ // Act
+ controller.ActionContext = actionContext;
+
+ // Assert
+ Assert.Equal(httpContext.Object, controller.Context);
+ Assert.Equal(routeData.Object, controller.RouteData);
+ Assert.Equal(actionContext.ModelState, controller.ModelState);
+ Assert.Equal(actionDescriptor.Object, actionContext.ActionDescriptor);
+ }
+
+ [Fact]
+ public void ActionContextModelState_ShouldBeSameAsViewDataAndControllerModelState()
+ {
+ // Arrange
+ var actionContext = new ActionContext();
+ var controller1 = new Controller();
+ var controller2 = new Controller();
+
+ // Act
+ controller2.ActionContext = actionContext;
+
+ // Assert
+ Assert.Equal(controller1.ModelState, controller1.ActionContext.ModelState);
+ Assert.Equal(controller1.ModelState, controller1.ViewData.ModelState);
+
+ Assert.Equal(actionContext.ModelState, controller2.ModelState);
+ Assert.Equal(actionContext.ModelState, controller2.ActionContext.ModelState);
+ Assert.Equal(actionContext.ModelState, controller2.ViewData.ModelState);
+ }
+
public static IEnumerable