locked
How does aspnetcore use DbContext in other threads? RRS feed

  • Question

  • User1849955458 posted
     public SerialPortStartController(FireControlContext context)
                {
                    _context = context;
                }
                public void Index()
                {
                    Task.Run(() =>
                    {
                        Start();
                    });
                }
                public void Start()
                {
                    //I need to use _context here 
                    //Reinstantiation is too cumbersome. I need to use ConnectionStrings in appsettings.json
                    string connection = @"Data Source=LP-HOME\SQLEXPRESS;Initial Catalog=FireControl;Integrated Security=True";
                    DbContextOptions dbContextOption = new DbContextOptions();
                    DbContextOptionsBuilder dbContextOptionBuilder = new DbContextOptionsBuilder(dbContextOption);
    
                    using (var ctx = new FireControlContext(dbContextOptionBuilder.UseSqlServer(connection).Options))
                    {
                    }
                }

    Thursday, June 20, 2019 9:03 AM

All replies

  • User753101303 posted

    Hi,

    The {;} icon allows to copy/paste code in a more legible way. You already have an instance level variable. Are you really trying to interact xwith the serial port from a web server (keep in mind that once deployed this code runs on your server, not on the client PC).

    Thursday, June 20, 2019 9:12 AM
  • User1120430333 posted

    Maybe, the link will help you.

    https://hackernoon.com/asp-net-core-how-to-use-dependency-injection-in-entity-framework-core-4388fc5c148b

    Thursday, June 20, 2019 10:49 AM
  • User-474980206 posted

    while dbcontext is thread safe, it does not support parallel operations. only one request at a time. in practice this means one dbcontext per thread, and the thread must use awaits to prevent concurrent operations.

    this means you can not pass _context Start unless you use an await. if you want fire and forget, then you need to register a dbcontext factory that return a new dbcontext (which you code will need to Dispose() to avoid memory leaks.

    Thursday, June 20, 2019 4:18 PM
  • User765422875 posted

    If you are asking whether or not the DbContext is threadsafe - it is not. More than one thread operating on a single Entity Framework context is not thread safe.

    However, a separate instance of context for each thread is thread-safe. as long as each thread of execution has its own instance of the context.

    https://docs.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext

    From the Docs:

    Avoiding DbContext threading issues

    Entity Framework Core does not support multiple parallel operations being run on the same DbContext instance. This includes both parallel execution of async queries and any explicit concurrent use from multiple threads. Therefore, always await async calls immediately, or use separate DbContext instances for operations that execute in parallel.

    When EF Core detects an attempt to use a DbContext instance concurrently, you'll see an InvalidOperationException with a message like this:

    A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext, however instance members are not guaranteed to be thread safe.

    When concurrent access goes undetected, it can result in undefined behavior, application crashes and data corruption.

    Thursday, June 20, 2019 5:32 PM
  • User1849955458 posted

    How to create a new dbcontext factory  using ConnectionStrings in appsettings.json ?

    Friday, June 21, 2019 1:03 AM
  • User1120430333 posted

    How to create a new dbcontext factory  using ConnectionStrings in appsettings.json ?

    You can pass the connectionstring in in a class using IOption and pass it into the Dbcontext. You would get the connectionstring set as a service in the Startup.cs

    https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-strings

    //Configuration
                services.Configure<ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));

    https://andrewlock.net/how-to-use-the-ioptions-pattern-for-configuration-in-asp-net-core-rc2/

    You would have to change the Dbcontext to accept the IOption on the constructor

    I use it in the manner below.

    using System.Collections.Generic;
    using System.Linq;
    using System.Transactions;
    using DAL.Models.DB;
    using Entities;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.Options;
    
    namespace DAL
    {
        public class DaoProject :IDaoProject
        {
            private readonly IOptions<ConnectionStrings> _options;
            
            public DaoProject(IOptions<ConnectionStrings> options)
            {
                _options = options;
            }
    
            public DtoProject GetProjectById(int id)
            {
                var dto = new DtoProject();
    
                using (var context = new ProjectManagementContext(_options))
                {
                    var project = (context.Projects.Where(a => a.ProjectId == id)).SingleOrDefault();
    
                    if (project == null) return dto;
                    dto.ProjectId = project.ProjectId;
                    dto.ClientName = project.ClientName;
                    dto.ProjectName = project.ProjectName;
                    dto.Technology = project.Technology;
                    dto.ProjectType = project.ProjectType;
                    dto.UserId = project.UserId;
                    dto.StartDate = project.StartDate;
                    dto.EndDate = project.EndDate;
                    dto.Cost = project.Cost;
                }
    
                return dto;
            }
    
            public List<DtoProject> GetProjectsByUserId(string userid)
            {
                var dtos = new List<DtoProject>();
    
                using (var context = new ProjectManagementContext(_options))
                {
                    
                    dtos = (from a in context.Projects.Where(a => a.UserId.Contains(userid))
                        select new DtoProject
                        {
                            ProjectId = a.ProjectId,
                            ClientName = a.ClientName,
                            ProjectName = a.ProjectName,
                            Technology = a.Technology,
                            ProjectType = a.ProjectType,
                            UserId = a.UserId,
                            StartDate = a.StartDate,
                            EndDate = a.EndDate,
                            Cost = a.Cost
                        }).ToList();
                }
    
                return dtos;
            }
    
            public void CreateProject(DtoProject dto)
            {
                using (var context = new ProjectManagementContext(_options))
                {
                    var project = new Projects
                    {
                        ClientName = dto.ClientName,
                        ProjectName = dto.ProjectName,
                        Technology = dto.Technology,
                        ProjectType = dto.ProjectType,
                        UserId = dto.UserId,
                        StartDate = dto.StartDate,
                        EndDate = dto.EndDate,
                        Cost = dto.Cost
                    };
    
                    context.Projects.Add(project);
                    context.SaveChanges();
               }
            }
    
            public void UpdateProject(DtoProject dto)
            {
                var project = new Projects();
                
                using (var context = new ProjectManagementContext(_options))
                {
                   project = (context.Projects.Where(a => a.ProjectId == dto.ProjectId)).SingleOrDefault();
                }
    
                if (project != null)
                {
                    project.ClientName = dto.ClientName;
                    project.ProjectName = dto.ProjectName;
                    project.Technology = dto.Technology;
                    project.ProjectType = dto.ProjectType;
                    project.UserId = dto.UserId;
                    project.StartDate = dto.StartDate;
                    project.EndDate = dto.EndDate;
                    project.Cost = dto.Cost;
                }
    
                using (var dbcontext = new ProjectManagementContext(_options))
                {
                    if (project == null) return;
                    dbcontext.Entry(project).State = EntityState.Modified;
                    dbcontext.SaveChanges();
                }
            }
    
            public void DeleteProject(int id)
            {
                Projects project;
    
                using (var context = new ProjectManagementContext(_options))
                {
                   project = (context.Projects.Where(a => a.ProjectId == id)).SingleOrDefault();
                }
    
                if (project == null) return;
    
                using (var newContext = new ProjectManagementContext(_options))
                {
                   
                    var tasks = new DaoTask(_options).GetTasksByProjectId(project.ProjectId);
                    using (TransactionScope scope = new TransactionScope())
                    {
                        foreach (var task in tasks)
                        {
                            new DaoTask(_options).DeleteTask(task.TaskId);
                        }
    
                        newContext.Entry(project).State = EntityState.Deleted;
                        newContext.SaveChanges();
    
                        scope.Complete();
                    }
                }
            }
        }
    }
    

    Friday, June 21, 2019 3:35 AM
  • User765422875 posted

    Setting Up Entity Framework Core Database With Factory

    https://www.c-sharpcorner.com/article/simulating-code-first-with-entity-framework-core/

    Friday, June 21, 2019 11:55 AM