依赖注入在后台服务 Android MAUI 中

huangapple go评论78阅读模式
英文:

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 &#39;MyBackgroundService&#39; 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 == &quot;START_SERVICE&quot;)
            {
                RegisterNotification();//Proceed to notify
                Run();
            }
            else if (intent.Action == &quot;STOP_SERVICE&quot;)
            {
                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(&quot;START_SERVICE&quot;);
            Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.StartService(startService);
        }

        public void Stop()
        {
            Intent stopIntent = new Intent(Microsoft.Maui.ApplicationModel.Platform.CurrentActivity, this.Class);
            stopIntent.SetAction(&quot;STOP_SERVICE&quot;);
            Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.StartService(stopIntent);
        }

        private void RegisterNotification()
        {
            NotificationChannel channel = new NotificationChannel(&quot;ServiceChannel&quot;, &quot;ServiceDemo&quot;, NotificationImportance.Max);
            NotificationManager manager = (NotificationManager)Microsoft.Maui.ApplicationModel.Platform.CurrentActivity.GetSystemService(Context.NotificationService);
            manager.CreateNotificationChannel(channel);
            Notification notification = new Notification.Builder(this, &quot;ServiceChannel&quot;)
               .SetContentTitle(&quot;Агент 2 фоновый процесс запущен&quot;)
               .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&lt;AsterixDBContext&gt; _DbContextFactoryAsterix;
	private readonly IDbContextFactory&lt;Agent2DBContext&gt; _DbContextFactory;

	public UpdateBackgroundService(IServiceScopeFactory scopeFactory, IDbContextFactory&lt;Agent2DBContext&gt; dbContextFactory, IDbContextFactory&lt;AsterixDBContext&gt; dbContextFactoryAsterix)
		: base(dbContextFactory)
	{
		this.scopeFactory = scopeFactory;
		_DbContextFactoryAsterix = dbContextFactoryAsterix;
		_DbContextFactory = dbContextFactory;
	}
	
	public Run()
	{
	...
	}
}

MauiProgram

builder.Services.AddTransient&lt;UpdateBackgroundService&gt;();
#if ANDROID
     builder.Services.AddTransient&lt;AndroidBackgroundService&gt;();
#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&lt;TService&gt;()
        =&gt; Current.GetService&lt;TService&gt;();

    public static IServiceProvider Current
        =&gt;
#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&lt;Contexte&gt;();

huangapple
  • 本文由 发表于 2023年3月31日 16:07:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/75896221.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定