Simple Injector throws an error in Caliburn.Micro Bootstrapper.Buildup when calling async method in the viewmodel

1

I am trying to use Simple Injector as the DI container for Caliburn.Micro. Demo source: https://github.com/nvstrien/WPFDemos

This project has a basic Caliburn.Micro setup with a Simple Injector Container. The ShellView has 1 button and when pressed, an async method is called to get some simulated data.

I am getting this error in Bootstrapper.Buildup.

SimpleInjector.ActivationException: 'No registration for type SequentialResult could be found. Make sure SequentialResult is registered, for instance by calling 'Container.Register<SequentialResult>();' during the registration phase. An implicit registration could not be made because Container.Options.ResolveUnregisteredConcreteTypes is set to 'false', which is now the default setting in v5. This disallows the container to construct this unregistered concrete type. For more information on why resolving unregistered concrete types is now disallowed by default, and what possible fixes you can apply, see https://simpleinjector.org/ructd. '

It has been suggested here that commenting out Bootstrapper.BuildUp should work: Caliburn.Micro Bootstrapper 'BuildUp' method throws exception when Simple Injector is used

However, when doing so, SimpleInjector will still throw an exception.

Any help solving this would be greatly appreciated

My complete Bootstrapper config file looks like this:

public static readonly Container _container = new();

public Bootstrapper()
{
    Initialize();
}

protected override void Configure()
{
    _container.Register<IWindowManager, WindowManager>();
    _container.RegisterSingleton<IEventAggregator, EventAggregator>();

    GetType().Assembly.GetTypes()
        .Where(type => type.IsClass)
        .Where(type => type.Name.EndsWith("ViewModel"))
        .ToList()
        .ForEach(viewModelType => _container.RegisterSingleton(viewModelType, viewModelType));

    _container.Verify();
}

protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
{
    DisplayRootViewFor<ShellViewModel>();
}

protected override IEnumerable<object> GetAllInstances(Type service)
{
    // as discussed here: https://stackoverflow.com/questions/32258863/simple-injector-getallinstances-throwing-exception-with-caliburn-micro

    //_container.GetAllInstances(service);

    IServiceProvider provider = _container;

    Type collectionType = typeof(IEnumerable<>).MakeGenericType(service);

    IEnumerable<object> services = (IEnumerable<object>)provider.GetService(collectionType);

    return services ?? Enumerable.Empty<object>();
}

protected override object GetInstance(System.Type service, string key)
{
    return _container.GetInstance(service);
}

protected override IEnumerable<Assembly> SelectAssemblies()
{
    return new[] { Assembly.GetExecutingAssembly() };
}

// see: https://stackoverflow.com/questions/37631468/caliburn-micro-bootstrapper-buildup-method-throws-exception-when-simple-inject
// commenting out BuildUp still throws an exception in SimpleInjector.dll 
protected override void BuildUp(object instance)
{
    InstanceProducer registration = _container.GetRegistration(instance.GetType(), true);
    registration.Registration.InitializeInstance(instance);
}

In the ShellViewModel I have 1 method that runs when pressing a button on the ShellView.

public async Task Button1()
{
    Debug.Print("Hello world");

    var data = await GetSampleDataAsync();

    foreach (var item in data)
    {
        Debug.Print(item);
    }
}

public async Task<IEnumerable<string>> GetSampleDataAsync()
{
    // method simulating getting async data
    var data = new List<string>() { "hello", "world" };

    return await Task.FromResult(data);
}

The error occurs when 'await GetSampleDataAsync()' gets called.

When adding the SequentialResult in Bootstrapper.Configure as follows.

protected override void Configure()
{
    _container.Register<IWindowManager, WindowManager>();
    _container.RegisterSingleton<IEventAggregator, EventAggregator>();
    _container.Register<SequentialResult>();

    GetType().Assembly.GetTypes()
        .Where(type => type.IsClass)
        .Where(type => type.Name.EndsWith("ViewModel"))
        .ToList()
        .ForEach(viewModelType => _container.RegisterSingleton(viewModelType, viewModelType));

    _container.Verify();
}

I get the next error:

System.InvalidOperationException
HResult=0x80131509 Message=The configuration is invalid. Creating the instance for type SequentialResult failed. The constructor of type SequentialResult contains the parameter with name 'enumerator' and type IEnumerator<IResult>, but IEnumerator<IResult> is not registered. For IEnumerator<IResult> to be resolved, it must be registered in the container. Source=SimpleInjector StackTrace: at SimpleInjector.InstanceProducer.VerifyExpressionBuilding() at SimpleInjector.Container.VerifyThatAllExpressionsCanBeBuilt(InstanceProducer[] producersToVerify) at SimpleInjector.Container.VerifyThatAllExpressionsCanBeBuilt() at SimpleInjector.Container.VerifyInternal(Boolean suppressLifestyleMismatchVerification) at SimpleInjector.Container.Verify(VerificationOption option) at SimpleInjector.Container.Verify() at CaliburnMicroWithSimpleInjectorDemo.Bootstrapper.Configure() in C:\Users\Niels\source\repos\WPFDemos\CaliburnMicroWithSimpleInjectorDemo\Bootstrapper.cs:line 37 at Caliburn.Micro.BootstrapperBase.StartRuntime() at Caliburn.Micro.BootstrapperBase.Initialize() at CaliburnMicroWithSimpleInjectorDemo.Bootstrapper..ctor() in C:\Users\Niels\source\repos\WPFDemos\CaliburnMicroWithSimpleInjectorDemo\Bootstrapper.cs:line 22

This exception was originally thrown at this call stack: [External Code]

Inner Exception 1: ActivationException: The constructor of type SequentialResult contains the parameter with name 'enumerator' and type IEnumerator<IResult>, but IEnumerator<IResult> is not registered. For IEnumerator<IResult> to be resolved, it must be registered in the container.

When I change the methods in my ShellViewModel to be synchronous like this, I don't get any exceptions:

public void Button1()
{
    Debug.Print("Hello world");

    var data = GetSampleData();

    foreach (var item in data)
    {
        Debug.Print(item);
    }
}

public IEnumerable<string> GetSampleData()
{
    var data = new List<string>() { "hello", "world" };
    return data;
}

It seems to me that the container doesn't get configured properly to work with some implementation in Caliburn.Micro, but the Bootstrapper configuration follows the recommended path. I am unfortunately not able to follow the explanation here: Caliburn.Micro Bootstrapper 'BuildUp' method throws exception when Simple Injector is used Also, what was marked as solution doesn't seem to work in my code sample.

dependency-injection
caliburn.micro
.net-5
simple-injector
asked on Stack Overflow May 14, 2021 by NM van Strien • edited May 14, 2021 by Steven

1 Answer

0

@Steven: Commenting out BuildUp indeed fixed my problem.

I thought that I had tested commenting out BuildUp in my sample project before coming to SO to ask my question, but trying it again now solved my problem. Thank you for putting me back on the right track!

Solution: comment out / delete BootStrapper.BuildUp as was also suggested here: Caliburn.Micro Bootstrapper 'BuildUp' method throws exception when Simple Injector is used

//protected override void BuildUp(object instance)
//{
//    InstanceProducer registration = _container.GetRegistration(instance.GetType(), true);
//    registration.Registration.InitializeInstance(instance);
//}
answered on Stack Overflow May 14, 2021 by NM van Strien

User contributions licensed under CC BY-SA 3.0