0

I am using saaskit multi tenancy project for multi tenant application.

I am able to create the tenant context and able to access in all controllers.

However, sometimes it give me following error

An unhandled exception has occurred: Unable to resolve service for type 'LMS.Model.AppTenant' while attempting to activate 'LMS.Controllers.OrganizationController'.

This error occurs randomly for any controller and on any action method executed. The nature of error is not specific to any controller/action method.

I can see my code enters the TenantResolver successfully which does in fact return a Tenant but when it comes for DI to inject it into my controller it complains with the error listed

After this error occurs my application stop completely and it shows white screen.

This issue occurs on production server and not on localhost.

Any help on this !

Tenant injected in all controller like this

public class HomeController
    {
        public HomeController(TenantContext<AppTenant> tenantContext)
        {

        }
    }

and below is the extension class for where tenantContext is made injectable

public static class MultitenancyServiceCollectionExtensions
    {
        public static IServiceCollection AddMultitenancy<TTenant, TResolver>(this IServiceCollection services) 
            where TResolver : class, ITenantResolver<TTenant>
            where TTenant : class
        {
            Ensure.Argument.NotNull(services, nameof(services));

            services.AddScoped<ITenantResolver<TTenant>, TResolver>();

            // Make Tenant and TenantContext injectable
            services.AddScoped(prov => 
                prov.GetService<IHttpContextAccessor>()?.HttpContext?.GetTenant<TTenant>());

            services.AddScoped(prov =>
                prov.GetService<IHttpContextAccessor>()?.HttpContext?.GetTenantContext<TTenant>());

            // Ensure caching is available for caching resolvers
            services.AddMemoryCache();

            return services;
        }
    }

Any help on this appreciated !

XamDev
  • 3,377
  • 12
  • 58
  • 97

1 Answers1

1

You can't/shouldn't do that. The issue lies in your registration:

// Make Tenant and TenantContext injectable
services.AddScoped(prov => 
    prov.GetService<IHttpContextAccessor>()?.HttpContext?.GetTenant<TTenant>());

services.AddScoped(prov =>
    prov.GetService<IHttpContextAccessor>()?.HttpContext?.GetTenantContext<TTenant>());

Both of them can be null! When you register a dependency it must NEVER be null!

In such case you must for example ensure that Tenant will always be returned and if there is no tenant information, return a generic or uninitialized Tenant instance. Same for your TenantContext<AppTenant>. It must always be non-null, but the tenant may not have to contain valid tenant information, i.e. you could have a IsValid property on it to check if its a valid tenant or not.

You may have an invalid tenant when someone mistypes the url part which contains the tenant or access the page w/o a tenant header (or however you are handling the tenants).

The reason why you are getting this issue sometimes and sometimes not is because the services are per request (scoped), so with each request it will try to call the factory method again and with each time it can result in null.

Tseng
  • 61,549
  • 15
  • 193
  • 205
  • Thats what my question is ? why it is getting null ? When someone types the invalid url/tenant name that part is handled like you have suggested uninitialized tenant instance(Default tenant). So do I need to register Singleton OR Transient ? – XamDev Dec 17 '16 at 12:11
  • 1
    Not singleton, its a job for scoped lifetime. But looking from the code you posted it seems you are using an older version of Saaskit. The code is from 1.1.3. Code from 1.1.4 looks slightly different https://github.com/saaskit/saaskit/blob/1.1.4/src/SaasKit.Multitenancy/MultitenancyServiceCollectionExtensions.cs – Tseng Dec 17 '16 at 12:51
  • Ok will check it ! Also, I have set `TenanContext` in Session in `AppTenantResolver` class, so that I do not need to resolve tenant again and again. But this session value sometimes comes null for any action method executed. I have set like `context.Session.SetObjectAsJson("TenantContext", tenantContext);` Why this HttpContext session comes null sometimes ? Because of this I am not able to get the tenant context – XamDev Dec 19 '16 at 05:59