Register dependencies from session / token

We’re starting to migrate a rather large monolithic MVC 5 app to APIs and we have a question about how we’d solve our multi tenancy issue using ServiceStack.

In our MVC app we have a single Neo4j database and use a different sub-graph for each tenant. In graphs terms, a label is somewhat similar to a sql table. We prefix each label with our tenant id <tenant_key>_Topic. Example: MATCH (person:tenant1_Person) RETURN person.

We’re using forms authentication and we obtain tenant id from cookie and register our ITenant instance from HTTPContext:

// MVC / Autofac tenant registration
builder
	.Register(context => HttpContext.Current.User as ITenant)
	.As<ITenant>()
	.InstancePerLifetimeScope();

From there we can resolve the correct ITenant for all user requests. This interface is weaved throughout the application.

In ServiceStack terms we’d like to do something similar. As we start building the APIs we’ll still have the MVC app, and as part of forms authentication, we’ll perform a secondary authentication against a ServiceStack API and probably obtain a JWT. We’d like to store the tenant key in this token and then calls to the secured APIs would need to extract the tenant key from the token and register an ITenant in the API host.

public interface ITenant
{
	string Key { get; set; }
}

public class Tenant : ITenant
{
	public string Key { get; set; }
}

public class AppHost : AppHostBase
{
	public AppHost() : base("demo", typeof(MyServices).Assembly) { }

	// Configure your AppHost with the necessary configuration and dependencies your App needs
	public override void Configure(Container container)
	{
		container.Register<ITenant>(c =>
		{
			var token = c.Resolve<???>

			return new Tenant
			{
				Key = token.TenantKey
			};
		}).ReusedWithin(ReuseScope.Request); 
	}
}

But as you can see, I’m stuck at this point. I’m not sure what object is available to be in order to extract the tenant key. Can I access the request object? Or the user’s session? Once we’re passing JWTs can I access them in this context?

Another option for consideration is to register an empty ITenant and then mutate this in a filter, setting ITenant.Key accordingly. But I’m not keen on mutating dependencies.

You don’t have access to the HTTP Request when registering an IOC dependency, you can register the HttpContextAccessor to enable it but it’s not recommended and I wouldn’t be designing my systems to rely on it.

The way ServiceStack Multitenancy for DB connections work is in the base Service class it resolves the DB connection at runtime by inspecting the incoming IRequest into a lazily initialized property, e.g:

private IDbConnection db;
public virtual IDbConnection Db => db ?? (db = HostContext.AppHost.GetDbConnection(Request));

Which should then be disposed if it was created:

public virtual void Dispose()
{
    db?.Dispose();
}

An alternative solution is to inject IRequest.Items with your dependency in a global Request Filter which your Service and all other filters in the Request pipeline will be able to access and will be disposed at the end of the request if your dependency implements IDisposable.