3

I'm currently developing a system where dependent on what domain a request comes from different website settings need to be loaded (eg. default language id) which is then used in the rest of the application. These settings are stored in a class WebsiteSettings which are injected into the rest of the application when needed.

The first option I tried was registering a service to access the HttpContext by doing this in my ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
    //Register other services

    services.TryAddScoped<IHttpContextAccessor, HttpContextAccessor>();
    services.TryAddScoped<WebsiteSettingsFiller>();
    services.TryAddScoped(typeof(WebsiteSettings), s =>
    {
        var settingFiller = s.GetService<WebsiteSettingsFiller>();
        return settingFiller.Create();
    });
}

Next, in my WebsiteSettingsFiller service, I inject the IHttpContextAccessor and some other services that I need to load the site settings.

public class WebsiteSettingsFiller
{
    protected readonly IRepository Database;
    private readonly IHttpContextAccessor _accessor;
    private readonly StartupSitePropertyService _sitePropertyService;
    private IQueryable<Site> AllSites => Database.All<Site>();
    private IQueryable<SiteLanguage> AllSiteLanguages => Database.All<SiteLanguage>();

    public WebsiteSettingsFiller(IRepository db, StartupSitePropertyService siteProperties, IHttpContextAccessor accessor)
    {
        Database = db;
        _accessor = accessor;
        _sitePropertyService = siteProperties;
    }

    public WebsiteSettings Create()
    {
        var domain = _accessor.HttpContext.Request.Host.Host; //null exception on this line
#if DEBUG
        domain = "www.somewebsite.com";
#endif
        var config = GetConfigByDomain(domain);
        return config;
    }

    private WebsiteSettings GetConfigByDomain(string domain)
    {
        var site = AllSites.OrderByDescending(s => s.Created).FirstOrDefault(t => t.Host == domain);
        if (site == null) return null;
        var languages = AllSiteLanguages.Where(sl => sl.SiteId == site.Id).ToList();
        //get more variables 
        return new WebsiteSettings
        {
            /* Set variables */
        }
    }
}

Example injection of WebsiteSettings:

public class RouteService : BaseService
{
    private IDictionary<int, string> _routeLanguages = null;
    private readonly WebsiteRedisService _websiteRedisService;

    public RouteService(IRepository db,
        WebsiteSettings settings,
        WebsiteRedisService websiteRedisService)
        : base(db, settings)
    {
        _websiteRedisService = websiteRedisService;
    }

    public async Task<IDictionary<int, string>> RouteLanguagesAsync()
    {
        return _routeLanguages ??
               (_routeLanguages = await _websiteRedisService.SiteLanguagesToAsync(Settings.SiteId));
    }
}

Sadly, no matter what I try the HttpContext reference is always null. Does anyone have any idea what I can try to resolve this? Or am I just approaching this problem the wrong way? Any suggestions are greatly appreciated!

nbokmans
  • 5,492
  • 4
  • 35
  • 59
  • Try to register as singleton: `services.TryAddSingleton();` – Evk Apr 05 '17 at 09:35
  • Sadly that didn't fix the issue. Also I think it needs to be `TryAddScoped` since the `HttpContext` accessor changes per request, right? – nbokmans Apr 05 '17 at 09:39
  • In this [issue](https://github.com/aspnet/Hosting/issues/793) it is claimed that HttpContextAccessor should be registered as singleton, otherwise it won't work (because of internals of it's implementation). – Evk Apr 05 '17 at 09:40
  • You sure it's the context that's empty and not Request or host? Put a break point there and inspect it. Also, do you call this during a request (and not i.e. in startup class - where no httpcontext exists)? – Tseng Apr 05 '17 at 09:41
  • @Evk thanks, didn't know that. Changed to be singleton now. @Tseng yes it's the `HttpContext` that is null as show in this picture: http://i.imgur.com/3u4Mq9A.png - as for your second question: I think so? The error happens right away when I start my website, but this opens a new tab in my browser at `localhost:50001` which I'm assuming is what starts the request and triggers the breakpoint? – nbokmans Apr 05 '17 at 09:46
  • Where do you inject `WebsiteSettings`? – Henk Mollema Apr 05 '17 at 09:47
  • @nbokmans http://stackoverflow.com/questions/31243068/access-httpcontext-current – Dbl Apr 05 '17 at 09:51
  • @HenkMollema added example usage of `WebsiteSettings` injection – nbokmans Apr 05 '17 at 09:52
  • My worry is that because I'm using dependency injection to inject `WebsiteSettings` in other parts of the application, this is technically a different 'request' than the one coming from the browser, and therefore I can't use `IHttpContextAccessor` to read data such as the domain. – nbokmans Apr 05 '17 at 09:54
  • Looks like this issue doesn't have an easy fix. I have decided to take another approach for this thing which seems to work. Sadly, it means manually passing around the settings between services and controllers and inferring the settings from the `HttpContext`. Not the nice solution I was looking for, but it works. Thanks for your suggestions! – nbokmans Apr 06 '17 at 13:16

0 Answers0