Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ServiceStack AppHost Is a Singleton?

I have been evaluating ServiceStack and so far, I've been pretty much sold - but I have a requirement that I think is going to be a deal-breaker.

I basically need multiple AppHost-derived instances. The first one spins up nicely, but the rest fail because "AppHostBase.Instance has already been set".

Does this mean if I want multiple hosts (on different Uris), to be in different executables? If so this is rather disappointing as this library is perfect in every single other way, other than this limitation.

If I am wrong, can anyone point me to a solution?

Allow me to elaborate a little. We have plans for many, many services across the network. My intention is that they are designed as individual services and then "hosted" in a hosting class. The hosting class itself is a service for administrative purposes and has the ability to start and stop services. They are "discoverable" across the network. We can spin up and spin down services on different machines at different times, or at will.

My plan was to use service-stack for each of these things and have the ability to create and destroy the services in an ad-hoc manner on any machine and in any "host". The only thing I am stumbling on is the AppHost only being initialised once.

Obviously I am doing something wrong, so any information on how to host multiple services in the same executable would be great :)

like image 312
Moo-Juice Avatar asked Apr 06 '13 11:04

Moo-Juice


1 Answers

In response to this question I've added new Modularizing services and Physical project structure wiki pages to highlight the different ways of structuring and modularizing ServiceStack services which I'll repeat hear for discoverability:

As you've discovered, ServiceStack has a single App Host for each App Domain. As you might be able to infer from the name, the role of the Host project is to be the conduit for binding all your services concrete dependencies, plugins, filters and everything else your service needs. The configuration of your service should be immutable after everything is initialized in your AppHost.Configure() method. The Physical project structure wiki page wiki shows the recommended physical project structure for typical solutions.

Modularizing services in multiple assemblies

Whilst you can only have 1 AppHost, services can be spread across multiple assemblies by providing the Assemblies in the AppHostBase constructor, e.g:

public class AppHost : AppHostBase
{
    //Tell Service Stack the name of your application and which assemblies to find your web services
    public AppHost() : base("Hello ServiceStack!", 
       typeof(ServicesFromDll1).Assembly, ServicesFromDll2).Assembly /*, etc */) { }

    public override void Configure(Container container) {}
}

You can also provide your own strategy for discovering and resolving the service types that ServiceStack should auto-wire by overriding CreateServiceManager, e.g:

public class AppHost : AppHostBase
{
    public AppHost() : base("Hello ServiceStack!", typeof(ServicesFromDll1).Assembly) { }
    public override void Configure(Container container) {}

    //Provide Alternative way to inject IOC Container + Service Resolver strategy
    protected virtual ServiceManager CreateServiceManager(params Assembly[] assembliesWithServices)
    {       
        return new ServiceManager(new Container(),
            new ServiceController(() => assembliesWithServices.ToList().SelectMany(x => x.GetTypes())));
    }
}

Encapsulating Services inside Plugins

One way of modularizing services is to encapsulate them inside Plugins which allows you to manually register services, custom routes, filters, content types, allow customization and anything else your module needs.

To illustrate this point, we'll show what a Basic Auth Feature example might look like:

public class BasicAuthFeature : IPlugin 
{
    public string HtmlRedirect { get; set; }   //User-defined configuration

    public void Register(IAppHost appHost)
    {
        //Register Services exposed by this module
        appHost.RegisterService<AuthService>("/auth", "/auth/{provider}");
        appHost.RegisterService<AssignRolesService>("/assignroles");
        appHost.RegisterService<UnAssignRolesService>("/unassignroles");

        //Load dependent plugins
        appHost.LoadPlugin(new SessionFeature());
    }
}

With everything encapsulated inside a plugin, your users can easily enable them in your AppHost with:

Plugins.Add(new BasicAuthFeature { HtmlRedirect = "~/login" });

Physical Project Structure

See this earlier answer on the recommended way to physically layout your project.

like image 183
mythz Avatar answered Sep 19 '22 01:09

mythz