341 lines
12 KiB
C#
341 lines
12 KiB
C#
// 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.Reflection;
|
|
using Microsoft.AspNet.Http;
|
|
using Microsoft.AspNet.Http.Internal;
|
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
|
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
|
using Microsoft.AspNet.Routing;
|
|
using Microsoft.Framework.DependencyInjection;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.AspNet.Mvc.Core
|
|
{
|
|
public class DefaultControllerFactoryTest
|
|
{
|
|
[Fact]
|
|
public void CreateController_ThrowsIfActionDescriptorIsNotControllerActionDescriptor()
|
|
{
|
|
// Arrange
|
|
var expected =
|
|
"The action descriptor must be of type 'Microsoft.AspNet.Mvc.ControllerActionDescriptor'." +
|
|
Environment.NewLine + "Parameter name: actionContext";
|
|
var actionDescriptor = new ActionDescriptor();
|
|
var controllerFactory = CreateControllerFactory();
|
|
var httpContext = new DefaultHttpContext();
|
|
var actionContext = new ActionContext(httpContext,
|
|
new RouteData(),
|
|
actionDescriptor);
|
|
|
|
// Act and Assert
|
|
var ex = Assert.Throws<ArgumentException>(() =>
|
|
controllerFactory.CreateController(actionContext));
|
|
Assert.Equal(expected, ex.Message);
|
|
Assert.Equal("actionContext", ex.ParamName);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateController_UsesControllerActivatorToInstantiateController()
|
|
{
|
|
// Arrange
|
|
var expected = new MyController();
|
|
var actionDescriptor = new ControllerActionDescriptor
|
|
{
|
|
ControllerTypeInfo = typeof(MyController).GetTypeInfo()
|
|
};
|
|
var httpContext = new DefaultHttpContext();
|
|
httpContext.RequestServices = GetServices();
|
|
var actionContext = new ActionContext(httpContext,
|
|
new RouteData(),
|
|
actionDescriptor);
|
|
var activator = new Mock<IControllerActivator>();
|
|
activator.Setup(a => a.Create(actionContext, typeof(MyController)))
|
|
.Returns(expected)
|
|
.Verifiable();
|
|
|
|
var controllerFactory = CreateControllerFactory(activator.Object);
|
|
|
|
// Act
|
|
var result = controllerFactory.CreateController(actionContext);
|
|
|
|
// Assert
|
|
var controller = Assert.IsType<MyController>(result);
|
|
Assert.Same(expected, controller);
|
|
activator.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateController_SetsPropertiesFromActionContextHierarchy()
|
|
{
|
|
// Arrange
|
|
var actionDescriptor = new ControllerActionDescriptor
|
|
{
|
|
ControllerTypeInfo = typeof(ControllerWithAttributes).GetTypeInfo()
|
|
};
|
|
var services = GetServices();
|
|
var httpContext = new DefaultHttpContext
|
|
{
|
|
RequestServices = services
|
|
};
|
|
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
|
|
var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));
|
|
|
|
// Act
|
|
var result = factory.CreateController(context);
|
|
|
|
// Assert
|
|
var controller = Assert.IsType<ControllerWithAttributes>(result);
|
|
Assert.Same(context, controller.ActionContext);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateController_SetsBindingContext()
|
|
{
|
|
// Arrange
|
|
var actionDescriptor = new ControllerActionDescriptor
|
|
{
|
|
ControllerTypeInfo = typeof(ControllerWithAttributes).GetTypeInfo()
|
|
};
|
|
var bindingContext = new ActionBindingContext();
|
|
|
|
var services = GetServices();
|
|
services.GetRequiredService<IScopedInstance<ActionBindingContext>>().Value = bindingContext;
|
|
var httpContext = new DefaultHttpContext
|
|
{
|
|
RequestServices = services
|
|
};
|
|
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
|
|
var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));
|
|
|
|
// Act
|
|
var result = factory.CreateController(context);
|
|
|
|
// Assert
|
|
var controller = Assert.IsType<ControllerWithAttributes>(result);
|
|
Assert.Same(bindingContext, controller.BindingContext);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateController_IgnoresPropertiesThatAreNotDecoratedWithAttribute()
|
|
{
|
|
// Arrange
|
|
var actionDescriptor = new ControllerActionDescriptor
|
|
{
|
|
ControllerTypeInfo = typeof(ControllerWithoutAttributes).GetTypeInfo()
|
|
};
|
|
var services = GetServices();
|
|
var httpContext = new DefaultHttpContext
|
|
{
|
|
RequestServices = services
|
|
};
|
|
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
|
|
var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));
|
|
|
|
// Act
|
|
var result = factory.CreateController(context);
|
|
|
|
// Assert
|
|
var controller = Assert.IsType<ControllerWithoutAttributes>(result);
|
|
Assert.Null(controller.ActionContext);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateController_IgnoresNonPublicProperties()
|
|
{
|
|
// Arrange
|
|
var actionDescriptor = new ControllerActionDescriptor
|
|
{
|
|
ControllerTypeInfo = typeof(ControllerWithNonVisibleProperties).GetTypeInfo()
|
|
};
|
|
var services = GetServices();
|
|
var httpContext = new DefaultHttpContext
|
|
{
|
|
RequestServices = services
|
|
};
|
|
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
|
|
var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));
|
|
|
|
// Act
|
|
var result = factory.CreateController(context);
|
|
|
|
// Assert
|
|
var controller = Assert.IsType<ControllerWithNonVisibleProperties>(result);
|
|
Assert.Null(controller.ActionContext);
|
|
Assert.Null(controller.BindingContext);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateController_ThrowsIConstructorCannotBeActivated()
|
|
{
|
|
// Arrange
|
|
var actionDescriptor = new ControllerActionDescriptor
|
|
{
|
|
ControllerTypeInfo = typeof(ControllerThatCannotBeActivated).GetTypeInfo()
|
|
};
|
|
var services = GetServices();
|
|
var httpContext = new DefaultHttpContext
|
|
{
|
|
RequestServices = services
|
|
};
|
|
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
|
|
var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));
|
|
|
|
// Act and Assert
|
|
var exception = Assert.Throws<InvalidOperationException>(() => factory.CreateController(context));
|
|
Assert.Equal(
|
|
$"Unable to resolve service for type '{typeof(TestService).FullName}' while attempting to activate " +
|
|
$"'{typeof(ControllerThatCannotBeActivated).FullName}'.",
|
|
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 = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));
|
|
|
|
// Act and Assert
|
|
var exception = Assert.Throws<InvalidOperationException>(() => factory.CreateController(context));
|
|
Assert.Equal(
|
|
$"The type '{type.FullName}' cannot be activated by '{typeof(DefaultControllerFactory).FullName}' " +
|
|
"because it is either a value type, an interface, an abstract class or an open generic type.",
|
|
exception.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void DefaultControllerFactory_DisposesIDisposableController()
|
|
{
|
|
// Arrange
|
|
var factory = CreateControllerFactory();
|
|
var controller = new MyController();
|
|
|
|
// Act + Assert
|
|
Assert.False(controller.Disposed);
|
|
|
|
factory.ReleaseController(controller);
|
|
|
|
Assert.True(controller.Disposed);
|
|
}
|
|
|
|
[Fact]
|
|
public void DefaultControllerFactory_ReleasesNonIDisposableController()
|
|
{
|
|
// Arrange
|
|
var factory = CreateControllerFactory();
|
|
var controller = new object();
|
|
|
|
// Act + Assert (does not throw)
|
|
factory.ReleaseController(controller);
|
|
}
|
|
|
|
private IServiceProvider GetServices()
|
|
{
|
|
var metadataProvider = new EmptyModelMetadataProvider();
|
|
var services = new Mock<IServiceProvider>();
|
|
services.Setup(s => s.GetService(typeof(IUrlHelper)))
|
|
.Returns(Mock.Of<IUrlHelper>());
|
|
services.Setup(s => s.GetService(typeof(IModelMetadataProvider)))
|
|
.Returns(metadataProvider);
|
|
services.Setup(s => s.GetService(typeof(IObjectModelValidator)))
|
|
.Returns(new DefaultObjectValidator(new IExcludeTypeValidationFilter[0], metadataProvider));
|
|
services
|
|
.Setup(s => s.GetService(typeof(IScopedInstance<ActionBindingContext>)))
|
|
.Returns(new MockScopedInstance<ActionBindingContext>());
|
|
services.Setup(s => s.GetService(typeof(ITempDataDictionary)))
|
|
.Returns(new Mock<ITempDataDictionary>().Object);
|
|
return services.Object;
|
|
}
|
|
|
|
private static DefaultControllerFactory CreateControllerFactory(IControllerActivator controllerActivator = null)
|
|
{
|
|
controllerActivator = controllerActivator ?? Mock.Of<IControllerActivator>();
|
|
var propertyActivators = new IControllerPropertyActivator[]
|
|
{
|
|
new DefaultControllerPropertyActivator(),
|
|
};
|
|
|
|
return new DefaultControllerFactory(controllerActivator, propertyActivators);
|
|
}
|
|
|
|
private class ControllerWithoutAttributes
|
|
{
|
|
public ActionContext ActionContext { get; set; }
|
|
|
|
public ActionBindingContext BindingContext { get; set; }
|
|
}
|
|
|
|
public class ControllerWithNonVisibleProperties
|
|
{
|
|
internal ActionContext ActionContext { get; set; }
|
|
|
|
public ActionBindingContext BindingContext { get; private set; }
|
|
}
|
|
|
|
private class ControllerWithAttributes
|
|
{
|
|
[ActionContext]
|
|
public ActionContext ActionContext { get; set; }
|
|
|
|
[ActionBindingContext]
|
|
public ActionBindingContext BindingContext { get; set; }
|
|
}
|
|
|
|
private class MyController : IDisposable
|
|
{
|
|
public bool Disposed { get; set; }
|
|
|
|
public void Dispose()
|
|
{
|
|
Disposed = true;
|
|
}
|
|
}
|
|
|
|
private class ControllerThatCannotBeActivated
|
|
{
|
|
public ControllerThatCannotBeActivated(TestService service)
|
|
{
|
|
Service = service;
|
|
}
|
|
|
|
public TestService Service { get; }
|
|
}
|
|
|
|
private class TestService
|
|
{
|
|
}
|
|
|
|
private class Controller
|
|
{
|
|
}
|
|
|
|
private class OpenGenericType<T> : Controller
|
|
{
|
|
}
|
|
|
|
private abstract class AbstractType : Controller
|
|
{
|
|
}
|
|
|
|
private interface InterfaceType
|
|
{
|
|
}
|
|
}
|
|
}
|