0

I have a class "ConnectorManagement" in which I need to use both SignalR services as well as querying a db table using EF CORE.

I cant work out how to load both dbcontext and hubcontext into the same class using a constructor and dependancy injection. The current result is visual studio fails to load the project when run in debug. Tried researching this but not understanding what needs to be done.

Current code below:

 namespace myNamespace.Controller
 {
  public class ConnectorManagement : IHostedService
  {
    private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(Logger));

    private readonly IHubContext<MessageHub> _hubContext;
    public readonly ApplicationDbContext _context;

    public ConnectorManagement(IHubContext<MessageHub> hubContext, ApplicationDbContext context)
    {
        _hubContext = hubContext;
        _context = context;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        log.Info("Initial Test");

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        throw new NotImplementedException();
    }

dbcontext class:

 namespace myNamespace.Data
 {
  public class ApplicationDbContext : IdentityDbContext
  {
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
    public DbSet<myProject.Models.ConnectorInbound> ConnectorInbound { get; set; }
    public DbSet<myProject.Models.ConnectorOutbound> ConnectorOutbound { get; set; }
    public DbSet<myProject.Models.SystemMapping> SystemMapping { get; set; }
 }
}

startup class:

namespace myProjectNamespace
{
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>()
            .AddDefaultUI(UIFramework.Bootstrap4)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        // Start up the TcpServerTcpServer engine
        services.AddHostedService<ConnectorManagement>();

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        services.AddSignalR();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseCookiePolicy();

        app.UseAuthentication();

        app.UseSignalR(routes =>
        {
            routes.MapHub<MessageHub>("/messageHub");
        });

        loggerFactory.AddLog4Net();
        app.UseMvc();
    }
 }
}
10
  • What error(s) are you getting? And define "INCORRECT" code, your code looks correct to us given the information you have posted. Commented Aug 27, 2019 at 19:58
  • Hi, I dont get any errors as such, the project attempts to load then automatically stops again. If I remove the reference to dbcontext from the constructor then everything works fine. I'm wandering whether i'm dealing with an anit-pattern violation or something. Commented Aug 27, 2019 at 20:08
  • This is all I can find in the debug console: Exception thrown: 'System.InvalidOperationException' in System.Private.CoreLib.dll The thread 0x6c84 has exited with code 0 (0x0). The program '[15904] iisexpress.exe' has exited with code 0 (0x0). Commented Aug 27, 2019 at 20:13
  • 1
    post the relevant startup.cs code, something might be amiss there Commented Aug 27, 2019 at 20:17
  • 1
    Yep i have a migration already added, and just tried update-databse but it says its already up to date. I then dropped the database and started it up, but still fails. Am wandering whether importing dbcontext into this class is not importing correctly, perhaps not pulling the underlying parameters needed i.e. options which include the details about the connection string, the parts which apparently DI should be handling automatically. Commented Aug 27, 2019 at 21:14

1 Answer 1

2

I wasn't paying attention to the fact that you're injecting this into a hosted service. Hosted services are singletons and both the hub context and database context are scoped services. You need to inject IServiceProvider instead and then create a scope. This will need to be done for every usage; you cannot persist it on an ivar, for example. You can only use it within the using statement.

using (var scope = _serviceProvider.CreateScope())
{
    var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
    // Do something
}
Sign up to request clarification or add additional context in comments.

2 Comments

Hi Chris, Using your above snippet I've got as far as being able to query from the dbcontext without errors now so can now move forward. Would I be right in saying that the context scope would only be valid for the lifetime of any code written within the using statement? I would be looking to use the same solution for bringing in the hubcontext for SignalR, but this hubcontext will need to be passed on through child tasks that are initiated from this class, thanks
Yes. The scope only exists within the using, and any scoped services go away when it does. However, that doesn't preclude you from calling child tasks, as long as those are called within the using.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.