自定义实例提供程序未在 Xamarin.Forms 应用程序中触发
Custom Instance Provider doesn't trigger in Xamarin.Forms App
我已经阅读了 "Mastering Ninject for Dependency Injection" 这本书,并且我做了电信练习,它教你在 2 个或更多 class 共享相同接口的场景中使用自定义实例提供程序。
我尝试将相同的概念应用于 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 属性的工厂接口,用于选择要应用的服务:
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);
}
}
这是我的属性,自定义实例提供程序将在其中获取属性名称或 class,它在 IFriendServiceFactory 上应用:
public class BindingNameAttribute : Attribute
{
public BindingNameAttribute(string name)
{
Name = name;
}
public string Name { get; set; }
}
最后,这是我 运行 应用程序后代码中断的地方。它甚至没有 运行,它在我的 ViewModel 调用 SwitchFriendService class:
的 Refresh 方法中引发异常
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);
}
}
现在我将通过屏幕截图向您展示异常情况,因为我不明白为什么它没有加载正确的实现,概念和应用实际上与书中相同。
这是我从 Ninject 收到的消息:
Unhandled Exception:
System.NotImplementedException: This is a DynamicProxy2 error: There are no interceptors specified for method 'WhyMvvm.MvvmLightIoc.Abstractions.IFriendService GetFriendService()' which has no target. When calling method without target there is no implementation to 'proceed' to and it is the responsibility of the interceptor to mimic the implementation (set return value, out arguments etc)
Thread finished: #13
但我没有使用拦截器。我应该使用自定义提供程序。
请有人帮助完成这项工作。为了将其应用于 xamarin.forms.
在控制台版本中它工作正常。
希望有人能告诉我我错过了什么?
我能够解决它,事实证明可以通过手动加载 Ninject.Extensions.Factory 来纠正异常,并且可以通过首先添加
的 using 语句来实现
使用Ninject.Extensions.Factory;
在我的例子中,我加载内核的地方在我的 ViewModelLocator 中,所以我没有像我在问题中展示的那样声明我的标准内核,我不得不像这样向内核添加一个 FuncModule:
var settings = new NinjectSettings() { LoadExtensions = false };
NinjectContainer = new StandardKernel(settings, new WhyMvvmModule(), new FuncModule());
第二行代码使 InstanceProvider 工作正常!!!
我已经阅读了 "Mastering Ninject for Dependency Injection" 这本书,并且我做了电信练习,它教你在 2 个或更多 class 共享相同接口的场景中使用自定义实例提供程序。
我尝试将相同的概念应用于 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 属性的工厂接口,用于选择要应用的服务:
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);
}
}
这是我的属性,自定义实例提供程序将在其中获取属性名称或 class,它在 IFriendServiceFactory 上应用:
public class BindingNameAttribute : Attribute
{
public BindingNameAttribute(string name)
{
Name = name;
}
public string Name { get; set; }
}
最后,这是我 运行 应用程序后代码中断的地方。它甚至没有 运行,它在我的 ViewModel 调用 SwitchFriendService class:
的 Refresh 方法中引发异常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);
}
}
现在我将通过屏幕截图向您展示异常情况,因为我不明白为什么它没有加载正确的实现,概念和应用实际上与书中相同。
这是我从 Ninject 收到的消息:
Unhandled Exception: System.NotImplementedException: This is a DynamicProxy2 error: There are no interceptors specified for method 'WhyMvvm.MvvmLightIoc.Abstractions.IFriendService GetFriendService()' which has no target. When calling method without target there is no implementation to 'proceed' to and it is the responsibility of the interceptor to mimic the implementation (set return value, out arguments etc)
Thread finished: #13
但我没有使用拦截器。我应该使用自定义提供程序。
请有人帮助完成这项工作。为了将其应用于 xamarin.forms.
在控制台版本中它工作正常。
希望有人能告诉我我错过了什么?
我能够解决它,事实证明可以通过手动加载 Ninject.Extensions.Factory 来纠正异常,并且可以通过首先添加
的 using 语句来实现使用Ninject.Extensions.Factory;
在我的例子中,我加载内核的地方在我的 ViewModelLocator 中,所以我没有像我在问题中展示的那样声明我的标准内核,我不得不像这样向内核添加一个 FuncModule:
var settings = new NinjectSettings() { LoadExtensions = false };
NinjectContainer = new StandardKernel(settings, new WhyMvvmModule(), new FuncModule());
第二行代码使 InstanceProvider 工作正常!!!