0

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
Gibrid
  • 25
  • 4
  • Does the classes that implement your DI interface have a parameterized constructor ? – Poulpynator Mar 31 '23 at 08:44
  • Yes, if there was simple class I can create them manually. – Gibrid Mar 31 '23 at 08:51
  • Services injected with DI should have default constructor (without parameters) or have others services as parameters, post the service code and how you register it if you want more specific help – Poulpynator Mar 31 '23 at 09:20
  • @Poulpynator Added in questions – Gibrid Mar 31 '23 at 09:45
  • You should add IServiceScopeFactory, IDbContextFactory, ... as services as well, otherwise DI will not be able to resolve it – Poulpynator Mar 31 '23 at 10:10
  • The problem isn't that. I know how to work with the DI. I don't know how add DI services in the android background Service. – Gibrid Mar 31 '23 at 11:53
  • My bad, didn't understood that [Service] doesn't support parametrized constructors, gave you an answer to bypass that – Poulpynator Mar 31 '23 at 12:35

1 Answers1

1

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>();
Poulpynator
  • 716
  • 5
  • 13