Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove factory with lazy initialization of current container #2920

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 37 additions & 11 deletions src/Forms/Prism.Forms/PrismApplicationBase.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Prism.AppModel;
using Prism.Behaviors;
Expand All @@ -22,6 +23,8 @@ namespace Prism
/// </summary>
public abstract class PrismApplicationBase : Application
{
private static bool _initialized;

/// <summary>
/// Gets the Current PrismApplication
/// </summary>
Expand Down Expand Up @@ -140,20 +143,31 @@ private INavigationService CreateNavigationService(object view)
/// </summary>
protected virtual void Initialize()
{
ContainerLocator.SetContainerExtension(CreateContainerExtension);
_containerExtension = ContainerLocator.Current;
RegisterRequiredTypes(_containerExtension);
PlatformInitializer?.RegisterTypes(_containerExtension);
RegisterTypes(_containerExtension);
_containerExtension.FinalizeExtension();
if(!_initialized)
{
ContainerLocator.TrySetContainerExtension(CreateContainerExtension());
_containerExtension = ContainerLocator.Current;
RegisterRequiredTypes(_containerExtension);
PlatformInitializer?.RegisterTypes(_containerExtension);
RegisterTypes(_containerExtension);
_containerExtension.FinalizeExtension();

_moduleCatalog = Container.Resolve<IModuleCatalog>();
ConfigureModuleCatalog(_moduleCatalog);

_moduleCatalog = Container.Resolve<IModuleCatalog>();
ConfigureModuleCatalog(_moduleCatalog);
_containerExtension.CreateScope();
NavigationService = _containerExtension.Resolve<INavigationService>();

_containerExtension.CreateScope();
NavigationService = _containerExtension.Resolve<INavigationService>();
InitializeModules();
}
else
{
_containerExtension = ContainerLocator.Current;
_containerExtension.CreateScope();
NavigationService = _containerExtension.Resolve<INavigationService>();
}

InitializeModules();
_initialized = true;
}

/// <summary>
Expand Down Expand Up @@ -259,5 +273,17 @@ private void PrismApplicationBase_ModalPopped(object sender, ModalPoppedEventArg
_previousPage = null;
}
}

/// <summary>
/// This method is for Unit Testing Purposes only. By default we do not reinitialize the container if the static
/// Initialization flag is already set to true. This could be the case on Android where the MainActivity is recreated
/// and the Application.Current was nulled out requiring a new instance of the Application to be created. This will preserve
/// the Registrations and Singletons that are already initialized in the initial container.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static void ResetInitialization()
{
_initialized = false;
}
}
}
2 changes: 1 addition & 1 deletion src/Maui/Prism.Maui/PrismAppBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ internal PrismAppBuilder(IContainerExtension containerExtension, MauiAppBuilder
});

ContainerLocator.ResetContainer();
ContainerLocator.SetContainerExtension(() => containerExtension);
ContainerLocator.SetContainerExtension(containerExtension);

containerExtension.RegisterInstance(this);
containerExtension.RegisterSingleton<IMauiInitializeService, PrismInitializationService>();
Expand Down
43 changes: 30 additions & 13 deletions src/Prism.Core/Ioc/ContainerLocator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
#nullable enable
using System;
using System.ComponentModel;

namespace Prism.Ioc
Expand All @@ -9,16 +10,14 @@
[EditorBrowsable(EditorBrowsableState.Never)]
public static class ContainerLocator
{
private static Lazy<IContainerExtension> _lazyContainer;

private static IContainerExtension _current;
private static IContainerExtension? _current;

/// <summary>
/// Gets the current <see cref="IContainerExtension" />.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static IContainerExtension Current =>
_current ?? (_current = _lazyContainer?.Value);
_current ?? throw new InvalidOperationException("The `ContainerLocator.SetContainerExtension` method has not been invoked");

/// <summary>
/// Gets the <see cref="IContainerProvider" />
Expand All @@ -27,15 +26,34 @@
Current;

/// <summary>
/// Sets the Container Factory to use if the Current <see cref="IContainerProvider" /> is null
/// Sets the Container to use if the <see cref="IContainerProvider" /> is null. Otherwise this will throw an exception.
/// </summary>
/// <param name="factory"></param>
/// <param name="instance">The current instance to set</param>
/// <remarks>
/// NOTE: We want to use Lazy Initialization in case the container is first created
/// prior to Prism initializing which could be the case with Shiny
/// </remarks>
public static void SetContainerExtension(Func<IContainerExtension> factory) =>
_lazyContainer = new Lazy<IContainerExtension>(factory);
/// <exception cref="InvalidOperationException">Throws an exception if the Container has already been set.</exception>
public static void SetContainerExtension(IContainerExtension instance)

Check warning on line 34 in src/Prism.Core/Ioc/ContainerLocator.cs

View workflow job for this annotation

GitHub Actions / build-prism-maui / Build Prism.Maui

XML comment has badly formed XML -- 'Expected an end tag for element 'remarks'.'

Check warning on line 34 in src/Prism.Core/Ioc/ContainerLocator.cs

View workflow job for this annotation

GitHub Actions / build-prism-wpf / Build Prism.Wpf

XML comment has badly formed XML -- 'Expected an end tag for element 'remarks'.'

Check warning on line 34 in src/Prism.Core/Ioc/ContainerLocator.cs

View workflow job for this annotation

GitHub Actions / build-prism-core / Build Prism.Core

XML comment has badly formed XML -- 'Expected an end tag for element 'remarks'.'

Check warning on line 34 in src/Prism.Core/Ioc/ContainerLocator.cs

View workflow job for this annotation

GitHub Actions / build-prism-uno / Build Prism.Uno

XML comment has badly formed XML -- 'Expected an end tag for element 'remarks'.'
{
if (_current is not null)
{
throw new InvalidOperationException("The Container has already been initialized with the ContainerLocator. Please use TrySetContainerExtension or Reset the ContainerLocator prior to invoking the SetContainerExtensionMethod.");
}
_current = instance;
}

/// <summary>
/// Returns <c>True</c> and sets the Container if the <see cref="IContainerProvider"/> is null. Otherwise
/// will return <c>False</c>
/// </summary>
/// <param name="instance">The instance of the <see cref="IContainerExtension"/> to set.</param>
/// <returns><c>True</c> if the Container was set.</returns>
public static bool TrySetContainerExtension(IContainerExtension instance)
{
if (_current is not null)
return false;

_current = instance;
return true;
}

/// <summary>
/// Used for Testing to Reset the Current Container
Expand All @@ -44,7 +62,6 @@
public static void ResetContainer()
{
_current = null;
_lazyContainer = null;
}
}
}
2 changes: 1 addition & 1 deletion src/Uno/Prism.Uno/PrismApplicationBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ protected virtual void ConfigureServices(IServiceCollection services) { }
/// </summary>
protected virtual void Initialize(IApplicationBuilder builder)
{
ContainerLocator.SetContainerExtension(CreateContainerExtension);
ContainerLocator.SetContainerExtension(CreateContainerExtension());
_containerExtension = ContainerLocator.Current;
ConfigureApp(builder);
builder.Configure(ConfigureHost)
Expand Down
2 changes: 1 addition & 1 deletion src/Wpf/Prism.Wpf/PrismApplicationBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ protected virtual void ConfigureViewModelLocator()
/// </summary>
protected virtual void Initialize()
{
ContainerLocator.SetContainerExtension(CreateContainerExtension);
ContainerLocator.SetContainerExtension(CreateContainerExtension());
_containerExtension = ContainerLocator.Current;
_moduleCatalog = CreateModuleCatalog();
RegisterRequiredTypes(_containerExtension);
Expand Down
2 changes: 1 addition & 1 deletion src/Wpf/Prism.Wpf/PrismBootstrapperBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ protected virtual void ConfigureViewModelLocator()
/// </summary>
protected virtual void Initialize()
{
ContainerLocator.SetContainerExtension(CreateContainerExtension);
ContainerLocator.SetContainerExtension(CreateContainerExtension());
_containerExtension = ContainerLocator.Current;
_moduleCatalog = CreateModuleCatalog();
RegisterRequiredTypes(_containerExtension);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public void GetErrorsDoesNotThrowException()
{
ContainerLocator.ResetContainer();
var container = Setup.CreateContainer();
ContainerLocator.SetContainerExtension(() => Setup.Extension);
Assert.False(ContainerLocator.TrySetContainerExtension(Setup.Extension));
Setup.Registry.Register<object, BadView>("BadView");

var ex = Record.Exception(() => container.Resolve<object>("BadView"));
Expand All @@ -60,7 +60,7 @@ public void GetErrorsLocatesIssueWithBadView()
{
ContainerLocator.ResetContainer();
var container = Setup.CreateContainer();
ContainerLocator.SetContainerExtension(() => Setup.Extension);
Assert.False(ContainerLocator.TrySetContainerExtension(Setup.Extension));
Setup.Registry.Register<object, BadView>("BadView");

var ex = Record.Exception(() => container.Resolve<object>("BadView"));
Expand All @@ -77,7 +77,7 @@ public void GetErrorsLocatesTargetInvocationException()
{
ContainerLocator.ResetContainer();
var container = Setup.CreateContainer();
ContainerLocator.SetContainerExtension(() => Setup.Extension);
Assert.False(ContainerLocator.TrySetContainerExtension(Setup.Extension));
Setup.Registry.Register<object, BadView>("BadView");

var ex = Record.Exception(() => container.Resolve<object>("BadView"));
Expand All @@ -94,7 +94,7 @@ public void GetErrorsLocatesXamlParseException()
{
ContainerLocator.ResetContainer();
var container = Setup.CreateContainer();
ContainerLocator.SetContainerExtension(() => Setup.Extension);
Assert.False(ContainerLocator.TrySetContainerExtension(Setup.Extension));
Setup.Registry.Register<object, BadView>("BadView");

var ex = Record.Exception(() => container.Resolve<object>("BadView"));
Expand All @@ -111,7 +111,7 @@ public void LocatesUnregisteredServiceType()
{
ContainerLocator.ResetContainer();
var container = Setup.CreateContainer();
ContainerLocator.SetContainerExtension(() => Setup.Extension);
Assert.False(ContainerLocator.TrySetContainerExtension(Setup.Extension));

var ex = Record.Exception(() => container.Resolve<ConstructorArgumentViewModel>());

Expand All @@ -127,7 +127,7 @@ public void LocatesUnregisteredServiceWithMissingRegistration()
{
ContainerLocator.ResetContainer();
var container = Setup.CreateContainer();
ContainerLocator.SetContainerExtension(() => Setup.Extension);
Assert.False(ContainerLocator.TrySetContainerExtension(Setup.Extension));

var ex = Record.Exception(() => container.Resolve<ConstructorArgumentViewModel>());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public ContainerSetup()
public IContainerProvider CreateContainer()
{
ContainerLocator.ResetContainer();
ContainerLocator.SetContainerExtension(() => CreateContainerInternal());
ContainerLocator.SetContainerExtension(CreateContainerInternal());
var container = ContainerLocator.Current;
container.CreateScope();
return container;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ public void NavigateDelegatesToIRegionNavigationService()
var containerMock = new Mock<IContainerExtension>();
containerMock.Setup(x => x.Resolve(typeof(IRegionNavigationService))).Returns(mockRegionNavigationService.Object);
ContainerLocator.ResetContainer();
ContainerLocator.SetContainerExtension(() => containerMock.Object);
ContainerLocator.SetContainerExtension(containerMock.Object);

// Act
region.NavigationService.RequestNavigate(uri, navigationCallback, navigationParameters);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ public void CanRegisterViewType()
};
var containerMock = new Mock<IContainerExtension>();
containerMock.Setup(c => c.Resolve(typeof(IRegionViewRegistry))).Returns(mockRegionContentRegistry);
ContainerLocator.SetContainerExtension(() => containerMock.Object);
ContainerLocator.SetContainerExtension(containerMock.Object);

var regionManager = new RegionManager();

Expand Down Expand Up @@ -387,7 +387,7 @@ public void CanRegisterViewTypeGeneric()
var containerMock = new Mock<IContainerExtension>();
containerMock.Setup(c => c.Resolve(typeof(IRegionViewRegistry))).Returns(mockRegionContentRegistry);
ContainerLocator.ResetContainer();
ContainerLocator.SetContainerExtension(() => containerMock.Object);
ContainerLocator.SetContainerExtension(containerMock.Object);

var regionManager = new RegionManager();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public INavigationServiceExtensionsFixture()
ContainerLocator.ResetContainer();
var container = new Mock<IContainerExtension>();
container.Setup(x => x.CreateScope()).Returns(Mock.Of<IScopedProvider>());
ContainerLocator.SetContainerExtension(() => container.Object);
ContainerLocator.SetContainerExtension(container.Object);
PageNavigationRegistry.ClearRegistrationCache();

PageNavigationRegistry.Register("NavigationPage", typeof(NavigationPage));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public PageNavigationServiceFixture()

ContainerLocator.ResetContainer();
_container = new PageNavigationContainerMock();
ContainerLocator.SetContainerExtension(() => _container);
ContainerLocator.SetContainerExtension(_container);

_container.Register("PageMock", typeof(PageMock));

Expand Down
37 changes: 28 additions & 9 deletions tests/Prism.Core.Tests/Ioc/ContainerLocatorFixture.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Moq;
using System;
using Moq;
using Prism.Ioc;
using Xunit;

Expand All @@ -18,33 +19,51 @@ public class ContainerLocatorFixture
public void FactoryCreatesContainerExtension()
{
Prism.Ioc.ContainerLocator.ResetContainer();
Assert.Null(Prism.Ioc.ContainerLocator.Current);
Prism.Ioc.ContainerLocator.SetContainerExtension(() => new Mock<IContainerExtension>().Object);
Assert.Throws<InvalidOperationException>(() => Prism.Ioc.ContainerLocator.Current);
Prism.Ioc.ContainerLocator.SetContainerExtension(new Mock<IContainerExtension>().Object);
Assert.NotNull(Prism.Ioc.ContainerLocator.Current);
}

[Fact]
public void ResetNullsCurrentContainer()
{
Prism.Ioc.ContainerLocator.ResetContainer();
Assert.Null(Prism.Ioc.ContainerLocator.Current);
Prism.Ioc.ContainerLocator.SetContainerExtension(() => new Mock<IContainerExtension>().Object);
Assert.Throws<InvalidOperationException>(() => Prism.Ioc.ContainerLocator.Current);
Prism.Ioc.ContainerLocator.SetContainerExtension(new Mock<IContainerExtension>().Object);
Assert.NotNull(Prism.Ioc.ContainerLocator.Current);
Prism.Ioc.ContainerLocator.ResetContainer();
Assert.Null(Prism.Ioc.ContainerLocator.Current);
Assert.Throws<InvalidOperationException>(() => Prism.Ioc.ContainerLocator.Current);
}

[Fact]
public void FactoryOnlySetsContainerOnce()
public void SetThrowExceptionWhenAlreadyInitialized()
{
Prism.Ioc.ContainerLocator.ResetContainer();
var container = new Mock<IContainerExtension>().Object;
var container2 = new Mock<IContainerExtension>().Object;

Prism.Ioc.ContainerLocator.SetContainerExtension(() => container);
Prism.Ioc.ContainerLocator.SetContainerExtension(container);
Assert.Same(container, Prism.Ioc.ContainerLocator.Container);

Prism.Ioc.ContainerLocator.SetContainerExtension(() => container2);
var ex = Record.Exception(() => Prism.Ioc.ContainerLocator.SetContainerExtension(container2));
Assert.NotNull(ex);
Assert.IsType<InvalidOperationException>(ex);
Assert.Same(container, Prism.Ioc.ContainerLocator.Container);
}

[Fact]
public void TrySetReturnsFalseWhenSetting2ndContainer()
{
Prism.Ioc.ContainerLocator.ResetContainer();
var container = new Mock<IContainerExtension>().Object;
var container2 = new Mock<IContainerExtension>().Object;

var result = Prism.Ioc.ContainerLocator.TrySetContainerExtension(container);
Assert.Same(container, Prism.Ioc.ContainerLocator.Container);
Assert.True(result);

result = Prism.Ioc.ContainerLocator.TrySetContainerExtension(container2);
Assert.False(result);
Assert.NotSame(container2, Prism.Ioc.ContainerLocator.Container);
Assert.Same(container, Prism.Ioc.ContainerLocator.Container);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using Moq;
using Prism.Container.Wpf.Mocks;
using Prism.Events;
Expand Down Expand Up @@ -154,7 +155,7 @@ public void RunShouldCallRegisterTypes()
public void SetsContainerLocatorCurrentContainer()
{
ContainerLocator.ResetContainer();
Assert.Null(ContainerLocator.Container);
Assert.Throws<InvalidOperationException>(() => ContainerLocator.Container);
var bootstrapper = new MockBootstrapper();

bootstrapper.Run();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ static ContainerProviderExtensionFixture()
public ContainerProviderExtensionFixture()
{
ContainerLocator.ResetContainer();
ContainerLocator.SetContainerExtension(() => _containerExtension);
ContainerLocator.SetContainerExtension(_containerExtension);
}

public void Dispose()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public RegionNavigationContentLoaderFixture()
_container.Register(typeof(IRegionNavigationContentLoader), typeof(RegionNavigationContentLoader));
_container.Register<IRegionNavigationJournal, RegionNavigationJournal>();
ContainerLocator.ResetContainer();
ContainerLocator.SetContainerExtension(() => _container);
ContainerLocator.SetContainerExtension(_container);
}

[StaFact]
Expand Down
Loading
Loading