【问题标题】:Caliburn.Micro Bootstrapper 'BuildUp' method throws exception when Simple Injector is used使用 Simple Injector 时,Caliburn.Micro Bootstrapper 'BuildUp' 方法会引发异常
【发布时间】:2016-10-04 12:41:35
【问题描述】:

我对内置的 CM SimpleContainer 没有任何问题,但今天我需要去Simple Injector

当我通过cal:Message.Attach 调用异步方法时,Bootstrapper 的BuildUp 方法会引发异常:

'SimpleInjector.ActivationException' 类型的异常发生在 SimpleInjector.dll 但未在用户代码中处理

附加信息:SequentialResult 类型的构造函数 包含名称为“枚举器”和类型的参数 IEnumerator<IResult> 未注册。请确保 IEnumerator<IResult>已注册,或更改构造函数 顺序结果。

这是我的引导程序类:

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

        _container.Verify();
    }

    protected override object GetInstance(Type service, string key)
    {
        var instance = _container.GetInstance(service);

        if (instance != null)
            return instance;

        throw new InvalidOperationException("Could not locate any instances.");
    }

    protected override IEnumerable<object> GetAllInstances(Type service)
    {
        IServiceProvider provider = _container;
        Type collectionType = typeof(IEnumerable<>).MakeGenericType(service);
        var services = (IEnumerable<object>)provider.GetService(collectionType);
        return services ?? Enumerable.Empty<object>();
    }

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

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

XAML 的一部分:

    <Border Grid.Row="2" Padding="10" Background="#F0F0F0" BorderBrush="#DFDFDF" BorderThickness="0,1,0,0">
        <StackPanel Orientation="Horizontal">
            <Button IsCancel="True" Content="{Resx Key=Close}" />
            <Button IsDefault="True" MinWidth="{Resx Key=CheckOrUpdateBtnWidth, DefaultValue='115'}" Margin="8,0,0,0"
                    cal:Message.Attach="CheckUpdateAsync" />
        </StackPanel>
    </Border>

部分虚拟机:

    public async Task CheckUpdateAsync()
    {
        IsUpdateDownloading = true;

        try
        {
            await Task.Run(async () =>
            {
                Cts = new CancellationTokenSource();

                var http = new HttpClient();
                HttpResponseMessage rm = await http.GetAsync(UpdateInfo.DownloadUri, HttpCompletionOption.ResponseHeadersRead, Cts.Token);

                long size = rm.Content.Headers.ContentLength.GetValueOrDefault();

                var downloader = FileDownloader.Create(UpdateInfo.DownloadUri);

                byte[] data = downloader.Download(Cts.Token);
                downloader.ValidateHash(data, CloudManager.UpdateInfo.Sha256);
            });
        }
        catch (OperationCanceledException) { }
        catch (Exception ex)
        {
            Logger.Error(ex);
            throw;
        }
        finally
        {
            IsUpdateDownloading = false;
            ProgressValue = 0;
        }
    }

我做错了什么?

【问题讨论】:

  • 你能显示相关的xaml和调用'message attach'时应该调用的代码吗?
  • @Ric.Net 我已经更新了问题。
  • 我认为它击中了SequentialResult的CTOR,即public SequentialResult(IEnumerator&lt;IResult&gt; enumerator) { this.enumerator = enumerator; },当它看到IEnumerator&lt;IResult&gt;时它不知道如何解析接口。
  • 您能否详细说明创建 SequentialResult 的位置和原因?我在这里错过了更大的画面。问题很清楚,SquentialResult 没有注册。这就是为什么 .Verify() 无法在启动时向您显示您缺少 ctor 参数 IEnumerator 的注册

标签: c# wpf asynchronous caliburn.micro simple-injector


【解决方案1】:

在 C.M. 内部使用 Message.Attach()。使用CoRoutines。看着 C.M. 的source我看到了这段代码:

 public static Func<IEnumerator<IResult>, IResult> CreateParentEnumerator = 
     inner => new SequentialResult(inner);

即如果没有被覆盖,则使用默认的SequentialResult&lt;IResult&gt;

弗塞隆:

 var enumerator = CreateParentEnumerator(coroutine);
 IoC.BuildUp(enumerator);

这是异常的来源。 BuildUp 在内部调用,当您直接调用容器以查找注册时,Simple Injector 将抛出 ActivationException

在大多数情况下,您根本不需要实现 BuildUp 方法。当您使用 Simple Injector 作为您的 DI 容器时,我想不出您为什么要使用此方法的任何原因。我一般不会实现这个方法。

BuildUp 是您通常需要的一种方法,如果您需要将(使用属性注入)注入到无法使用普通 Simple Injector 管道创建的组件中。您可以阅读 Simple Injector 文档here 中的详细信息。

在这种情况下,我认为您不需要在这种情况下构建SequentialResult。您无需在此 C.M. 中注入任何内容。默认类。

所以这里的问题是您需要BuildUp 的任何课程吗?您的应用程序设计通常应该只使用在应用程序本身中定义的类,这些类您在 Simple Injector 中注册并且可以直接使用 GetInstance() 解析。

如果答案为“否”,则永远不要在外部类中注入依赖项,请完全删除 BuildUp() 方法。

但是,如果您需要 BuildUp() 其他类,则只有在覆盖默认 PropertyInjectionBehaviour 时才有意义。如果你不覆盖它,那么调用registration.InitializeInstance 根本没有意义,因为Simple Injector 不知道要注入什么,因为Simple Injector 仅支持开箱即用的Explicit Property Injection。您可以在覆盖默认 PropertyInjectionBehaviour 时创建某种隐式行为。

总而言之,我认为您应该完全删除 BuildUp 方法,因为当前的实现没有做任何事情。 InitializeInstance 不会注入任何东西。

【讨论】:

  • 是的,确实如此。我不需要 BuildUp 方法。感谢您对问题的详细描述。
【解决方案2】:
//this was an example from Simple Injector.
var repositoryAssembly = typeof(SqlUserRepository).Assembly;   

var registrations =
from type in repositoryAssembly.GetExportedTypes()
where type.Namespace == "MyComp.MyProd.BL.SqlRepositories"
where type.GetInterfaces().Any()
select new { Service = type.GetInterfaces().Single(), Implementation = type };

foreach (var reg in registrations) {
    container.Register(reg.Service, reg.Implementation, Lifestyle.Transient);
}

虽然我知道带有 SelectedAssemblies 覆盖的 CM “假设”是所有与 Assembly 相关的东西的包罗万象,但我推测 GetAllInstances 中的几行并没有获得 CM 所需的一切。我认为您需要扩展以包括type.GetIntefaces().Any()。我希望这足以满足 SequentialResult 的 CTOR 需求。

我从未使用过 Simple Injector,但我说它的工作原理非常相似,并且可能对开放泛型有更好的处理能力。我认为您应该在配置中进行更多注册的地方缺少一些东西。到目前为止,我假设在“抛出”注入器问题的 XAML 部分之前没有其他任何东西死亡或失败。这似乎不是 CM 问题,而是简单的注入器配置。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多