英文:
Dependency injection in background service android maui
问题
我在Android MAUI中创建了一个后台服务,就像在这个问题中描述的一样:如何在.NET MAUI中创建后台服务。它运行正常。但我不明白如何在这个后台服务中添加依赖注入(DI)服务?
我需要添加IDbContextFactory
以用于我的EF Core上下文和IServiceScopeFactory
。
如果我将它们添加到构造函数中,我会得到一个错误:Error XA4213 The type 'MyBackgroundService' must provide a public default constructor
.
我的后台服务示例代码如下:
[Service]
public class AndroidBackgroundService : Service, IService
{
UpdateBackgroundService _updateBackgroundService; //我需要这个DI服务
public AndroidBackgroundService(UpdateBackgroundService updateBackgroundService) //这里编译错误
{
_updateBackgroundService = updateBackgroundService;
}
public AndroidBackgroundService()
{
}
public override IBinder OnBind(Intent intent)
{
throw new NotImplementedException();
}
[return: GeneratedEnum]//我们捕获操作意图以了解前台服务的状态
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
if (intent.Action == "START_SERVICE")
{
RegisterNotification();//进行通知
Run();
}
else if (intent.Action == "STOP_SERVICE")
{
StopForeground(true);//停止服务
StopSelfResult(startId);
}
return StartCommandResult.NotSticky;
}
public void Run()
{
_updateBackgroundService.Run();
}
//启动和停止意图,为MainActivity设置操作以获取前台服务的状态
//设置一个启动操作和一个停止前台服务的操作
public void Start()
{
Intent startService = new Intent(Microsoft.Maui.ApplicationModel.Platform.CurrentActivity, typeof(AndroidBackgroundService));
startService.SetAction("START_SERVICE");
Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.StartService(startService);
}
public void Stop()
{
Intent stopIntent = new Intent(Microsoft.Maui.ApplicationModel.Platform.CurrentActivity, this.Class);
stopIntent.SetAction("STOP_SERVICE");
Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.StartService(stopIntent);
}
private void RegisterNotification()
{
NotificationChannel channel = new NotificationChannel("ServiceChannel", "ServiceDemo", NotificationImportance.Max);
NotificationManager manager = (NotificationManager)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.GetSystemService(Context.NotificationService);
manager.CreateNotificationChannel(channel);
Notification notification = new Notification.Builder(this, "ServiceChannel")
.SetContentTitle("Агент 2 фоновый процесс запущен")
.SetSmallIcon(Resource.Drawable.abc_ab_share_pack_mtrl_alpha)
.SetOngoing(true)
.Build();
StartForeground(100, notification);
}
}
我的UpdateBackgroundService
示例代码如下:
public class UpdateBackgroundService : BaseBackgroundService
{
private readonly IServiceScopeFactory scopeFactory;
private readonly IDbContextFactory<AsterixDBContext> _DbContextFactoryAsterix;
private readonly IDbContextFactory<Agent2DBContext> _DbContextFactory;
public UpdateBackgroundService(IServiceScopeFactory scopeFactory, IDbContextFactory<Agent2DBContext> dbContextFactory, IDbContextFactory<AsterixDBContext> dbContextFactoryAsterix)
: base(dbContextFactory)
{
this.scopeFactory = scopeFactory;
_DbContextFactoryAsterix = dbContextFactoryAsterix;
_DbContextFactory = dbContextFactory;
}
public Run()
{
// 实现你的Run方法
}
}
MauiProgram
示例代码如下:
builder.Services.AddTransient<UpdateBackgroundService>();
#if ANDROID
builder.Services.AddTransient<AndroidBackgroundService>();
#endif
这些是你的代码示例的主要部分。希望这能帮助你解决DI服务的问题。
英文:
I created a background service in android maui like in this question: How to create a background service in .NET Maui. It's working fine. But I don't understand how to add DI services in this background?
I need to add IDbContextFactory for my ef core context and IServiceScopeFactory.
If I add them in the constructor, I got an error:
Error XA4213 The type 'MyBackgroundService' must provide a public default constructor
.
My backgroubdService:
[Service]
public class AndroidBackgroundService : Service, IService
{
UpdateBackgroundService _updateBackgroundService; //I need this DI service
public AndroidBackgroundService(UpdateBackgroundService updateBackgroundService) //This compile error
{
_updateBackgroundService = updateBackgroundService;
}
public AndroidBackgroundService()
{
}
public override IBinder OnBind(Intent intent)
{
throw new NotImplementedException();
}
[return: GeneratedEnum]//we catch the actions intents to know the state of the foreground service
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
if (intent.Action == "START_SERVICE")
{
RegisterNotification();//Proceed to notify
Run();
}
else if (intent.Action == "STOP_SERVICE")
{
StopForeground(true);//Stop the service
StopSelfResult(startId);
}
return StartCommandResult.NotSticky;
}
public void Run()
{
_updateBackgroundService.Run();
}
//Start and Stop Intents, set the actions for the MainActivity to get the state of the foreground service
//Setting one action to start and one action to stop the foreground service
public void Start()
{
Intent startService = new Intent(Microsoft.Maui.ApplicationModel.Platform.CurrentActivity, typeof(AndroidBackgroundService));
startService.SetAction("START_SERVICE");
Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.StartService(startService);
}
public void Stop()
{
Intent stopIntent = new Intent(Microsoft.Maui.ApplicationModel.Platform.CurrentActivity, this.Class);
stopIntent.SetAction("STOP_SERVICE");
Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.StartService(stopIntent);
}
private void RegisterNotification()
{
NotificationChannel channel = new NotificationChannel("ServiceChannel", "ServiceDemo", NotificationImportance.Max);
NotificationManager manager = (NotificationManager)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.GetSystemService(Context.NotificationService);
manager.CreateNotificationChannel(channel);
Notification notification = new Notification.Builder(this, "ServiceChannel")
.SetContentTitle("Агент 2 фоновый процесс запущен")
.SetSmallIcon(Resource.Drawable.abc_ab_share_pack_mtrl_alpha)
.SetOngoing(true)
.Build();
StartForeground(100, notification);
}
}
My UpdateBackgroundService
public class UpdateBackgroundService : BaseBackgroundService
{
private readonly IServiceScopeFactory scopeFactory;
private readonly IDbContextFactory<AsterixDBContext> _DbContextFactoryAsterix;
private readonly IDbContextFactory<Agent2DBContext> _DbContextFactory;
public UpdateBackgroundService(IServiceScopeFactory scopeFactory, IDbContextFactory<Agent2DBContext> dbContextFactory, IDbContextFactory<AsterixDBContext> dbContextFactoryAsterix)
: base(dbContextFactory)
{
this.scopeFactory = scopeFactory;
_DbContextFactoryAsterix = dbContextFactoryAsterix;
_DbContextFactory = dbContextFactory;
}
public Run()
{
...
}
}
MauiProgram
builder.Services.AddTransient<UpdateBackgroundService>();
#if ANDROID
builder.Services.AddTransient<AndroidBackgroundService>();
#endif
答案1
得分: 2
看起来一个[Service]类的构造函数不能有任何参数,这里提供了一种不需要传递参数的依赖注入的替代方法。
创建一个ServiceProvider
类:
public static class ServiceProvider
{
public static TService GetService<TService>()
=> Current.GetService<TService>();
public static IServiceProvider Current
#if WINDOWS10_0_17763_0_OR_GREATER
=> MauiWinUIApplication.Current.Services;
#elif ANDROID
=> MauiApplication.Current.Services;
#elif IOS || MACCATALYST
=> MauiUIApplicationDelegate.Current.Services;
#else
=> null;
#endif
}
然后你可以简单地在任何组件的构造函数中使用它:
_Contexte = ServiceHelper.GetService<Contexte>();
英文:
Seems like a [Service] class can't have any parameters in the constructor, here is an alternative way to use dependency injection without passing parameters.
Create a ServiceProvider
class :
public static class ServiceProvider
{
public static TService GetService<TService>()
=> Current.GetService<TService>();
public static IServiceProvider Current
=>
#if WINDOWS10_0_17763_0_OR_GREATER
MauiWinUIApplication.Current.Services;
#elif ANDROID
MauiApplication.Current.Services;
#elif IOS || MACCATALYST
MauiUIApplicationDelegate.Current.Services;
#else
null;
#endif
}
Then you can simply use it in any component constructor :
_Contexte = ServiceHelper.GetService<Contexte>();
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论