【问题标题】:DryIoc switch between fake and real service implementation (Xamarin Forms)VS2017DryIoc 真假服务实现切换(Xamarin Forms)VS2017
【发布时间】:2018-11-24 07:24:15
【问题描述】:

我有一种情况,我想在运行时在“FakeService”和“RealService”之间切换。

我的视图模型

    public class BookingViewModel 
    {
        private readonly IBookingService bookingService;

        public WelcomePageViewModel(
            INavigationService navigationService,IBookingService bookingService)
        {
            this.bookingService= bookingService;
        }
     }

在我的 App.xaml 中,我执行以下操作:

    private IContainer container;
    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        container = containerRegistry.GetContainer();

        RegisterRealServices()
    }

    private void RegisterRealServices()
    {
        container.Register<IBookingService, RealBookingService>(Reuse.Singleton);
    }

用户现在按下一个菜单选项来使用假服务。所以取消注册真实服务并使用假服务。

但是我在下面所做的似乎不起作用,因为 我不断被重定向到“RealBookingService”而不是“FakeBookingService”

我该怎么做?

    private void RegisterFakeServices()
    {
        container.Unregister<IBookingService>();

        container.Register<IBookingService,FakeBookingService>(
            Reuse.Singleton,
            ifAlreadyRegistered: IfAlreadyRegistered.Replace);
    }

问题:是否可以在运行时切换服务实现?你如何使用 DryIoc 来做到这一点?

【问题讨论】:

    标签: c# dependency-injection xamarin.forms dryioc


    【解决方案1】:

    一旦你用它来解决实例,你应该从你的容器中prevent removing or replacing registrations——这会导致复杂化,并可能导致非常微妙、难以跟踪的错误,因为实例及其对象图的构造方式都可以缓存在 DI 容器中。你应该更喜欢保持你的对象图是固定的,这样就不会在运行时改变图的形状。

    解决方案是构建一个新的IBookingService 服务实现,它依赖于FakeBookingServiceRealBookingService,并根据运行时信息(您的开关)将传入呼叫转发给其中一个。这是代理模式的一个实现:

    public class BookingServiceSelectorProxy : IBookingService
    {
        private readonly FakeBookingService fake;
        private readonly RealBookingService real;
        public BookingServiceSelectorProxy(FakeBookingService fake, RealBookingService real) {
            this.fake = fake;
            this.real = real;
        }
    
        private IBookingService BookingService => 
            /* return fake or real based on your runtime switch */
    
        // All methods dispatch to one of the wrapped repositories
        public void CompleteBooking(CompleteBookingRequest request)
            => this.BookingService.CompleteBooking(request);
    
        public void CancelBooking(CancelBookingRequest request)
            => this.BookingService.CancelBooking(request);
    }
    

    【讨论】:

    • 谢谢 理想情况下,我不应该在运行时更改它,但这不是我的决定。关于您的实现,您是在说“同时注册”并以一种方法处理它。有趣的是,我没有想到。
    • 是的,但要处理它,而不仅仅是 any 方法。诀窍是让消费者和实现都不知道这种切换正在发生的事实。这就是为什么在新的IBookingService 实现(代理)中实现开关的原因。这使您可以将该代理注入消费者,而无需消费者知道这一点,因此:无需更改。
    【解决方案2】:

    我不是 Xamarin 方面的专家,但在 DryIoc 中取消(重新)注册需要特殊准备(特别是对于单例)。那是因为服务创建可能已经被缓存了。

    这里是详细解释这一点的 wiki: https://bitbucket.org/dadhi/dryioc/wiki/UnregisterAndResolutionCache

    【讨论】:

    • @dahi 感谢您抽出宝贵时间回复我无法在工作时在我的计算机上早点连接(Reuse.Singleton,setup: Setup.With(asResolutionCall: true) 似乎已经成功了。不确定如果它是正确的方法。
    • 是的,看起来不错。请记住,如果您在重新注册之前注入了单例,它不会改变。 DryIoc 不是 MEF,不能即时更改现有属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-16
    相关资源
    最近更新 更多