Search code examples
c#dependency-injectionazure-service-fabricservice-fabric-actor

Service Fabric Actor Service Dependency Injection and Actor Events


When an actor service spins up I would like to auto-subscribe to any of the events as described in the documentation. Manually subscribing to the events works. However when the service is instantiated is there a way to auto-subscribe the actor service, like in the OnActivateAsync()?

What I was trying to do was resolve this through dependency injection that on the instantiation of the MyActor class it passes in an Interface that the OnActivateAsync calls to subscribe events for the client. However I'm having problems with the dependency injection.

Using Microsoft.ServiceFabric.Actors.2.2.207 is supposed to support dependency injection in to actor services. Now when implementing the Microsoft.ServiceFabric.Actors.Runtime.Actor creates a default constructor with the ActorService and ActorId arguments.

I would like to add my own constructor that has an additional interface being passed in. How do you write the registration for the actor service to add the dependency? In the default Program.cs Main it provides this

IMyInjectedInterface myInjectedInterface = null;

// inject interface instance to the UserActor
ActorRuntime.RegisterActorAsync<MyActor>(
   (context, actorType) => new ActorService(context, actorType, () => new MyActor(myInjectedInterface))).GetAwaiter().GetResult();

However on the line where it says "() => new MyActor(myInjectedInterface)" It tells me an error

Delegate 'Func' does not take 0 arguments

Looking at the constructor on the Actor class it has the following

MyActor.Cs

internal class MyActor : Microsoft.ServiceFabric.Actors.Runtime.Actor, IMyActor
{
    private ActorService _actorService;
    private ActorId _actorId;
    private IMyInjectedInterface _myInjectedInterface;

    public SystemUserActor(IMyInjectedInterface myInjectedInterface, ActorService actorService = null, ActorId actorId = null) : base(actorService, actorId)
    {
        _actorService = actorService;
        _actorId = actorId;
        _myInjectedInterface = myInjectedInterface;
    }
}

1) How do I resolve the error I receive when trying to resolve the Actor Dependency?

Delegate 'Func' does not take 0 arguments

Bonus Question:

How do I resolve the IMyInjectedInterface for the interface instance to be injected into the actor service when called by my Stateless Service(calling client)?


Solution

  • IMyInjectedInterface myInjectedInterface = null;
    //inject interface instance to the UserActor
    
    ActorRuntime.RegisterActorAsync<MyActor>(
        (context, actorType) => new ActorService(context, actorType, 
            (service, id) => new MyActor(myInjectedInterface, service, id)))
    
        .GetAwaiter().GetResult();
    

    The signature for the function that creates your actor instances is:

    Func<ActorService, ActorId, ActorBase>
    

    The framework provides an instance of ActorService and ActorId which you can pass in to your Actor's constructor and down through the base constructor.

    Bonus Answer:

    The use case here is a little different than what you're thinking of. The pattern here is a general pattern that decouples concrete implementations via interfaces - it's not a way for client applications to modify runtime behavior. So the calling client doesn't provide the concrete implementation of the dependency (at least not through constructor injection). The dependency is injected at compile time. An IoC container usually does that, or you can provide one manually.