diff --git a/src/Splat.Autofac.Tests/DependencyResolverTests.cs b/src/Splat.Autofac.Tests/DependencyResolverTests.cs index 34ca06aae..478c71394 100644 --- a/src/Splat.Autofac.Tests/DependencyResolverTests.cs +++ b/src/Splat.Autofac.Tests/DependencyResolverTests.cs @@ -26,7 +26,9 @@ public void AutofacDependencyResolver_Should_Resolve_Views() var builder = new ContainerBuilder(); builder.RegisterType().As>(); builder.RegisterType().As>(); - builder.Build().UseAutofacDependencyResolver(); + + var autofacResolver = builder.UseAutofacDependencyResolver(); + autofacResolver.SetLifetimeScope(builder.Build()); var viewOne = Locator.Current.GetService(typeof(IViewFor)); var viewTwo = Locator.Current.GetService(typeof(IViewFor)); @@ -45,7 +47,9 @@ public void AutofacDependencyResolver_Should_Resolve_Named_View() { var builder = new ContainerBuilder(); builder.RegisterType().Named>("Other"); - builder.Build().UseAutofacDependencyResolver(); + + var autofacResolver = builder.UseAutofacDependencyResolver(); + autofacResolver.SetLifetimeScope(builder.Build()); var viewTwo = Locator.Current.GetService(typeof(IViewFor), "Other"); @@ -62,7 +66,9 @@ public void AutofacDependencyResolver_Should_Resolve_View_Models() var builder = new ContainerBuilder(); builder.RegisterType().AsSelf(); builder.RegisterType().AsSelf(); - builder.Build().UseAutofacDependencyResolver(); + + var autofacResolver = builder.UseAutofacDependencyResolver(); + autofacResolver.SetLifetimeScope(builder.Build()); var vmOne = Locator.Current.GetService(); var vmTwo = Locator.Current.GetService(); @@ -79,7 +85,9 @@ public void AutofacDependencyResolver_Should_Resolve_Screen() { var builder = new ContainerBuilder(); builder.RegisterType().As().SingleInstance(); - builder.Build().UseAutofacDependencyResolver(); + + var autofacResolver = builder.UseAutofacDependencyResolver(); + autofacResolver.SetLifetimeScope(builder.Build()); var screen = Locator.Current.GetService(); @@ -91,10 +99,12 @@ public void AutofacDependencyResolver_Should_Resolve_Screen() /// Should throw an exception if service registration call back called. /// [Fact] - public void AutofacDependencyResolver_Should_Throw_If_ServiceRegistionCallback_Called() + public void AutofacDependencyResolver_Should_Throw_If_ServiceRegistrationCallback_Called() { - var container = new ContainerBuilder(); - container.UseAutofacDependencyResolver(); + var builder = new ContainerBuilder(); + + var autofacResolver = builder.UseAutofacDependencyResolver(); + autofacResolver.SetLifetimeScope(builder.Build()); var result = Record.Exception(() => Locator.CurrentMutable.ServiceRegistrationCallback(typeof(IScreen), disposable => { })); @@ -111,15 +121,18 @@ public void AutofacDependencyResolver_Should_Throw_If_ServiceRegistionCallback_C [Fact] public void AutofacDependencyResolver_Should_ReturnRegisteredLogger() { - var container = new ContainerBuilder(); - container.UseAutofacDependencyResolver(); + var builder = new ContainerBuilder(); + + var autofacResolver = builder.UseAutofacDependencyResolver(); Locator.CurrentMutable.RegisterConstant( new FuncLogManager(type => new WrappingFullLogger(new ConsoleLogger())), typeof(ILogManager)); - var d = Splat.Locator.Current.GetService(); - Assert.IsType(d); + autofacResolver.SetLifetimeScope(builder.Build()); + + var logManager = Locator.Current.GetService(); + Assert.IsType(logManager); } /// @@ -132,20 +145,96 @@ public void AutofacDependencyResolver_Should_ReturnRegisteredLogger() public void AutofacDependencyResolver_PreInit_Should_ReturnRegisteredLogger() { var builder = new ContainerBuilder(); + + var autofacResolver = builder.UseAutofacDependencyResolver(); + builder.Register(_ => new FuncLogManager(type => new WrappingFullLogger(new ConsoleLogger()))).As(typeof(ILogManager)) .AsImplementedInterfaces(); - builder.UseAutofacDependencyResolver(); + autofacResolver.SetLifetimeScope(builder.Build()); - var d = Splat.Locator.Current.GetService(); - Assert.IsType(d); + var logManager = Locator.Current.GetService(); + Assert.IsType(logManager); + } + + /// + /// + /// + [Fact] + public override void UnregisterCurrent_Doesnt_Throw_When_List_Empty() + { + } + + /// + /// + /// + [Fact] + public override void UnregisterCurrent_Remove_Last() + { + } + + /// + /// + /// + [Fact] + public override void UnregisterCurrentByName_Doesnt_Throw_When_List_Empty() + { + } + + /// + /// + /// + [Fact] + public override void UnregisterAll_UnregisterCurrent_Doesnt_Throw_When_List_Empty() + { + } + + /// + /// + /// + [Fact] + public override void UnregisterAllByContract_UnregisterCurrent_Doesnt_Throw_When_List_Empty() + { + } + + /// + /// + /// + /// + [Fact] + public override void HasRegistration() + { + var type = typeof(string); + const string contractOne = "ContractOne"; + const string contractTwo = "ContractTwo"; + var resolver = GetDependencyResolver(); + + Assert.False(resolver.HasRegistration(type)); + Assert.False(resolver.HasRegistration(type, contractOne)); + Assert.False(resolver.HasRegistration(type, contractTwo)); + + resolver.Register(() => "unnamed", type); + Assert.True(resolver.HasRegistration(type)); + Assert.False(resolver.HasRegistration(type, contractOne)); + Assert.False(resolver.HasRegistration(type, contractTwo)); + + resolver.Register(() => contractOne, type, contractOne); + Assert.True(resolver.HasRegistration(type)); + Assert.True(resolver.HasRegistration(type, contractOne)); + Assert.False(resolver.HasRegistration(type, contractTwo)); + + resolver.Register(() => contractTwo, type, contractTwo); + Assert.True(resolver.HasRegistration(type)); + Assert.True(resolver.HasRegistration(type, contractOne)); + Assert.True(resolver.HasRegistration(type, contractTwo)); } /// protected override AutofacDependencyResolver GetDependencyResolver() { - var container = new ContainerBuilder(); - return new AutofacDependencyResolver(container.Build()); + var builder = new ContainerBuilder(); + + return builder.UseAutofacDependencyResolver(); } } } diff --git a/src/Splat.Autofac.Tests/Splat.Autofac.Tests.csproj b/src/Splat.Autofac.Tests/Splat.Autofac.Tests.csproj index cd7b9fa9b..4e829d514 100644 --- a/src/Splat.Autofac.Tests/Splat.Autofac.Tests.csproj +++ b/src/Splat.Autofac.Tests/Splat.Autofac.Tests.csproj @@ -8,10 +8,6 @@ $(NoWarn);1591;CA1707;SA1633;CA2000 - - - - diff --git a/src/Splat.Autofac/AutofacDependencyResolver.cs b/src/Splat.Autofac/AutofacDependencyResolver.cs index 73be503f1..ea00ea8e5 100644 --- a/src/Splat.Autofac/AutofacDependencyResolver.cs +++ b/src/Splat.Autofac/AutofacDependencyResolver.cs @@ -6,11 +6,9 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using Autofac; using Autofac.Core; -using Autofac.Core.Registration; #pragma warning disable CS0618 // Obsolete values. @@ -22,15 +20,35 @@ namespace Splat.Autofac public class AutofacDependencyResolver : IDependencyResolver { private readonly object _lockObject = new object(); - private IComponentContext _componentContext; + private readonly ContainerBuilder _builder; + + /// + /// The internal container, which takes care of mutability needed for ReactiveUI initialization procedure. + /// It is disposed of once the user sets the actual lifetime scope from which to resolve by calling SetLifetimeScope. + /// + private IContainer _internalContainer; + + private ILifetimeScope _lifetimeScope; +#pragma warning disable CA2213 // _internalLifetimeScope will be disposed, because it is a child of _internalContainer + private ILifetimeScope _internalLifetimeScope; +#pragma warning restore CA2213 // Disposable fields should be disposed + + /// + /// Set to true, when SetLifetimeScope has been called. + /// Prevents mutating the ContainerBuilder or setting the lifetime again. + /// + private bool _lifetimeScopeSet; /// /// Initializes a new instance of the class. /// - /// The component context. - public AutofacDependencyResolver(IComponentContext componentContext) + /// Autofac container builder. + public AutofacDependencyResolver(ContainerBuilder builder) { - _componentContext = componentContext; + _builder = builder; + + _internalContainer = new ContainerBuilder().Build(); + _internalLifetimeScope = _internalContainer.BeginLifetimeScope(); } /// @@ -42,6 +60,30 @@ public virtual object GetService(Type serviceType, string contract = null) } } + /// + /// Sets the lifetime scope which will be used to resolve ReactiveUI services. + /// It should be set after Autofac application-wide container is built. + /// + /// Lifetime scope, which will be used to resolve ReactiveUI services. + public void SetLifetimeScope(ILifetimeScope lifetimeScope) + { + lock (_lockObject) + { + if (_lifetimeScopeSet) + { + throw new Exception("Lifetime scope of the Autofac resolver has already been set"); + } + + _lifetimeScopeSet = true; + _lifetimeScope = lifetimeScope; + + // We dispose on the internal container, since it and its many child lifetime scopes are not needed anymore. + _internalContainer.Dispose(); + _internalContainer = null; + _internalLifetimeScope = null; + } + } + /// public virtual IEnumerable GetServices(Type serviceType, string contract = null) { @@ -65,183 +107,96 @@ public bool HasRegistration(Type serviceType, string contract = null) { lock (_lockObject) { - return _componentContext.ComponentRegistry.Registrations.Any(x => GetWhetherServiceRegistrationMatchesSearch( - x.Services, - serviceType, - contract)); + var lifeTimeScope = _lifetimeScope ?? _internalLifetimeScope; + + return string.IsNullOrEmpty(contract) ? + lifeTimeScope.IsRegistered(serviceType) : + lifeTimeScope.IsRegisteredWithName(contract, serviceType); } } /// - /// Register a function with the resolver which will generate a object - /// for the specified service type. - /// Optionally a contract can be registered which will indicate - /// that that registration will only work with that contract. - /// Most implementations will use a stack based approach to allow for multile items to be registered. + /// Important: Because Autofac 5+ containers are immutable, + /// this method should not be used by the end-user. + /// It is still needed to satisfy ReactiveUI initialization procedure. + /// Register a function with the resolver which will generate a object + /// for the specified service type. + /// Optionally a contract can be registered which will indicate + /// that that registration will only work with that contract. + /// Most implementations will use a stack based approach to allow for multiple items to be registered. /// /// The factory function which generates our object. /// The type which is used for the registration. /// A optional contract value which will indicates to only generate the value if this contract is specified. + [Obsolete("Because Autofac 5+ containers are immutable, this method should not be used by the end-user.")] public virtual void Register(Func factory, Type serviceType, string contract = null) { lock (_lockObject) { - var builder = new ContainerBuilder(); + if (_lifetimeScopeSet) + { + throw new Exception("Container has already been built and the lifetime scope set, so it is not possible to modify it anymore."); + } + + // We register every ReactiveUI service twice. + // First to the application-wide container, which we are still building. + // Second to child lifetimes in a temporary container, that is used only to satisfy ReactiveUI dependencies. if (string.IsNullOrEmpty(contract)) { - builder.Register(x => factory()).As(serviceType).AsImplementedInterfaces(); + _builder.Register(_ => factory()) + .As(serviceType) + .AsImplementedInterfaces(); + _internalLifetimeScope = _internalLifetimeScope.BeginLifetimeScope(internalBuilder => + internalBuilder.Register(_ => factory()) + .As(serviceType) + .AsImplementedInterfaces()); } else { - builder.Register(x => factory()).Named(contract, serviceType).AsImplementedInterfaces(); + _builder.Register(_ => factory()) + .Named(contract, serviceType) + .AsImplementedInterfaces(); + _internalLifetimeScope = _internalLifetimeScope.BeginLifetimeScope(internalBuilder => + internalBuilder.Register(_ => factory()) + .Named(contract, serviceType) + .AsImplementedInterfaces()); } - - builder.Update(_componentContext.ComponentRegistry); } } /// - /// Unregisters the current item based on the specified type and contract. - /// https://stackoverflow.com/questions/5091101/is-it-possible-to-remove-an-existing-registration-from-autofac-container-builder. + /// Because Autofac 5+ containers are immutable, + /// UnregisterCurrent method is not available anymore. + /// Instead, simply register your service after InitializeReactiveUI to override it. /// /// The service type to unregister. /// The optional contract value, which will only remove the value associated with the contract. /// This is not implemented by default. /// - public virtual void UnregisterCurrent(Type serviceType, string contract = null) - { - lock (_lockObject) - { - var registrations = _componentContext.ComponentRegistry.Registrations.ToList(); - var registrationCount = registrations.Count; - if (registrationCount < 1) - { - return; - } - - var candidatesForRemoval = new List(registrationCount); - var registrationIndex = 0; - while (registrationIndex < registrationCount) - { - var componentRegistration = registrations[registrationIndex]; - - var isCandidateForRemoval = GetWhetherServiceRegistrationMatchesSearch( - componentRegistration.Services, - serviceType, - contract); - if (isCandidateForRemoval) - { - registrations.RemoveAt(registrationIndex); - candidatesForRemoval.Add(componentRegistration); - registrationCount--; - } - else - { - registrationIndex++; - } - } - - if (candidatesForRemoval.Count == 0) - { - // nothing to remove - return; - } - - if (candidatesForRemoval.Count > 1) - { - // need to re-add some registrations - var reAdd = candidatesForRemoval.Take(candidatesForRemoval.Count - 1); - registrations.AddRange(reAdd); - - /* - // check for multi service registration - // in future might want to just remove a single service from a component - // rather than do the whole component. - var lastCandidate = candidatesForRemoval.Last(); - var lastCandidateRegisteredServices = lastCandidate.Services.ToArray(); - if (lastCandidateRegisteredServices.Length > 1) - { - // - // builder.RegisterType() - // .AsSelf() - // .As() - // .As(); - var survivingServices = lastCandidateRegisteredServices.Where(s => s.GetType() != serviceType); - var newRegistration = new ComponentRegistration( - lastCandidate.Id, - lastCandidate.Activator, - lastCandidate.Lifetime, - lastCandidate.Sharing, - lastCandidate.Ownership, - survivingServices, - lastCandidate.Metadata); - registrations.Add(newRegistration); - } - */ - } - - RemoveAndRebuild(registrations); - } - } + [Obsolete("Because Autofac 5+ containers are immutable, UnregisterCurrent method is not available anymore. " + + "Instead, simply register your service after InitializeReactiveUI to override it https://autofaccn.readthedocs.io/en/latest/register/registration.html#default-registrations.")] + public virtual void UnregisterCurrent(Type serviceType, string contract = null) => + throw new NotImplementedException("Because Autofac 5+ containers are immutable, UnregisterCurrent method is not available anymore. " + + "Instead, simply register your service after InitializeReactiveUI to override it https://autofaccn.readthedocs.io/en/latest/register/registration.html#default-registrations."); /// - /// Unregisters all the values associated with the specified type and contract. - /// https://stackoverflow.com/questions/5091101/is-it-possible-to-remove-an-existing-registration-from-autofac-container-builder. + /// Because Autofac 5+ containers are immutable, + /// UnregisterAll method is not available anymore. + /// Instead, simply register your service after InitializeReactiveUI to override it. /// /// The service type to unregister. /// The optional contract value, which will only remove the value associated with the contract. /// This is not implemented by default. /// - public virtual void UnregisterAll(Type serviceType, string contract = null) - { - lock (_lockObject) - { - // prevent multiple enumerations - var registrations = _componentContext.ComponentRegistry.Registrations.ToList(); - var registrationCount = registrations.Count; - if (registrationCount < 1) - { - return; - } - - if (!string.IsNullOrEmpty(contract)) - { - RemoveAndRebuild( - registrationCount, - registrations, - x => x.Services.All(s => - { - if (!(s is TypedService typedService)) - { - return false; - } - - return typedService.ServiceType != serviceType || !HasMatchingContract(s, contract); - })); - return; - } - - RemoveAndRebuild( - registrationCount, - registrations, - x => x.Services.All(s => - { - if (!(s is TypedService typedService)) - { - return false; - } - - return typedService.ServiceType != serviceType; - })); - } - } + [Obsolete("Because Autofac 5+ containers are immutable, UnregisterAll method is not available anymore. " + + "Instead, simply register your service after InitializeReactiveUI to override it https://autofaccn.readthedocs.io/en/latest/register/registration.html#default-registrations.")] + public virtual void UnregisterAll(Type serviceType, string contract = null) => + throw new NotImplementedException("Because Autofac 5+ containers are immutable, UnregisterAll method is not available anymore. " + + "Instead, simply register your service after InitializeReactiveUI to override it https://autofaccn.readthedocs.io/en/latest/register/registration.html#default-registrations."); /// - public virtual IDisposable ServiceRegistrationCallback(Type serviceType, string contract, Action callback) - { - // this method is not used by RxUI + public virtual IDisposable ServiceRegistrationCallback(Type serviceType, string contract, Action callback) => throw new NotImplementedException(); - } /// public void Dispose() @@ -260,119 +215,28 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - _componentContext.ComponentRegistry?.Dispose(); - } - } - } - - private static bool GetWhetherServiceRegistrationMatchesSearch( - IEnumerable componentRegistrationServices, - Type serviceType, - string contract) - { - foreach (var componentRegistrationService in componentRegistrationServices) - { - if (!(componentRegistrationService is IServiceWithType keyedService)) - { - continue; + _lifetimeScope.ComponentRegistry.Dispose(); + _internalContainer?.Dispose(); } - - if (keyedService.ServiceType != serviceType) - { - continue; - } - - // right type - if (string.IsNullOrEmpty(contract)) - { - if (!HasNoContract(componentRegistrationService)) - { - continue; - } - - // candidate for removal - return true; - } - - if (!HasMatchingContract(componentRegistrationService, contract)) - { - continue; - } - - // candidate for removal - return true; - } - - return false; - } - - private static bool HasMatchingContract(Service service, string contract) - { - if (!(service is KeyedService keyedService)) - { - return false; } - - if (!(keyedService.ServiceKey is string stringServiceKey)) - { - return false; - } - - return stringServiceKey.Equals(contract, StringComparison.Ordinal); - } - - private static bool HasNoContract(Service service) - { - return !(service is KeyedService); } private object Resolve(Type serviceType, string contract) { object serviceInstance; + var lifeTimeScope = _lifetimeScope ?? _internalLifetimeScope; + if (string.IsNullOrEmpty(contract)) { - _componentContext.TryResolve(serviceType, out serviceInstance); + lifeTimeScope.TryResolve(serviceType, out serviceInstance); } else { - _componentContext.TryResolveNamed(contract, serviceType, out serviceInstance); + lifeTimeScope.TryResolveNamed(contract, serviceType, out serviceInstance); } return serviceInstance; } - - private void RemoveAndRebuild( - int registrationCount, - IList registrations, - Func predicate) - { - var survivingComponents = registrations.Where(predicate).ToArray(); - - if (survivingComponents.Length == registrationCount) - { - // not removing anything - // drop out - return; - } - - RemoveAndRebuild(survivingComponents); - } - - private void RemoveAndRebuild(IEnumerable survivingComponents) - { - var builder = new ContainerBuilder(); - foreach (var c in survivingComponents) - { - builder.RegisterComponent(c); - } - - foreach (var source in _componentContext.ComponentRegistry.Sources) - { - builder.RegisterSource(source); - } - - _componentContext = builder.Build(); - } } } diff --git a/src/Splat.Autofac/README.md b/src/Splat.Autofac/README.md index 53c6fffc1..02fbebb04 100644 --- a/src/Splat.Autofac/README.md +++ b/src/Splat.Autofac/README.md @@ -7,17 +7,40 @@ Splat.Autofac is an adapter for `IMutableDependencyResolver`. It allows you to ### Register the Container ```cs -var container = new ContainerBuilder(); -container.RegisterType().As>(); -container.RegisterType().As>(); -container.RegisterType().AsSelf(); -container.RegisterType().AsSelf(); +var builder = new ContainerBuilder(); +builder.RegisterType().As>(); +builder.RegisterType().As>(); +builder.RegisterType().AsSelf(); +builder.RegisterType().AsSelf(); +// etc. ``` ### Register the Adapter to Splat ```cs -container.UseAutofacDependencyResolver(); +// Creates and sets the Autofac resolver as the Locator +var autofacResolver = builder.UseAutofacDependencyResolver(); + +// Register the resolver in Autofac so it can be later resolved +builder.RegisterInstance(autofacResolver); + +// Initialize ReactiveUI components +autofacResolver.InitializeReactiveUI(); + +// If you need to override any service (such as the ViewLocator), register it after InitializeReactiveUI +// https://autofaccn.readthedocs.io/en/latest/register/registration.html#default-registrations +// builder.RegisterType().As().SingleInstance(); +``` + +### Set Autofac Locator's lifetime after the ContainerBuilder has been built + +```cs +var autofacResolver = container.Resolve(); + +// Set a lifetime scope (either the root or any of the child ones) to Autofac resolver +// This is needed, because the previous steps did not Update the ContainerBuilder since they became immutable in Autofac 5+ +// https://github.com/autofac/Autofac/issues/811 +autofacResolver.SetLifetimeScope(container);` ``` ### Use the Locator diff --git a/src/Splat.Autofac/Splat.Autofac.csproj b/src/Splat.Autofac/Splat.Autofac.csproj index f68d836f8..f8064a5ff 100644 --- a/src/Splat.Autofac/Splat.Autofac.csproj +++ b/src/Splat.Autofac/Splat.Autofac.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/Splat.Autofac/SplatAutofacExtensions.cs b/src/Splat.Autofac/SplatAutofacExtensions.cs index ae1439c47..ef4ffa817 100644 --- a/src/Splat.Autofac/SplatAutofacExtensions.cs +++ b/src/Splat.Autofac/SplatAutofacExtensions.cs @@ -16,24 +16,14 @@ public static class SplatAutofacExtensions /// /// Initializes an instance of that overrides the default . /// - /// Autofac component context. + /// Autofac container builder. + /// The Autofac dependency resolver. [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "Dispose handled by locator.")] - public static void UseAutofacDependencyResolver(this IComponentContext componentContext) => - Locator.SetLocator(new AutofacDependencyResolver(componentContext)); - - /// - /// Initializes an instance of that overrides the default . - /// - /// Autofac container builder. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "Dispose handled by locator.")] - public static void UseAutofacDependencyResolver(this ContainerBuilder containerBuilder) + public static AutofacDependencyResolver UseAutofacDependencyResolver(this ContainerBuilder builder) { - if (containerBuilder is null) - { - throw new ArgumentNullException(nameof(containerBuilder)); - } - - Locator.SetLocator(new AutofacDependencyResolver(containerBuilder.Build())); + var autofacResolver = new AutofacDependencyResolver(builder); + Locator.SetLocator(autofacResolver); + return autofacResolver; } } } diff --git a/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs b/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs index 9398af959..14ba2a757 100644 --- a/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs +++ b/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs @@ -17,7 +17,7 @@ public abstract class BaseDependencyResolverTests /// Test to ensure Unregister doesn't cause an IndexOutOfRangeException. /// [Fact] - public void UnregisterCurrent_Doesnt_Throw_When_List_Empty() + public virtual void UnregisterCurrent_Doesnt_Throw_When_List_Empty() { var resolver = GetDependencyResolver(); var type = typeof(ILogManager); @@ -31,7 +31,7 @@ public void UnregisterCurrent_Doesnt_Throw_When_List_Empty() /// Test to ensure UnregisterCurrent removes last entry. /// [Fact] - public void UnregisterCurrent_Remove_Last() + public virtual void UnregisterCurrent_Remove_Last() { var resolver = GetDependencyResolver(); var type = typeof(ILogManager); @@ -52,7 +52,7 @@ public void UnregisterCurrent_Remove_Last() /// Test to ensure Unregister doesn't cause an IndexOutOfRangeException. /// [Fact] - public void UnregisterCurrentByName_Doesnt_Throw_When_List_Empty() + public virtual void UnregisterCurrentByName_Doesnt_Throw_When_List_Empty() { var resolver = GetDependencyResolver(); var type = typeof(ILogManager); @@ -81,7 +81,7 @@ public virtual void UnregisterAll_UnregisterCurrent_Doesnt_Throw_When_List_Empty /// Test to ensure Unregister doesn't cause an IndexOutOfRangeException. /// [Fact] - public void UnregisterAllByContract_UnregisterCurrent_Doesnt_Throw_When_List_Empty() + public virtual void UnregisterAllByContract_UnregisterCurrent_Doesnt_Throw_When_List_Empty() { var resolver = GetDependencyResolver(); var type = typeof(ILogManager); @@ -108,7 +108,7 @@ public void GetServices_Should_Never_Return_Null() /// Tests for ensuring hasregistration behaves when using contracts. /// [Fact] - public void HasRegistration() + public virtual void HasRegistration() { var type = typeof(string); const string contractOne = "ContractOne";