diff --git a/src/Microsoft.AspNet.Mvc.Core/DefaultControllerFactory.cs b/src/Microsoft.AspNet.Mvc.Core/DefaultControllerFactory.cs index 4da4083e58..926f7accb3 100644 --- a/src/Microsoft.AspNet.Mvc.Core/DefaultControllerFactory.cs +++ b/src/Microsoft.AspNet.Mvc.Core/DefaultControllerFactory.cs @@ -62,6 +62,17 @@ namespace Microsoft.AspNet.Mvc } var controllerType = actionDescriptor.ControllerTypeInfo.AsType(); + var controllerTypeInfo = controllerType.GetTypeInfo(); + if (controllerTypeInfo.IsValueType || + controllerTypeInfo.IsInterface || + controllerTypeInfo.IsAbstract || + (controllerTypeInfo.IsGenericType && controllerTypeInfo.IsGenericTypeDefinition)) + { + var message = Resources.FormatValueInterfaceAbstractOrOpenGenericTypesCannotBeActivated( + controllerType.FullName, GetType().FullName); + throw new InvalidOperationException(message); + } + var controller = _controllerActivator.Create(actionContext, controllerType); ActivateProperties(controller, actionContext); @@ -87,13 +98,6 @@ namespace Microsoft.AspNet.Mvc protected virtual void ActivateProperties([NotNull] object controller, [NotNull] ActionContext context) { var controllerType = controller.GetType(); - var controllerTypeInfo = controllerType.GetTypeInfo(); - if (controllerTypeInfo.IsValueType) - { - var message = Resources.FormatValueTypesCannotBeActivated(GetType().FullName); - throw new InvalidOperationException(message); - } - var propertiesToActivate = _activateActions.GetOrAdd(controllerType, _getPropertiesToActivate); diff --git a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs index d6212aa949..7b96a7681b 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs @@ -1082,22 +1082,6 @@ namespace Microsoft.AspNet.Mvc.Core return string.Format(CultureInfo.CurrentCulture, GetString("ActionResult_ActionReturnValueCannotBeNull"), p0); } - /// - /// Value types cannot be activated by '{0}'. - /// - internal static string ValueTypesCannotBeActivated - { - get { return GetString("ValueTypesCannotBeActivated"); } - } - - /// - /// Value types cannot be activated by '{0}'. - /// - internal static string FormatValueTypesCannotBeActivated(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("ValueTypesCannotBeActivated"), p0); - } - /// /// The type '{0}' must derive from '{1}'. /// @@ -1786,6 +1770,22 @@ namespace Microsoft.AspNet.Mvc.Core return string.Format(CultureInfo.CurrentCulture, GetString("TempData_CannotSerializeDictionary"), p0, p1); } + /// + /// The type '{0}' cannot be activated by '{1}' because it is either a value type, an interface, an abstract class or an open generic type. + /// + internal static string ValueInterfaceAbstractOrOpenGenericTypesCannotBeActivated + { + get { return GetString("ValueInterfaceAbstractOrOpenGenericTypesCannotBeActivated"); } + } + + /// + /// The type '{0}' cannot be activated by '{1}' because it is either a value type, an interface, an abstract class or an open generic type. + /// + internal static string FormatValueInterfaceAbstractOrOpenGenericTypesCannotBeActivated(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("ValueInterfaceAbstractOrOpenGenericTypesCannotBeActivated"), p0, p1); + } + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/Microsoft.AspNet.Mvc.Core/Resources.resx b/src/Microsoft.AspNet.Mvc.Core/Resources.resx index 7db062ae64..ccf380dd34 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Resources.resx +++ b/src/Microsoft.AspNet.Mvc.Core/Resources.resx @@ -319,9 +319,6 @@ Cannot return null from an action method with a return type of '{0}'. - - Value types cannot be activated by '{0}'. - The type '{0}' must derive from '{1}'. @@ -460,4 +457,7 @@ The '{0}' cannot serialize a dictionary with a key of type '{1}' to session state. + + The type '{0}' cannot be activated by '{1}' because it is either a value type, an interface, an abstract class or an open generic type. + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/DefaultControllerFactoryTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/DefaultControllerFactoryTest.cs index 73f8cbb2b1..373b87cf70 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/DefaultControllerFactoryTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/DefaultControllerFactoryTest.cs @@ -188,6 +188,33 @@ namespace Microsoft.AspNet.Mvc.Core "' cannot be activated.", exception.Message); } + [Theory] + [InlineData(typeof(int))] + [InlineData(typeof(OpenGenericType<>))] + [InlineData(typeof(AbstractType))] + [InlineData(typeof(InterfaceType))] + public void CreateController_ThrowsIfControllerCannotBeActivated(Type type) + { + // Arrange + var actionDescriptor = new ControllerActionDescriptor + { + ControllerTypeInfo = type.GetTypeInfo() + }; + var services = GetServices(); + var httpContext = new DefaultHttpContext + { + RequestServices = services + }; + var context = new ActionContext(httpContext, new RouteData(), actionDescriptor); + var factory = new DefaultControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache())); + + // Act and Assert + var exception = Assert.Throws(() => factory.CreateController(context)); + Assert.Equal("The type '" + type.FullName + "' cannot be activated by '" + typeof(DefaultControllerFactory) + + "' because it is either a value type, an interface, an abstract class or an open generic type.", + exception.Message); + } + [Fact] public void DefaultControllerFactory_DisposesIDisposableController() { @@ -290,5 +317,20 @@ namespace Microsoft.AspNet.Mvc.Core { } + + private class OpenGenericType : Controller + { + + } + + private abstract class AbstractType : Controller + { + + } + + private interface InterfaceType + { + + } } }