摘要:我希望使用 MAUIbuilder.Services来解析 ViewModel 中的服务,但我不明白该怎么做。
我可以创建自己的IServiceProvider,但我希望避免所需的样板代码,因此我寻求“标准 MAUI”解决方案。
我添加了以下行MauiProgram.CreateMauiApp():
builder.Services.AddSingleton<IAlertService, AlertService>();
Run Code Online (Sandbox Code Playgroud)
以及相应的声明(在其他文件中):
public interface IAlertService
{
// ----- async calls (use with "await") -----
Task ShowAlertAsync(string title, string message, string cancel = "OK");
Task<bool> ShowConfirmationAsync(string title, string message, string accept = "Yes", string cancel = "No");
}
internal class AlertService : IAlertService
{
// ----- async calls (use with "await") -----
public Task ShowAlertAsync(string title, string message, string cancel = "OK")
{
return Application.Current.MainPage.DisplayAlert(title, message, cancel);
}
public Task<bool> ShowConfirmationAsync(string title, string message, string accept = "Yes", string cancel = "No")
{
return Application.Current.MainPage.DisplayAlert(title, message, accept, cancel);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在我的 BaseViewModel 类中:
internal class BaseViewModel
{
protected static IAlertService AlertSvc = ??? GetService (aka Resolve) ???
public static void Test1()
{
Task.Run(async () =>
await AlertSvc.ShowAlertAsync("Some Title", "Some Message"));
}
}
Run Code Online (Sandbox Code Playgroud)
问:AlertSvcMauiProgram中注册的服务如何填写?
信用:基于一些 SO 讨论或 MAUI 问题中建议的“DialogService”。抱歉,我已经找不到原著了。
Ger*_*uis 17
IServiceProvider所有依赖项都将通过.NET MAUI 的实现提供。幸运的是,它IServiceProvider本身也被添加到依赖注入容器中,因此您可以执行以下操作。
将您需要的内容添加到以下位置的依赖项注入容器中MauiProgram.cs:
builder.Services.AddSingleton<IStringService, StringService>();
builder.Services.AddTransient<FooPage>();
Run Code Online (Sandbox Code Playgroud)
为了完整起见,我的StringService样子是这样的:
public interface IStringService
{
string GetString();
}
public class StringService : IStringService
{
public string GetString()
{
return "string";
}
}
Run Code Online (Sandbox Code Playgroud)
然后在你的FooPage,当然也可以是你的视图模型或任何东西中,添加一个像这样的构造函数:
public FooPage(IServiceProvider provider)
{
InitializeComponent();
var str = provider.GetService<IStringService>().GetString();
}
Run Code Online (Sandbox Code Playgroud)
在这里您可以看到您通过手动解决了该服务,IServiceProvider并且您可以调用该服务。请注意,您需要在此处添加一些错误处理,以查看该服务是否确实可以解决。
如果您不能(或不想)使用 MAUI Shell 的自动构造函数注入,您仍然可以利用IServiceProvider属于类的实例MauiApp。
您可以只创建一个静态类,而不是IServiceProvider在类中存储对 的实现的引用App(这会在为 ViewModel 等编写单元测试时引入其他依赖性问题) :ServiceHelper
public static class ServiceHelper
{
public static IServiceProvider Services { get; private set; }
public static void Initialize(IServiceProvider serviceProvider) =>
Services = serviceProvider;
public static T GetService<T>() => Services.GetService<T>();
}
Run Code Online (Sandbox Code Playgroud)
然后,在调用该方法后ServiceHelper在MauiProgram.cs 文件中对其进行初始化:Build()
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
// ...
builder.Services.AddSingleton<IAlertService, AlertService>();
var app = builder.Build();
//we must initialize our service helper before using it
ServiceHelper.Initialize(app.Services);
return app;
}
Run Code Online (Sandbox Code Playgroud)
最后,您可以解决类中的任何依赖关系,例如 ViewModel,如下所示:
private IAlertService _alertService;
public class MyViewModel()
{
_alertService = ServiceHelper.GetService<IAlertService>();
}
Run Code Online (Sandbox Code Playgroud)
这也可以在单元测试中使用,您可以简单地向 提供一个假的或模拟的实现ServiceHelper,例如:
using Moq;
namespace MyTests;
[TestFixture]
public class MyViewModelTests
{
[Setup]
public void Setup()
{
var alertServiceMock = new Mock<IAlertService>();
var serviceProviderMock = new Mock<IServiceProvider>();
serviceProviderMock
.Setup(sp => sp.GetService<IAlertService>())
.Returns(alertServiceMock.Object);
ServiceHelper.Initialize(serviceProviderMock.Object);
}
// write tests here...
}
Run Code Online (Sandbox Code Playgroud)
我刚刚还发表了一篇关于该主题的博客文章,其中有更多详细信息。
可以通过构造函数的参数在不使用 DI 注入的情况下访问服务提供者(如其他答案中所示):
\nmyvar = Application.Current.Handler.MauiContext.Services.GetService<SomeType>();\nRun Code Online (Sandbox Code Playgroud)\n我\xe2\x80\x99m 不知道有什么理由这样做而不是使用 DI,但为了完整性我提到它。查看对 MauiContext 的访问也能提供丰富的信息。
\n| 归档时间: |
|
| 查看次数: |
8673 次 |
| 最近记录: |