Caliburn.Micro Bootstrapper' BuildUp'使用Simple Injector时抛出异常

时间:2016-06-04 14:41:19

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

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

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

  

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

     

其他信息:SequentialResult类型的构造函数   包含名称&#39;枚举器&#39;的参数。并输入   未注册的IEnumerator<IResult>。请确保   IEnumerator<IResult>已注册,或更改了构造函数   SequentialResult。

这是我的引导课程:

    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>

VM的一部分:

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

我做错了什么?

2 个答案:

答案 0 :(得分:1)

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

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

即。如果没有覆盖,则使用默认的SequentialResult<IResult>

Furtheron:

 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()直接解析。

如果答案是&#39; no&#39;,则永远不会在外部类中注入依赖项,完全删除BuildUp()方法。

如果你需要BuildUp()其他类,只有覆盖默认的PropertyInjectionBehaviour才有意义。如果你不重写这个,打电话给registration.InitializeInstance根本没有意义,因为Simple Injector不知道要注入什么,因为Simple Injector只支持{{3 }} 盒子外面。覆盖默认的PropertyInjectionBehaviour时,您可以创建某种隐式行为。

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

答案 1 :(得分:0)

//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是&#34;假设&#34;为了解决与程序集相关的所有事情,我推测GetAllInstances中的几行并没有获得CM所需的所有内容。我认为您需要扩展以包含type.GetIntefaces().Any()。我希望能够满足SequentialResult的CTOR需求。

我还没有使用过Simple Injector,但是我说它的工作方式非常相似,并且对于开放式泛型可能会有更好的处理。我认为你应该在Configure中进行更少的注册。我假设没有其他任何事情在XAML的那部分之前死亡或失败,并且#34;抛出&#34;注射器问题..这似乎不是CM问题,而是简单的注射器配置。