XamDev
XamDev

Reputation: 3657

Working with dependency injection in mvc

In one of our app I am already using the dependency injection of AppTenant class like follows

public void ConfigureServices(IServiceCollection services)
{

services.AddMultitenancy<AppTenant, CachingAppTenantResolver>();
services.Configure<MultitenancyOptions>(Configuration.GetSection("Multitenancy"));
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
 app.UseMultitenancy<AppTenant>();
}

and in controller i am able to access it easily as follows

public AccountController(AppTenant tenant)
    {
        this.tenant = tenant;
    }

Now, I want to access the same AppTenant OR HttpContext in other project class in the same solution. So, I have tried like this

public SqlStringLocalizerFactory(
       AppTenant tenant)
    {
     _tenant = tenant;

    }

But it is coming null, so what I need to do, to get the AppTenant OR HttpContext in the other project class ?

For SqlStringLocalizerFactory class the services are written in ConfigureServices method like follows

public static class SqlLocalizationServiceCollectionExtensions
{

    public static IServiceCollection AddSqlLocalization(this IServiceCollection services)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        return AddSqlLocalization(services, setupAction: null);
    }

   public static IServiceCollection AddSqlLocalization(
        this IServiceCollection services,
       Action<SqlLocalizationOptions> setupAction)
    {

            if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        services.TryAdd(new ServiceDescriptor(
            typeof(IStringExtendedLocalizerFactory),
            typeof(SqlStringLocalizerFactory),
            ServiceLifetime.Singleton));
        services.TryAdd(new ServiceDescriptor(
            typeof(IStringLocalizerFactory),
            typeof(SqlStringLocalizerFactory),
            ServiceLifetime.Singleton));
        services.TryAdd(new ServiceDescriptor(
            typeof(IStringLocalizer),
            typeof(SqlStringLocalizer),
            ServiceLifetime.Singleton));

        if (setupAction != null)
        {
            services.Configure(setupAction);
        }
        return services;
    }
}

I have even tried with IHttpContextAccessor, but still not getting any success.

Any help on this appreciated !

Upvotes: 1

Views: 578

Answers (2)

adem caglin
adem caglin

Reputation: 24123

Edit-2

New Solution:

public SqlStringLocalizerFactory(IHttpContextAccessor _accessor)
{
   _accessor= accessor;
}
public void SomeMethod()
{
    var tenant = _accessor.HttpContext.RequestServices
            .GetRequiredService<AppTenant>();
}

Edit : IServiceProvider way doesn't work as i expect. See @Sock's solution

First, i assumes the problem occurs because of captive dependency as pointed by @qujck. To avoid captive dependency:

If lifetime of SqlStringLocalizerFactory must be singleton(some cases must be), in this case use IServiceProvider:

public SqlStringLocalizerFactory(IServiceProvider serviceProvider)
{
   _serviceProvider = serviceProvider;
}
public void SomeMethod()
{
    var tenant =  _serviceProvider.GetService<AppTenant>();
}

Otherwise using AddScoped seems reasonable for your case.

Upvotes: 2

Sock
Sock

Reputation: 5413

You have two options, the best option, if the SqlStringLocalizerFactory can be a scoped dependency (you get a new instance for every request) then you can register it as a scoped dependency:

services.TryAdd(new ServiceDescriptor(
        typeof(IStringLocalizerFactory),
        typeof(SqlStringLocalizerFactory),
        ServiceLifetime.Scoped));

If the SqlStringLocalizerFactory must be a a Singleton dependency, then you need to make sure you resolve a scoped dependency for the Tenant by using a ServiceSope:

public class SqlStringLocalizerFactory
{
    private readonly IServiceProvider _serviceProvider;

    public SqlStringLocalizerFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public void SomeMethod()
    {
        using (var serviceScope = _serviceProvider
            .GetRequiredService<IServiceScopeFactory>().CreateScope())
        {
            var tenant = serviceScope.ServiceProvider.GetService<AppTenant>();

            // do something with tenant...
        }
    }
}

Upvotes: 2

Related Questions