在视图模型中调用异步方法时,简单注入器在 Caliburn.Micro Bootstrapper.Buildup 中抛出错误

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

我正在尝试使用 Simple Injector 作为 Caliburn.Micro 的 DI 容器。演示源:https://github.com/nvstrien/WPFDemos

这个项目有一个基本的 Caliburn.Micro 设置,带有一个简单的注入器容器。 ShellView 有 1 个按钮,当按下时,会调用一个异步方法来获取一些模拟数据。

我在 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. '

这里有人建议注释掉 Bootstrapper.BuildUp 应该有效:

但是,这样做时,SimpleInjector 仍然会抛出异常。

任何解决此问题的帮助将不胜感激

我完整的 Bootstrapper 配置文件如下所示:

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: 

    //_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: 
// 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);
}

在 ShellViewModel 中,我有 1 个方法在按下 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);
}

调用'await GetSampleDataAsync()'时出现错误。

在Bootstrapper.Configure中添加SequentialResult时如下。

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();
}

我收到下一个错误:

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.

当我将 ShellViewModel 中的方法更改为像这样同步时,我没有遇到任何异常:

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;
}

在我看来,容器没有正确配置以与 Caliburn.Micro 中的某些实现一起工作,但 Bootstrapper 配置遵循推荐的路径。不幸的是,我无法理解这里的解释: 此外,标记为解决方案的内容在我的代码示例中似乎不起作用。

@Steven:注释掉 BuildUp 确实解决了我的问题。

我以为在来 SO 提问之前,我已经测试过在我的示例项目中注释掉 BuildUp,但现在再次尝试解决了我的问题。谢谢你让我回到正轨!

解决方案:注释掉/删除 BootStrapper.BuildUp,正如这里也建议的那样:

//protected override void BuildUp(object instance)
//{
//    InstanceProducer registration = _container.GetRegistration(instance.GetType(), true);
//    registration.Registration.InitializeInstance(instance);
//}