我花了两周多时间搜索谷歌,bing,堆栈溢出和msdn文档,试图找出如何为我正在开发的移动应用程序进行适当的依赖注入。要清楚,我每天都在网络应用程序中进行DI。我不需要关于什么,谁以及为什么DI很重要的速成课程。我知道它是,并且我总是拥抱它。
我需要了解的是它在移动应用程序世界中的运作方式,尤其是UWP Template 10 Mobile应用程序。
从我的过去,在.net / Asp应用程序中我可以" RegisterType(新XYZ).Singleton()等等#34; {请原谅语法;只是一个例子}在App_Start.ConfigureServices中。这在.netcore中几乎完全相同,授予了一些语法更改。
我的问题是现在我正在尝试提供我的api将要使用需要消化我的IXYZ服务的UWP应用程序。绝不是我认为他们应该"新"每次都有一个实例。必须有一种方法将其注入UWP方面的容器中;而且我觉得我在这个过程中缺少一些非常的东西。
这是我的代码:
App.xaml.cs
public override async Task OnStartAsync(StartKind startKind, IActivatedEventArgs args)
{
// TODO: add your long-running task here
//if (args.Kind == ActivationKind.LockScreen)
//{
//}
RegisterServices();
await NavigationService.NavigateAsync(typeof(Views.SearchCompanyPage));
}
public static IServiceProvider Container { get; private set; }
private static void RegisterServices()
{
var services = new ServiceCollection();
services.AddSingleton<IXYZ, XYZ>();
Container = services.BuildServiceProvider();
}
MainPage.xaml.cs中:
public MainPage()
{
InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Enabled;
}
MainPageViewModel:
public class MainPageViewModel : ViewModelBase
{
private readonly IXYZ _xyz;
public MainPageViewModel(IXYZ xyz)
{
//Stuff
_xyz= xyz;
}
}
我现在收到错误: XAML MainPage ...无法构造ViewModel类型。为了在XAML中构造,类型不能是抽象的,接口嵌套的泛型或结构,并且必须具有公共默认构造函数。
我愿意使用任何品牌的IoC Container,但我需要的是如何在UWP应用中正确使用DI服务的示例。关于DI的99.9%的问题是关于视图(即Prism?)而不仅仅是服务的简单DI(即DataRepo;又称API / DataService)。
再一次,我觉得我错过了一些明显的东西,需要在正确的方向上轻推。有人可以告诉我一个示例项目,基本代码,或基于我不应该成为程序员的基础......请不要这样做(我不知道我的自我是否可以接受它)。
答案 0 :(得分:1)
您可以尝试像ASP.NET一样使用Microsoft.Hosting.Extensions,James Montemagno在Xamarin.Forms上有一个实现,它也可以在我尝试过的UWP中使用,并且效果很好。您必须更改某些部分才能使其正常工作。
在OnLaunched方法中,添加Startup.Init();
public static class Startup
{
public static IServiceProvider ServiceProvider { get; set; }
public static void Init()
{
StorageFolder LocalFolder = ApplicationData.Current.LocalFolder;
var configFile = ExtractResource("Sales.Client.appsettings.json", LocalFolder.Path);
var host = new HostBuilder()
.ConfigureHostConfiguration(c =>
{
// Tell the host configuration where to file the file (this is required for Xamarin apps)
c.AddCommandLine(new string[] { $"ContentRoot={LocalFolder.Path}" });
//read in the configuration file!
c.AddJsonFile(configFile);
})
.ConfigureServices((c, x) =>
{
// Configure our local services and access the host configuration
ConfigureServices(c, x);
}).
ConfigureLogging(l => l.AddConsole(o =>
{
//setup a console logger and disable colors since they don't have any colors in VS
o.DisableColors = true;
}))
.Build();
//Save our service provider so we can use it later.
ServiceProvider = host.Services;
}
static void ConfigureServices(HostBuilderContext ctx, IServiceCollection services)
{
//ViewModels
services.AddTransient<HomeViewModel>();
services.AddTransient<MainPageViewModel>();
}
static string ExtractResource(string filename, string location)
{
var a = Assembly.GetExecutingAssembly();
using (var resFilestream = a.GetManifestResourceStream(filename))
{
if (resFilestream != null)
{
var full = Path.Combine(location, filename);
using (var stream = File.Create(full))
{
resFilestream.CopyTo(stream);
}
}
}
return Path.Combine(location, filename);
}
}
Injecting a ViewModel也可以,这很好。
答案 1 :(得分:0)
在@mvermef和SO问题Dependency Injection using Template 10的帮助下,我找到了解决方案。事实证明这是一个兔子洞,每次转弯都会遇到问题。
第一个问题是让依赖注入工作。一旦我能够从上面的来源中弄明白,我就可以开始将我的服务注入ViewModels并将它们设置为后面代码中的DataContext。
然后我遇到注入问题,将我的IXYZ服务注入到UserControls的ViewModels中。
Pages和他们的ViewModel工作得很好,但我遇到的问题是UserControl的DataContext没有注入UserControl的ViewModel。相反,它们是由持有它的Page的ViewModel注入的。
最终的解决方案是确保 UserControl 在 XAML 中设置了DataContext不是后面的代码,就像我们对Pages做的那样,然后在后面的代码中创建DependencyProperty。
要显示下面的基本解决方案。
为了使它成功,我开始:
<强> APP.XAML.CS 强>
public override async Task OnStartAsync(StartKind startKind, IActivatedEventArgs args)
{
// long-running startup tasks go here
RegisterServices();
await Task.CompletedTask;
}
private static void RegisterServices()
{
var services = new ServiceCollection();
services.AddSingleton<IRepository, Repository>();
services.AddSingleton<IBinderService, BinderServices>();
**//ViewModels**
**////User Controls**
services.AddSingleton<AddressesControlViewModel, AddressesControlViewModel>();
services.AddSingleton<CompanyControlViewModel, CompanyControlViewModel>();
**//ViewModels**
**////Pages**
services.AddSingleton<CallListPageViewModel, CallListPageViewModel>();
services.AddSingleton<CallListResultPageViewModel, CallListResultPageViewModel>();
etc....
Container = services.BuildServiceProvider();
}
public override INavigable ResolveForPage(Page page, NavigationService navigationService)
{
**//INJECT THE VIEWMODEL FOR EACH PAGE**
**//ONLY THE PAGE NOT USERCONTROL**
if (page is CallListPage)
{
return Container.GetService<CallListPageViewModel>();
}
if (page is CallListResultPage)
{
return Container.GetService<CallListResultPageViewModel>();
}
etc...
return base.ResolveForPage(page, navigationService);
}
在页面背后的代码中
<强> CALLLISTPAGE.XAML.CS 强>
public CallListPage()
{
InitializeComponent();
}
CallListPageViewModel _viewModel;
public CallListPageViewModel ViewModel
{
get { return _viewModel ?? (_viewModel = (CallListPageViewModel)DataContext); }
}
在您的XAML中添加您的UserControl
<强> CALLLISTPAGE.XAML 强>
<binder:CompanyControl Company="{x:Bind ViewModel.SelectedCompany, Mode=TwoWay}"/>
在UserControl中,确保将DataContext添加到XAML NOT 后面的代码,就像我们对页面所做的那样。
<强> COMPANYCONTROL.XAML 强>
<UserControl.DataContext>
<viewModels:CompanyControlViewModel x:Name="ViewModel" />
</UserControl.DataContext>
在UserControl Code Behind中添加依赖属性
<强> COMPANYCONTROL.XAML.CS 强>
public static readonly DependencyProperty CompanyProperty = DependencyProperty.Register(
"Company", typeof(Company), typeof(CompanyControl), new PropertyMetadata(default(Company), SetCompany));
public CompanyControl()
{
InitializeComponent();
}
public Company Company
{
get => (Company) GetValue(CompanyProperty);
set => SetValue(CompanyProperty, value);
}
private static void SetCompany(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as CompanyControl;
var viewModel = control?.ViewModel;
if (viewModel != null)
viewModel.Company = (Company) e.NewValue;
}
最后我不确定这是否是一个优雅的解决方案,但它确实有效。