ReactiveUI中IMutableDependencyResolver和Structuremap的问题[英] Issues with IMutableDependencyResolver and Structuremap in ReactiveUI

本文是小编为大家收集整理的关于ReactiveUI中IMutableDependencyResolver和Structuremap的问题的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

本文来自:IT宝库(https://www.itbaoku.cn)

首先,让我说我认为这不是反应式本身的问题,这就是为什么我没有在其github repo上创建一个问题,其次,我意识到我正在使用beta版本的reactiveui.

我想使用structureMap,因为我将在WPF应用中使用插件方案,而Splat中的DI容器并未用于此类内容.

观察这些单元测试:

[Fact]
public void ShouldBeAbleToOverrideDefaultDependencyResolver()
{
    Locator.Current = new ApplicationDependencyResolver(StructureMapBootstrapper.Instance.Container);
    Locator.CurrentMutable.InitializeSplat();
    Locator.CurrentMutable.InitializeReactiveUI();

    var view = Locator.Current.GetService<SplashScreenView>();

    view.Should().NotBeNull().And.BeOfType<SplashScreenView>();
}

[Fact]
public void ShouldBeAbleToLocateTheViewForAViewModel()
{
    Locator.Current = new ApplicationDependencyResolver(StructureMapBootstrapper.Instance.Container);
    Locator.CurrentMutable.InitializeSplat();
    Locator.CurrentMutable.InitializeReactiveUI();
    var viewLocator = Locator.Current.GetService<IViewLocator>();

    var view = viewLocator.ResolveView(typeof (SplashScreenViewModel));

    view.Should().NotBeNull().And.BeOfType<SplashScreenView>();
}

第一个测试通过.第二个测试没有,并提供此堆栈:

StructureMap.StructureMapConfigurationExceptionNo default Instance is registered and cannot be automatically determined for type 'IViewFor<RuntimeType>'

There is no configuration specified for IViewFor<RuntimeType>

1.) Container.GetInstance(IViewFor<RuntimeType>)

   at StructureMap.SessionCache.GetDefault(Type pluginType, IPipelineGraph pipelineGraph) in c:\BuildAgent\work\996e173a8ceccdca\src\StructureMap\SessionCache.cs: line 63
   at StructureMap.Container.GetInstance(Type pluginType) in c:\BuildAgent\work\996e173a8ceccdca\src\StructureMap\Container.cs: line 325
   at Redacted.ApplicationDependencyResolver.GetService(Type serviceType, String contract) in ApplicationDependencyResolver.cs: line 27
   at ReactiveUI.DefaultViewLocator.attemptToResolveView(Type type, String contract)
   at ReactiveUI.DefaultViewLocator.ResolveView(T viewModel, String contract)
   at Redacted.BootstrapAndDependencyResolutionTests.ShouldBeAbleToLocateTheViewForAViewModel() in BootstrapAndDependencyResolutionTests.cs: line 39

我显然没有,也不会有任何实现IViewFor<RuntimeType>的视图.有人对为什么会发生这种情况以及我能做什么来解决这个问题有任何想法吗?我不能使用普通的结构配置来排除它.

为了完全清楚,这是解析器和stusturemap bootstrapper的实现:

    public class ApplicationDependencyResolver : IMutableDependencyResolver
{
    private readonly IContainer _container;

    public ApplicationDependencyResolver(IContainer container)
    {
        _container = container;
    }

    public void Dispose()
    {
        _container.Dispose();
    }

    public object GetService(Type serviceType, string contract = null)
    {
        return string.IsNullOrEmpty(contract)
            ? _container.GetInstance(serviceType)
            : _container.GetInstance(serviceType, contract);
    }

    public IEnumerable<object> GetServices(Type serviceType, string contract = null)
    {
        return _container.GetAllInstances(serviceType).Cast<object>();
    }

    public void Register(Func<object> factory, Type serviceType, string contract = null)
    {
        var o = factory();
        _container.Configure(configure => configure.For(serviceType).Use(o));
    }
}

    public sealed class StructureMapBootstrapper
{
    private static readonly StructureMapBootstrapper InternalInstance = new StructureMapBootstrapper();

    static StructureMapBootstrapper() { }

    private StructureMapBootstrapper()
    {
        Configure();
    }

    public static StructureMapBootstrapper Instance { get { return InternalInstance; } }

    public IContainer Container { get; private set; }

    private void Configure()
    {
        Container = new Container(configure =>
        {
            configure.Scan(with =>
            {
                with.TheCallingAssembly();
                with.LookForRegistries();
                with.WithDefaultConventions();
            });
        });
    }
}

推荐答案

在使用RactiveUI单元测试进行了一段优质的时间之后,事实证明,失败的单元测试实际上未正确实现,应该看起来像这样:

[Fact]
public void ShouldBeAbleToLocateTheViewForAViewModel()
{
    var container = StructureMapBootstrapper.Instance.Container;
    var ihas = container.WhatDoIHave();
    Locator.Current = new ApplicationDependencyResolver(container);
    Locator.CurrentMutable.InitializeSplat();
    Locator.CurrentMutable.InitializeReactiveUI();
    var vm = new SplashScreenViewModel();

    var viewLocator = Locator.Current.GetService<IViewLocator>();

    var view = viewLocator.ResolveView(vm);

    view.Should().NotBeNull().And.BeOfType<SplashScreenView>();
}

具体来说,这是我通过typeof(SplashScreenViewMode)的事实,而不是实例,导致测试失败.

编辑:我还必须将with.AddAllTypesOf(typeof (IViewFor<>));添加到structuremap配置中.

本文地址:https://www.itbaoku.cn/post/2043143.html

问题描述

First off, let me say that I don't think that is is an issue with ReactiveUI per se, which is why I've not created an issue on its github repo, and second, I realise that I'm using a beta version of ReactiveUI.

I want to use Structuremap because I'm going to have a plugin scenario in my WPF app, and the DI container in Splat isn't cut out for that sort of thing.

Observe these unit tests:

[Fact]
public void ShouldBeAbleToOverrideDefaultDependencyResolver()
{
    Locator.Current = new ApplicationDependencyResolver(StructureMapBootstrapper.Instance.Container);
    Locator.CurrentMutable.InitializeSplat();
    Locator.CurrentMutable.InitializeReactiveUI();

    var view = Locator.Current.GetService<SplashScreenView>();

    view.Should().NotBeNull().And.BeOfType<SplashScreenView>();
}

[Fact]
public void ShouldBeAbleToLocateTheViewForAViewModel()
{
    Locator.Current = new ApplicationDependencyResolver(StructureMapBootstrapper.Instance.Container);
    Locator.CurrentMutable.InitializeSplat();
    Locator.CurrentMutable.InitializeReactiveUI();
    var viewLocator = Locator.Current.GetService<IViewLocator>();

    var view = viewLocator.ResolveView(typeof (SplashScreenViewModel));

    view.Should().NotBeNull().And.BeOfType<SplashScreenView>();
}

The first test passes. The second test does not, and provides this stacktrace:

StructureMap.StructureMapConfigurationExceptionNo default Instance is registered and cannot be automatically determined for type 'IViewFor<RuntimeType>'

There is no configuration specified for IViewFor<RuntimeType>

1.) Container.GetInstance(IViewFor<RuntimeType>)

   at StructureMap.SessionCache.GetDefault(Type pluginType, IPipelineGraph pipelineGraph) in c:\BuildAgent\work\996e173a8ceccdca\src\StructureMap\SessionCache.cs: line 63
   at StructureMap.Container.GetInstance(Type pluginType) in c:\BuildAgent\work\996e173a8ceccdca\src\StructureMap\Container.cs: line 325
   at Redacted.ApplicationDependencyResolver.GetService(Type serviceType, String contract) in ApplicationDependencyResolver.cs: line 27
   at ReactiveUI.DefaultViewLocator.attemptToResolveView(Type type, String contract)
   at ReactiveUI.DefaultViewLocator.ResolveView(T viewModel, String contract)
   at Redacted.BootstrapAndDependencyResolutionTests.ShouldBeAbleToLocateTheViewForAViewModel() in BootstrapAndDependencyResolutionTests.cs: line 39

I obviously do not, and can not, have any views which implement IViewFor<RuntimeType>. Anyone got any ideas as to why this is happening, and what I can do to get around this? I can't exclude it using the normal Structuremap configuration.

For full clarity here are the implementations of the resolver and the structuremap bootstrapper:

    public class ApplicationDependencyResolver : IMutableDependencyResolver
{
    private readonly IContainer _container;

    public ApplicationDependencyResolver(IContainer container)
    {
        _container = container;
    }

    public void Dispose()
    {
        _container.Dispose();
    }

    public object GetService(Type serviceType, string contract = null)
    {
        return string.IsNullOrEmpty(contract)
            ? _container.GetInstance(serviceType)
            : _container.GetInstance(serviceType, contract);
    }

    public IEnumerable<object> GetServices(Type serviceType, string contract = null)
    {
        return _container.GetAllInstances(serviceType).Cast<object>();
    }

    public void Register(Func<object> factory, Type serviceType, string contract = null)
    {
        var o = factory();
        _container.Configure(configure => configure.For(serviceType).Use(o));
    }
}

    public sealed class StructureMapBootstrapper
{
    private static readonly StructureMapBootstrapper InternalInstance = new StructureMapBootstrapper();

    static StructureMapBootstrapper() { }

    private StructureMapBootstrapper()
    {
        Configure();
    }

    public static StructureMapBootstrapper Instance { get { return InternalInstance; } }

    public IContainer Container { get; private set; }

    private void Configure()
    {
        Container = new Container(configure =>
        {
            configure.Scan(with =>
            {
                with.TheCallingAssembly();
                with.LookForRegistries();
                with.WithDefaultConventions();
            });
        });
    }
}

推荐答案

After some quality time with the ReactiveUI unit tests, it turns out that the unit test which was failing was actually not implemented correctly, and should look like this:

[Fact]
public void ShouldBeAbleToLocateTheViewForAViewModel()
{
    var container = StructureMapBootstrapper.Instance.Container;
    var ihas = container.WhatDoIHave();
    Locator.Current = new ApplicationDependencyResolver(container);
    Locator.CurrentMutable.InitializeSplat();
    Locator.CurrentMutable.InitializeReactiveUI();
    var vm = new SplashScreenViewModel();

    var viewLocator = Locator.Current.GetService<IViewLocator>();

    var view = viewLocator.ResolveView(vm);

    view.Should().NotBeNull().And.BeOfType<SplashScreenView>();
}

Specifically, it was the fact I was passing typeof(SplashScreenViewMode), and not an instance, that was causing the test to fail.

Edit: I also had to add with.AddAllTypesOf(typeof (IViewFor<>)); to the Structuremap configuration.