Closed tapika closed 2 years ago
The NO container in the performance test is not a dependency injection container. It is just used for a base line. You can use other dependency injection containers with Caliburn.Micro. Here is a sample that uses Microsoft Dependency Injection.
https://github.com/vb2ae/CaliburnMicroMicosoftDI
Here is a link to an example that uses Castle Windsor.
https://gist.github.com/tarasn/55079e824b64e4e0e072
I was thinking of making examples that uses DryLoc and UnityContainer. Any suggested container you would like to see?
I will work on creating some templates that use other di containers.
is not a dependency injection container. It is just used for a base line
I've understood that container no satisfies same requirements as rest of containers - meaning you can register and resolve required interfaces. Container "no" might not have everything that container supports, but it has basic support as majority of containers. Maybe I missed something ?
Any suggested container you would like to see?
What is the purpose ? I think it maybe makes sense to cross bind Caliburn.Micro to UnityContainer for people who use unity, but eventually it's also slow - maybe just replacing all containers with "no" container - then performance would be best.
@vb2ae Thanks for creating the sample which integrates Microsoft.Extensions.DependencyInjection. I have a question regarding using a similar approach with a WPF project. In my WPF project I have created a boostrapper to do the wire up. I'm struggling with getting INavigationService wired up as there does not appear to be a hook to get to the Frame during initialization of my application. I've searched through the issues in this repository and on StackOverflow but have not found an answer.
I have found older samples of doing the wire up of INavigationService with SimpleContainer where a method is called in the ShellViewModel from the ShellView like this:
<Frame cm:Message.Attach="RegisterFrame($source)" Grid.Row="1" NavigationUIVisibility="Hidden" />
public void RegisterFrame(Frame frame)
{
_navigationService = new FrameAdapter(frame);
_container.Instance(_navigationService);
_navigationService.NavigateToViewModel(typeof(LandingViewModel));
}
Unfortunately, this approach will not work with Microsoft.Extensions.DependencyInjection as the ServiceProvider will have already been created before RegsiterFrame
has been called and MS DI does not support adding new registrations to the ServiceCollection after ServiceProvider has been created.
I would appreciate any advice on how to register an instance of INavigationService for my WPF app with in my Boostrapper class.
Thanks in adavance!
@gerfen What framework are you using for your wpf app?
@vb2ae Not sure exactly what you're asking? UI framework?
Are you using .net 5, .net 6, .net core 3.1, .net framework 4.8? etc
Oh, .net 6.
@vb2ae I found a path forward. There may be a better way but this is what I came up with...
Instead of declaring the Frame in my ShellView, I'm programmatically creating it and adding to the Grid control defined in ShellView. This allows me to create the Frame and a FrameAdapter then register the FrameAdapter as an instance of INavigationService in Bootstrapper.Configure() like so (note - I'm still using SimpleContainer here):
protected override void Configure()
{
_container = new SimpleContainer();
//... code elided
_frameSet = new FrameSet();
_container.RegisterInstance(typeof(INavigationService), null, _frameSet.NavigationService);
}
where FrameSet looks like this:
public class FrameSet
{
public FrameSet()
{
Frame = new Frame
{
NavigationUIVisibility = NavigationUIVisibility.Hidden
};
FrameAdapter = new FrameAdapter(Frame);
}
public Frame Frame { get; private set; }
public FrameAdapter FrameAdapter { get; private set; }
public INavigationService NavigationService => FrameAdapter as INavigationService;
}
Then in Bootstraper.OnStartup, I add the Frame to the Grid control:
protected override async void OnStartup(object sender, StartupEventArgs e)
{
await DisplayRootViewForAsync<ShellViewModel>();
AddFrameToMainWindow(_frameSet.Frame);
_frameSet.NavigationService.NavigateToViewModel(typeof(LandingViewModel));
}
private void AddFrameToMainWindow(Frame frame)
{
var mainWindow = Application.MainWindow;
if (mainWindow == null)
{
throw new NullReferenceException("'Application.MainWindow' is null.");
}
if (mainWindow.Content is not Grid grid)
{
throw new NullReferenceException("The grid on 'Application.MainWindow' is null.");
}
Grid.SetRow(frame, 1);
Grid.SetColumn(frame, 0);
grid.Children.Add(frame);
}
If you have a better approach, I'm open to suggestions.
Thanks!
In following article:
https://www.palmmedia.de/Blog/2011/8/30/ioc-container-benchmark-performance-comparison
There was multiple containers tested, and results were collected - including
Caliburn.Micro
.At the moment
Caliburn.Micro
is not fastest container - if you check tests on github (https://github.com/danielpalme/IocPerformance) - you will find out that container named "No" is the fastest.No container is based on
IocPerformanceDictionary
, which apparently has superior performance compared to other alternatives.Since
Caliburn.Micro
is not purely container itself, it's tightly bound to UI - I was thinking - why not to combine all good parts into one.So in theory
Caliburn.Micro
could reuseIocPerformanceDictionary
and improve benchmark performance. (To have both - UI functionality and container performance)