Transitioning to AutofacWebApiDependencyResolver from MVC's DependencyResolver - Where is .Current? - c#

I had AutoFac working properly with MVC4. I'm trying to transition to Web API 2. Here's what I've got for setting up AutoFac:
public class AutofacRegistrations
{
public static void RegisterAndSetResolver()
{
// Create the container builder.
var containerBuilder = new ContainerBuilder();
// Register the Web API controllers.
containerBuilder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// Only generate one SessionFactory ever because it is expensive.
containerBuilder.Register(x => new NHibernateConfiguration().Configure().BuildSessionFactory()).SingleInstance();
// Everything else wants an instance of Session per HTTP request, so indicate that:
containerBuilder.Register(x => x.Resolve<ISessionFactory>().OpenSession()).InstancePerApiRequest();
containerBuilder.Register(x => LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType)).InstancePerApiRequest();
containerBuilder.RegisterType<NHibernateDaoFactory>().As<IDaoFactory>().InstancePerApiRequest();
containerBuilder.RegisterType<StreamusManagerFactory>().As<IManagerFactory>().InstancePerApiRequest();
// Build the container.
ILifetimeScope container = containerBuilder.Build();
// Create the depenedency resolver.
var dependencyResolver = new AutofacWebApiDependencyResolver(container);
// Configure Web API with the dependency resolver.
GlobalConfiguration.Configuration.DependencyResolver = dependencyResolver;
}
}
I'm pretty confident all of that is correct. My problem arises when I'm trying to setup some test cases. My base class for my test cases isn't a controller so it isn't automatically passed anything. In MVC4 I did the following:
[SetUp]
public void SetUp()
{
HttpSimulator = new HttpSimulator().SimulateRequest();
Logger = DependencyResolver.Current.GetService<ILog>();
DaoFactory = DependencyResolver.Current.GetService<IDaoFactory>();
Session = DependencyResolver.Current.GetService<ISession>();
ManagerFactory = DependencyResolver.Current.GetService<IManagerFactory>();
}
[TearDown]
public void TearDown()
{
HttpSimulator.Dispose();
}
Unfortunately, there's no DependencyResolver.Current in WebAPI. So I'm left wondering how to do this properly?
This builds, but is NOT correct. I received the message "Session Closed!" when I try to execute a test case:
[SetUp]
public void SetUp()
{
using (var scope = GlobalConfiguration.Configuration.DependencyResolver.BeginScope())
{
// TODO: Consider initializing Helpers during setup to keep this DRY.
Logger = (ILog)scope.GetService(typeof(ILog));
DaoFactory = (IDaoFactory)scope.GetService(typeof(IDaoFactory));
Session = (ISession)scope.GetService(typeof(ISession));
ManagerFactory = (IManagerFactory)scope.GetService(typeof(IManagerFactory));
}
}

With WebAPI, you don't need access to the current resolver because the current dependency scope generally comes along with the inbound HttpRequestMessage. That message is also what's responsible for generating the new request scope.
You can see the code for this in the System.Net.Http.HttpRequestMessageExtensions.GetDependencyScope method.
One big thing you'll notice in WebAPI is that you don't actually need to set anything in global static values - that is, you don't need to set a global configuration/resolver because everything is instance-based now.
For testing, what this means is:
Your setup will create an HttpRequestMessage with the appropriate dependency resolver and configuration.
Your teardown will dispose of the HttpRequestMessage which will, in turn, dispose the dependency scopes, etc. down the line.
Individual tests will use HttpRequestMessage.GetDependencyScope() if they need to do manual resolution of something and the request message will be used to coordinate/pass around the scope.
In a more concrete fashion, it might look like:
private HttpRequestMessage _request;
[SetUp]
public void SetUp()
{
var builder = new ContainerBuilder();
// Register stuff.
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
var config = new HttpConfiguration();
config.DependencyResolver = resolver;
config.EnsureInitialized();
this._request = new HttpRequestMessage();
this._request.SetConfiguration(config);
}
[TearDown]
public void TearDown()
{
this._request.Dispose();
}
[Test]
public void Test()
{
// When you need to resolve something, use the request message
this._request.GetDependencyScope().GetService(typeof(TheThing));
}
What's nice about this is that you don't have to fight with global configuration settings or resetting static values after every test.
You might wonder why you'd pass around the whole request message rather than just the dependency resolver - the reason is that the request message is what coordinates and controls the lifetime of the dependency scope. Otherwise, when you call GetDependencyScope multiple times, you'll get multiple different scopes rather than the same one as you'd expect.
Some things to consider from a design perspective:
You might want to put the actual registrations of things into an Autofac module so it can be reused in both tests and in your RegisterAndSetResolver method without having to worry about global statics getting tampered with.
Instead of a RegisterAndSetResolver modifying the global static configuration, you might consider just setting the resolver on the HttpConfiguration object that gets wired up in that WebApiConfig.Register method that WebAPI gives you. Take an HttpConfiguration object in as a parameter and set the resolver on that rather than the global.
If you're doing every registration for everything in a unit test, your unit tests might be closer to "integration tests." You might consider looking at only what's required for the stuff you're testing and using a mock framework to register stubs rather than actually registering a boatload of "real stuff."
Anyway, HttpRequestMessage is the way to go for WebAPI.

Related

ReactiveUi: How can I replace the default IViewLocator when using AutoFac?

High!
I am trying to replace the default IViewLocator of ReactiveUi/Splat in WPF. I am using AutoFac as container.
My goal is very simple: ReactiveUi/Splat should use my custom implementation of IViewLocator when resolving a view for view model.
I really read every availabe tutorial and stackoverflow thread, but nothing helped.
Currently I do the following while bootstrapping: (I tried many different things...)
namespace MDM
{
public static class Bootstrapper
{
private static AutofacDependencyResolver? Locator;
private static IContainer? Container;
public static void Register()
{
Splat.Locator.CurrentMutable.InitializeSplat();
Splat.Locator.CurrentMutable.InitializeReactiveUI();
Splat.Locator.CurrentMutable.RegisterConstant<IViewLocator>(new ViewLocator());
var builder = new ContainerBuilder();
builder.RegisterType<MainWindowView>().As<IViewFor<MainWindowViewModel>>().SingleInstance();
builder.RegisterType<EinstellungenView>().As<IViewFor<EinstellungenViewModel>>().SingleInstance();
builder.RegisterType<MainWindowViewModel>().AsSelf().SingleInstance();
builder.RegisterType<EinstellungenViewModel>().AsSelf().SingleInstance();
Locator = builder.UseAutofacDependencyResolver();
builder.RegisterInstance(Locator);
Locator.InitializeReactiveUI();
Splat.Locator.SetLocator(Locator);
Container = builder.Build();
Locator.SetLifetimeScope(Container);
}
public static T Resolve<T>() where T : class
{
return Container!.Resolve<T>();
}
}
}
While debugging the following line of code in my IViewLocator is never hit:
public IViewFor? ResolveView<T>(T viewModel, string? contract = null)
{
}
So my question is: What do I need to do while bootstrapping, to tell ReactiveUi to use my IViewLocator?
If you decide to drop Splat (the IoC container used by ReactiveUI) and use Autofac, then you must go with it, especially when registering services.
Once you have registered a custom IoC container (properly), you shouldn't use Splat anymore to resolve any dependencies. Although Splat will redirect service requests to the Autofac container, I recommend against mixing the APIs.
var containerBuilder = new ContainerBuilder();
// TODO::Register application's dependencies with Autofac
/* Configure Splat to use Autofac */
var autofacResolver = containerBuilder.UseAutofacDependencyResolver();
containerBuilder.RegisterInstance(autofacResolver);
autofacResolver.InitializeReactiveUI();
// AFTER configuring the IoC redirect, register the Splat service overrides
containerBuilder.RegisterType<ViewLocator>()
.As<IViewLocator>()
.SingleInstance();
var container = containerBuilder.Build();
autofacResolver.SetLifetimeScope(container);
Don't use the Service Locator anti-pattern. The IoC container should not be distributed across the application. Neither as injected reference nor as static reference.
Use the Abstract Factory pattern instead.
For this reason, IViewLocator.ResolveView must use factories instead of the static Resolve method that you have implemented in your Bootstrapper.

Test to verify if the dependency registered correctly in windsor

I have a class which inherited from IWindsorInstaller. I use this class to install/register the dependencies. Now I want to write tests for this class.
I register in the container a dependency with parameter. Like this:
container.Register(Component.For<IXService>().ImplementedBy<XService>().DependsOn(Dependency.OnComponent("operationY", "OperationY")).LifeStyle.Singleton);
Now in my Unit-Test, I want to verify if it is registered correctly. Something like this:
_containerMock.Verify(f=>f.Register(It.IsAny<ComponentRegistration<IXService>>().ImplementedBy<XService>().DependsOn(Dependency.OnComponent("operationY", "OperationY")).LifestyleSingleton()),Times.AtLeastOnce);
I don't have any idea, what should I do?
Thanks in advance, Mo.
Your unit test is not there to prove that the container has a registration for a given service.
It's to prove that the container can resolve that service (the fact that a registration exists is an implementation detail).
So, in your unit test, just attempt to resolve your service and verify it's what you are looking for, e.g:
public void UnitTest_Prove_That_Service_Can_Be_Created()
{
var sut = new SystemUnderTest();
var container = sut.GetContainer();
var service = container.Resolve<IXService>();
// Prove the IXService resolves to an XService - i.e. the registration
// has the correct mapping.
Assert.Type<XService>(service);
}
Additionally, you might want to prove it's a singleton:
public void UnitTest_Prove_That_Service_Is_A_Singleton()
{
var sut = new SystemUnderTest();
var container = sut.GetContainer();
var service1 = container.Resolve<IXService>();
var service2 = container.Resolve<IXService>();
// Prove you got the same service back each time - i.e. it's a singleton
Assert.Equals(service1, service2);
}
EDIT
The fact that the SUT is an IWindsorInstaller doesn't really change my answer. Just tweak the unit test slightly:
public void UnitTest_Prove_That_Service_Can_Be_Created()
{
var container = new WindsorContainer();
container.Install(new SystemUnderTest());
var service = container.Resolve<IXService>();
// Prove the IXService resolves to an XService - i.e. the registration
// has the correct mapping.
Assert.Type<XService>(service);
}

Proper way to override dependencies within a scope

I'm using Simple Injector. I have a background processor which is using DI from the start. It will pickup jobs to run, and run them. However, each job needs to run within its own scope so that I can override some contextual dependencies. For example, the job needs to run within a specific security context (the one from which it was created), so I need to start a new scope and override the ISecurityContext injection so the job will be properly secured.
To accomplish this, I was creating a new container (with the proper ISecurityContext) and starting a scope, then running the job, but I'm not sure if this is an appropriate thing to do.
RunJob
private readonly Func<ISecurityContext, Container> _containerFactory;
internal async Task RunJob(BackgroundJob job) {
var parameters = job.GetParameters();
var securityContext = parameters.SecurityContext;
using (var container = _containerFactory(securityContext))
using (AsyncScopedLifestyle.BeginScope(container)) {
// Run the job within this scope.
}
}
DI Bits
container.RegisterSingleton<Func<ISecurityContext, Container>>(() => securityContext => {
var c = new Container();
RegisterDependencies(c);
c.Options.AllowOverridingRegistrations = true;
c.Register<ISecurityContext>(() => securityContext, Lifestyle.Scoped);
return c;
});
It doesn't feel right to me, but I'm not sure what the correct solution is.
The Simple Injector documentation warns about what you are doing by stating:
Warning: Do not create an infinite number of Container instances (such as one instance per request). Doing so will drain the performance of your application. The library is optimized for using a very limited number of Container instances. Creating and initializing Container instances has a large overhead, but resolving from the Container is extremely fast once initialized.
In general, you should create only one Container instance per application. This not only holds from a performance perspective, but the creation of this sort of 'child containers' in general is littered with quirks and flaws. For instance, how to ensure that registrations are singletons across the application?
So instead, don't abuse the container for your runtime state, but store it elsewhere. You can use a Scope instance as dictionary for scoped state, but it's as easy to create a simple wrapper for ISecurityContext that is registered as Scoped instance and gets initialized directly after the scope is created as seen in the following example.
// Can be part of your Composition Root
internal sealed class SecurityContextWrapper : ISecurityContext
{
// One of the rare cases that Property Injection makes sense.
public ISecurityContext WrappedSecurityContext { get; set; }
// Implement ISecurityContext methods here that delegate to WrappedSecurityContext.
}
// Composition Root. Only have 1 container for the complete application
c = new Container();
RegisterDependencies(c);
c.Register<SecurityContextWrapper>(Lifestyle.Scoped);
c.Register<ISecurityContext, SecurityContextWrapper>(Lifestyle.Scoped);
// Job logic
private readonly Container _container;
internal async Task RunJob(BackgroundJob job) {
var parameters = job.GetParameters();
var securityContext = parameters.SecurityContext;
using (AsyncScopedLifestyle.BeginScope(_container)) {
// Resolve the wapper inside the scope
var wrapper = _container.GetInstance<SecurityContextWrapper>();
// Set it's wrapped value.
wrapper.WrappedSecurityContext = securityContext;
// Run the job within this scope.
}
}
Alternatively, if you use Scope as state, you can inject a Scope instance as constructor argument of SecurityContextWrapper. That removes the need to use Property Injection, but does make your SecurityContextWrapper dependent on Simple Injector:
// Can be part of your Composition Root
internal sealed class SecurityContextWrapper : ISecurityContext
{
ISecurityContext _wrappedSecurityContext;
public SecurityContextWrapper(Scope scope)
{
_wrappedSecurityContext= (ISecurityContext)scope.GetItem(typeof(ISecurityContext));
}
// Implement ISecurityContext methods here that delegate to WrappedSecurityContext.
}
// Composition Root. Only have 1 container for the complete application
c = new Container();
RegisterDependencies(c);
c.Register<ISecurityContext, SecurityContextWrapper>(Lifestyle.Scoped);
// Job logic
private readonly Container _container;
internal async Task RunJob(BackgroundJob job) {
var parameters = job.GetParameters();
var securityContext = parameters.SecurityContext;
using (var scope = AsyncScopedLifestyle.BeginScope(_container)) {
// Set it's wrapped value.
scope.SetItem(typeof(ISecurityContext), securityContext);
// Run the job within this scope.
}
}

Nancy OWIN test interaction

I'm trying to figure out why our integration tests are not independent.
The essential part of each test is:
var builder = new ContainerBuilder();
// IoC registrations, typically SingleInstance lifetimes or RegisterInstance
var browser = new Browser(new CustomBootstrapper(builder));
// browser.Post...
// Assertions
Each test uses fresh ContainerBuilder and Browser instances.
One of our tests passes when run independently, but fails if run along with another similar test. This happens in two different test runners (TestDriven.Net and JetBrains).
Instrumenting, I can see by checking HashCodes that an object used by the first test and injected by the IoC container shows up in the second test (and doesn't match the object created there). Methods are called on the wrong object, so the test fails.
The code doesn't use static members.
Am I misunderstanding something about the way Nancy, Nancy.Testing, or OWIN works? How can these tests influence each other?
Per request, more details:
[Test]
public void Test1()
{
var organizationCache = new OrganizationCache();
// Logs Creating OrganizationCache with HashCode:43641814 (varies by run)
organizationCache.AddOrganization(organization);
ContainerBuilder builder = AutofacTestContainerBuilderFactory.CreateTestContainerBuilder();
builder.RegisterInstance(organizationCache);
var browser = new Browser(new CustomBootstrapper(builder));
BrowserResponse browserResponse = browser.Post(
"/api/...",
with => with.JsonBody(model));
browserResponse.StatusCode.ShouldBe(HttpStatusCode.OK);
}
In separate TestFixture class, with no setup/teardown on either:
[Test]
public void Test2()
{
var organizationCache = new OrganizationCache();
// Logs Creating OrganizationCache with HashCode:5337202 (varies by run)
organizationCache.AddOrganization(organization);
ContainerBuilder builder = AutofacTestContainerBuilderFactory.CreateTestContainerBuilder();
builder.RegisterInstance(organizationCache);
var browser = new Browser(new CustomBootstrapper(builder));
TestHelpers.Authenticate(browser); // log in (does a browser.Post)
BrowserResponse browserResponse = browser.Post(
"/api/...",
with => with.JsonBody(model));
browserResponse.StatusCode.ShouldBe(HttpStatusCode.Created);
// Passes if run independently, fails if run with other test
// When run with other test, system under test logs both OrganizationCache HashCodes during this test
}
Could CookieBasedSessions somehow be affecting this? (Note: I tried removing CookieBasedSessions.Enable and- separately and together- creating a new Session in the pipeline; this did not affect the issue.)
Disposing of the customBootstrapper after each test made no difference either.
(CustomBootstrapper has no static fields and descends from AutofacNancyBootstrapper. It's too long to post here.)
One of our developers found the issue in our code.
using Nancy.Authentication.Forms;
public class UserMapper : IUserMapper
{
public static IOrganizationService OrganizationService { get; set; }
// ...
}
The implementation of IOrganizationService has an OrganizationCache injected into its constructor.
The static field was the culprit.

Autofac/FluentValidation: No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested

Attempting to inject data into a FluentValidation validator:
public class MyFormValidator : AbstractValidator<MyForm>
{
private readonly IQueryable<Models.User> _users;
public MyFormValidator(IQueryable<Models.User> users)
{
_users = users;
...
}
}
My validator factory:
public class DependencyResolverValidatorFactory : ValidatorFactoryBase
{
private readonly IContainer container;
public DependencyResolverValidatorFactory(IContainer container)
{
this.container = container;
}
public override IValidator CreateInstance(Type validatorType)
{
return container.ResolveOptionalKeyed<IValidator>(validatorType);
}
}
My Autofac configurator:
public class AutofacConfigurator
{
public static void Configure()
{
var builder = new ContainerBuilder();
...
builder.RegisterType<MyFormValidator>()
.Keyed<IValidator>(typeof(IValidator<MyForm>))
.As<IValidator>()
// 2nd parameter returns IQueryable<User>
.WithParameter("users", new SqlRepository<User>(dataContext))
.InstancePerRequest();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// Register the validator factory with FluentValidation, and register
// FluentValidation as the model validator provider for the MVC framework.
// see http://www.jerriepelser.com/blog/using-fluent-validation-with-asp-net-mvc-part-3-adding-dependency-injection
var fluentValidationModelValidatorProvider =
new FluentValidationModelValidatorProvider(
new DependencyResolverValidatorFactory(container));
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
fluentValidationModelValidatorProvider.AddImplicitRequiredValidator = false;
ModelValidatorProviders.Providers.Add(fluentValidationModelValidatorProvider);
}
}
Getting the following exception:
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
I have other validators, most of which will not need data injected into them.
This is largely new ground for me (in both Autofac and FluentValidation) and am still trying to understand what I am doing here. I suspect I'm simply registering my type incorrectly. How do I fix this and properly register my type?
(My apologies if this is too similar to other questions that were already asked.)
I have zero experience with FluentValidation, but I doubt it's the cause of your issues anyway, so I'll plow forward regardless.
The exception you're getting means that Autofac can't resolve your service as 'instance per request'. There's a lot of documentation as to what this means on the Autofac documentation page. To summarize, it means that Autofac will attempt to resolve the service from a lifetime scope that is automatically created for each request sent to the webserver. When you register something as .InstancePerRequestScope() but then attempt to resolve that service outside of that scope, you'll get the DependencyResolutionException you see.
So we've established that your MyFormValidator isn't being resolved from a 'Request' scope. Why?
The custom DependencyResolverValidatorFactory you've written takes the actual IContainer that was built by Autofac, and resolves from that. This is a special type of ILifetimeScope, the 'root scope'. There's no request lifetime scope directly associated with this, so you get your exception. You need to to resolve from an ILifetimeScope that is began from the 'request' scope, or a sub-scope that is contained within the request scope.
The Autofac/MVC integration already automatically hosts a request scope (within the AutofacDependencyResolver, see the source), but your custom DependencyResolverValidatorFactory doesn't resolve from it. If you want to do that, I suppose you could modify your DependencyResolverValidatorFactory to accept the AutofacDependencyResolver instance instead, and use that to resolve.
It would look something like this:
public class DependencyResolverValidatorFactory : ValidatorFactoryBase
{
private readonly AutofacDependencyResolver resolver;
public DependencyResolverValidatorFactory(AutofacDependencyResolver resolver)
{
this.resolver = resolver;
}
public override IValidator CreateInstance(Type validatorType)
{
return resolver.RequestLiftimeScope.ResolveOptionalKeyed<IValidator>(validatorType);
}
}
Note the RequestLifetimeScope stuck in there.
Then you create this in your .Configure() method using
var resolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(resolver);
var fluentValidationModelValidatorProvider =
new FluentValidationModelValidatorProvider(
new DependencyResolverValidatorFactory(resolver));
That should get rid of the exception, assuming that this factory does indeed have a request to work from when creating instances of IValidators. If not, You might need to register using the default behavior (.InstancePerDependency(), where it creates a new instance every time it's requested) or a singleton (.SingleInstance()), depending on how/if validators can or should be shared.
Good luck.

Categories