2

Extening on : IOC injection of IServerSideEvents

I am trying to setup a Singleton on the container which requires IServerSideEvents (IMessager has the dependancy).

 // setup Engine
List<IFileHandler> handler = new List<IFileHandler>() { new FileHandler() };
var engine = new Engine(handler, new List<IFileConverter>());
engine.Fail += container.Resolve<IMessager>().Error;
container.AddSingleton<Engine>(engine);

This is becuase I need to bind same events in multiple controllers but the events are in an external library. I can bind them fine on injection of a controller, but trying to get IOC to handle it will not work, returns the same error as above.

I imagine this is a loading order issue and when I am attempting to resolve the dependancy, the plugins have yet to be loaded. This is being attemtped in the Configure(Container container) method

Barry
  • 357
  • 1
  • 11

1 Answers1

1

Please read section on the .NET Core Container Adapter:

any dependencies registered .NET Core Startup are also available to ServiceStack but dependencies registered in ServiceStack’s IOC are only visible to ServiceStack.

So if you need dependencies available to both ServiceStack and external ASP.NET Core features like MVC you need to register them in your Startup.ConfigureServices().

Plugins

From your link:

public override void Configure(Funq.Container container)
{
    var serverEventsFeature = new ServerEventsFeature();
    // bind server events
    serverEventsFeature.Register(this);         
    container.AddSingleton(new Engine(container.Resolve<IServerEvents>()));
}

Plugins should never be called directly like this, they're expected to be registered in the Plugins collection:

Plugins.Add(new ServerEventsFeature());

Plugins are registered after Configure() is run, if you want to register a dependency that uses IServerEvents registered by the ServerEventsFeature you would need to either register your dependency with a factory function, i.e:

container.AddSingleton<ICacheClient>(c => 
    new Engine(c.Resolve<IServerEvents>()));

Alternatively you can register a singleton instance an AfterInitCallbacks which is run at the end of AppHost initialization, e.g:

AfterInitCallbacks.Add(host => {
    container.AddSingleton<ICacheClient>(
        new Engine(c.Resolve<IServerEvents>()));
});

If you wanted to register a singleton that any other Plugin registered you can have your plugin to implement IPostInitPlugin which runs AfterPluginsLoaded() after all plugins are registered:

public class MyPlugin : IPlugin, IPostInitPlugin
{
    public void Register(IAppHost appHost) {}

    public void AfterPluginsLoaded(IAppHost appHost)
    {
        appHost.GetContainer().AddSingleton<ICacheClient>(c => 
            new Engine(c.Resolve<IServerEvents>()));
    }
}
mythz
  • 141,670
  • 29
  • 246
  • 390
  • That isn't the problem. I need them inside ServiceStack framework, but it is a race condition. If i take the implimentation provided in the linked post and put it straight before my call, it works flawlessly. The Plugin Add is not being ran before the end of the Configure(Funq.Container container) ergo when trying to resolve in configure it fails. Is there a service stack contextual method AFTER configure which has access to the container model which I can append the singleton to ? – Barry May 22 '19 at 10:45
  • @Barry You may have an logic ordering problem but there's no a race condition as there's only 1 thread that runs App Startup. Your code doesn't indicate what your logic ordering problem is, if you registered your dependency in `Startup.ConfigureServices()` as suggested it would be available in MVC Controllers as well as in `AppHost.Configure()` and plugins. Plugins are registered in `Configure()` and run after `Configure()` is run, if you need logic to run before/after plugins are registered your [plugins can implement IPreInitPlugin interface](https://docs.servicestack.net/plugins). – mythz May 22 '19 at 13:12
  • All code is in SS. When I say race condition. the plugin's [Register](https://github.com/ServiceStack/ServiceStack/blob/62403cf85c4c15b862c2448bac4892bc0a3c8c4c/src/ServiceStack/ServerEventsFeature.cs#L82) is not ran before the end of the configure function. Example of not working/working [here](https://dotnetfiddle.net/Wrrbgg The register on a plugin seems to not be called immediately ergo the reference cannot be resolved however if i call the register myself, it is resolvable. Additionally, the ServiceEvents plugin does not use IPreInitPlugin and the PreInit has no access to the container. – Barry May 23 '19 at 14:31
  • Character limit, please see above @mythz – Barry May 23 '19 at 14:39
  • @Barry See my updated answer, `IPreInitPlugin` interface is for implementing in your own plugins that you want to run custom logic before Plugins are registered, you would implement `IPostInitPlugin` for running custom logic after plugins are registered. – mythz May 23 '19 at 19:54
  • container.AddSingleton(c => new Engine(c.Resolve())); seems to be the missing piece of info I was missing. Thanks – Barry May 24 '19 at 09:48