自定义实例提供程序不会在Xamarin.Forms应用程序中触发

时间:2019-09-01 23:29:28

标签: c# xamarin xamarin.forms ninject ninject-extensions

我已经阅读了“掌握依赖注入的精通Ninject”一书,并进行了电信练习,该课程教您如何使用自定义实例提供程序来处理2个或更多类共享同一接口的情况。

我尝试将相同的概念应用于DesignTime数据和运行时,如果我不使用工厂或约定,则我的应用程序可以正常工作,但是,一旦我尝试使用自定义实例提供程序,代码就可以了,但是当到达出厂实现,它不会触发我的实例提供程序为运行时或设计时数据获取正确的实现。

这是我的Ninject模块:

public class WhyMvvmModule : NinjectModule
{
    public override void Load()
    {
        Bind<IFriendServiceFactory>().ToFactory(() => new NameAttributeInstanceProvider());
        Bind<IDialogService>().To<DialogService>();
        Bind<INavigationServiceExtension>().To<NavigationService>();
        Bind<IFriendService>().To<FriendService>().NamedLikeFactoryMethod((IFriendServiceFactory f) => f.GetFriendService());
        Bind<IFriendService>().To<DesignFriendService>().NamedLikeFactoryMethod((IFriendServiceFactory f) => f.GetDesignFriendService());
        Bind<IFileStorageService>().To<FileStorageService>();
    }
}

这是共享界面:

public interface IFriendService
{
    Task<IEnumerable<Friend>> Refresh();
    Task<string> Save(Friend updatedFriend);
}

这是我的带有BindingName属性的Factory接口,用于选择要应用的服务:

public interface IFriendServiceFactory
{
    [BindingName("DesignFriendService")]
    IFriendService GetDesignFriendService();
    [BindingName("FriendService")]
    IFriendService GetFriendService();
}

这些是服务实现:

public class DesignFriendService : IFriendService
{
    public Task<IEnumerable<Friend>> Refresh()
    {
        var result = new List<Friend>();
        for (int i = 0; i < 10; i++)
        {
            result.Add(new Friend { Id = i, FirstName = $"First Name {i}", LastName = $"Last Name {i}", PictureUrl = "LinkedInOriginalLogo256x256.png" });
        }
        return Task.FromResult<IEnumerable<Friend>>(result);
    }

    public Task<string> Save(Friend updatedFriend)
    {
        throw new NotImplementedException();
    }
}

和运行时服务:

public class FriendService : IFriendService
{
    public async Task<IEnumerable<Friend>> Refresh()
    {
        var result = await App.FriendRepo.GetAllFriendsAsync();

        return result.Data;
    }

    public async Task<string> Save(Friend updatedFriend)
    {
        string result = string.Empty;
        result = (await App.FriendRepo.UpdateFriendAsync(updatedFriend)).ToString();

        return result;
    }
}

这是我的自定义实例提供程序:

public class NameAttributeInstanceProvider : StandardInstanceProvider
{
    protected override string GetName(MethodInfo methodInfo, object[] arguments)
    {
        if (methodInfo.GetCustomAttributes(typeof(BindingNameAttribute), true)
            .FirstOrDefault() is BindingNameAttribute nameAttribute)
            return nameAttribute.Name;
        return base.GetName(methodInfo, arguments);
    }
}

这是我的属性,自定义实例提供程序将在其中获得在IFriendServiceFactory上应用的属性或类的名称:

public class BindingNameAttribute : Attribute
{
    public BindingNameAttribute(string name)
    {
        Name = name;
    }

    public string Name { get; set; }
}

最后,这是我运行应用程序后代码中断的地方。它甚至没有运行,它在我的ViewModel的Refresh方法上引发了一个异常,该异常调用了SwitchFriendService类:

ViewModel方法:

async Task Refresh()
{
    Friends.Clear();

    var friends = await _dataService.Refresh();

    foreach (var friend in friends)
    {
        Friends.Add(friend);
    }
}

public MainViewModel(Abstractions.IDialogService dialogService, INavigationServiceExtension navigationService)
{
    //_dataService = ServiceLocator.Current.GetInstance<SwitchFriendService>();
    _dataService = ViewModelLocator.Instance.NinjectContainer.Get<SwitchFriendService>();
    _dialogService = dialogService;
    _navigationService = navigationService;
    Friends = new ObservableCollection<Friend>();

    #if DEBUG
        if (DesignMode.IsDesignModeEnabled)
        {
    #pragma warning disable
            Refresh();
    #pragma warning restore
        }
    #endif
    }

和SwitchFriendService:

public class SwitchFriendService
{
    readonly IFriendServiceFactory _switchFriendServiceFactory;
    public SwitchFriendService(IFriendServiceFactory switchFriendServiceFactory)
    {
        _switchFriendServiceFactory = switchFriendServiceFactory;
    }

    public async Task<IEnumerable<Friend>> Refresh()
    {
        IFriendService friendService;
        if(DesignMode.IsDesignModeEnabled)
        {
            friendService = _switchFriendServiceFactory.GetDesignFriendService();
        }
        else
        {
            friendService = _switchFriendServiceFactory.GetFriendService();
        }
        return await friendService.Refresh();
    }

    public async Task<string> Save(Friend updatedFriend)
    {
        IFriendService friendService;
        if (DesignMode.IsDesignModeEnabled)
        {
            friendService = _switchFriendServiceFactory.GetDesignFriendService();
        }
        else
        {
            friendService = _switchFriendServiceFactory.GetFriendService();
        }

        return await friendService.Save(updatedFriend);
    }
}

现在,我将通过屏幕截图向您展示该异常,因为我不明白为什么它没有加载正确的实现,其概念和应用与本书几乎相同。

Here is where it should trigger the Custom Instance Provider, but after I step to next step it doesnt trigger anything and the services are null.

Here I show you it ends null, after this step it throws an exception.

这是我从Ninject收到的消息:

  

未处理的异常:   System.NotImplementedException:这是一个DynamicProxy2错误:没有为没有目标的方法'WhyMvvm.MvvmLightIoc.Abstractions.IFriendService GetFriendService()'指定拦截器。当调用没有目标的方法时,没有实现要“执行”,拦截器有责任模仿实现(设置返回值,输出参数等)

     

线程完成:#13

但是我没有使用拦截器。我应该使用自定义提供程序。

有人可以帮助完成这项工作吗,PLZ。为了将此应用于xamarin.forms。

在控制台版本中,它工作正常。

希望有人能告诉我我想念什么?

1 个答案:

答案 0 :(得分:0)

我能够解决这个问题,事实证明可以通过手动加载Ninject.Extensions.Factory来纠正异常,并且可以通过首先添加using语句来实现。

使用Ninject.Extensions.Factory;

在我的情况下,我加载内核的地方是在ViewModelLocator中,所以与其像我在问题中所展示的那样声明我的标准内核,还不如这样向内核添加FuncModule:

var settings = new NinjectSettings() { LoadExtensions = false };

NinjectContainer = new StandardKernel(settings, new WhyMvvmModule(), new FuncModule());

第二行代码使InstanceProvider正常工作!!