【问题标题】:>VS 2017 and ASP.Net Core 2.1 and Entity framework - I don't wan't to hard code the connection string>VS 2017 和 ASP.Net Core 2.1 和实体框架 - 我不想硬编码连接字符串
【发布时间】:2019-05-19 12:49:55
【问题描述】:

我有一个使用实体框架的 ASP.Net Core 2.1,前端有 Angular 5,后端有 Web Api 控制器。

它可以正常工作,但现在我想更改它,以便数据库连接字符串不是硬编码的。

我正在关注这个: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-strings

但它不起作用。我明白了:

处理请求时发生未处理的异常。 InvalidOperationException:没有为此 DbContext 配置数据库提供程序。可以通过覆盖 DbContext.OnConfiguring 方法或在应用程序服务提供者上使用 AddDbContext 来配置提供者。如果使用了 AddDbContext,那么还要确保您的 DbContext 类型在其构造函数中接受 DbContextOptions 对象并将其传递给 DbContext 的基本构造函数。

'((Microsoft.EntityFrameworkCore.Internal.InternalDbSet)db.TblEmployee).Local' 引发了“System.InvalidOperationException”类型的异常

逻辑路径为:

  1. 出现主页。然后我点击“当前员工”菜单项。
  2. 它进入 Angular 服务并执行 getEmployees() 方法,该方法执行 web api 方法。
  3. 它进入 Web api 控制器并执行 -GetAllEmployee() 方法,该方法执行员工数据访问层方法。
  4. 它转到员工数据访问层类(我在这里实例化了 dbContext)。我在 return 语句上有一个断点。如果我将鼠标悬停在 return 语句上,我会看到错误。当然,当我继续时,应用程序会失败。

我的数据库上下文类是:

namespace Angular5NetcoreEF.Models
{
public partial class DBAngular5NetcoreEFContext : DbContext
{
    public DBAngular5NetcoreEFContext()
    {
    }

    public DBAngular5NetcoreEFContext(DbContextOptions<DBAngular5NetcoreEFContext> options)
        : base(options)
    {
    }

    public virtual DbSet<TblCities> TblCities { get; set; }
    public virtual DbSet<TblEmployee> TblEmployee { get; set; }

    //protected override void OnConfiguring(DbContextOptionsBuilder 
    optionsBuilder)
    //{
    //    if (!optionsBuilder.IsConfigured)
    //    {
    //        optionsBuilder.UseSqlServer("Server=  
    //        (localdb)\\mssqllocaldb;Database=DBAngular5NetcoreEF;
    //        Trusted_Connection=True; MultipleActiveResultSets=true");
    //    }
    //} 

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<TblCities>(entity =>
        {
            entity.HasKey(e => e.CityId);

            entity.ToTable("tblCities");

            entity.Property(e => e.CityId).HasColumnName("CityID");

            entity.Property(e => e.CityName)
                  .IsRequired()
                  .HasMaxLength(20)
                  .IsUnicode(false);
        });

        modelBuilder.Entity<TblEmployee>(entity =>
        {
            entity.HasKey(e => e.EmployeeId);

            entity.ToTable("tblEmployee");

            entity.Property(e => e.EmployeeId).HasColumnName("EmployeeID");

            entity.Property(e => e.City)
                  .IsRequired()
                  .HasMaxLength(20)
                  .IsUnicode(false);

            entity.Property(e => e.Department)
                  .IsRequired()
                  .HasMaxLength(20)
                  .IsUnicode(false);

            entity.Property(e => e.Gender)
                  .IsRequired()
                  .HasMaxLength(6)
                  .IsUnicode(false);

            entity.Property(e => e.Name)
                  .IsRequired()
                  .HasMaxLength(20)
                  .IsUnicode(false);
        });
      } 
   }
}

因此,按照说明,我在上面进行硬编码的地方注释掉了 OnConfiguring 方法。

我添加到 appsettings.json 文件中:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
   }
  },
  "ConnectionStrings": {
    "DBAngular5NetcoreEFDatabase": "Server=(localdb)\\mssqllocaldb;Database=DBAngular5NetcoreEF;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "AllowedHosts": "*"
}

我添加到我的 Startup.cs - ConfigureServices 方法:

using Angular5NetcoreEF.Models;
using Microsoft.EntityFrameworkCore;

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    // In production, the Angular files will be served from this directory.
    services.AddSpaStaticFiles(configuration =>
    {
        configuration.RootPath = "ClientApp/dist";
    });

    // I added this.
    services.AddDbContext<DBAngular5NetcoreEFContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DBAngular5NetcoreEFDatabase")));
}

【问题讨论】:

  • 那么,更改代码后是否会引发异常?我看不出你的代码有什么问题。
  • 是的...在更改代码之前工作正常。我同意..但是伙计,这总是一些事情..lol
  • 您是否安装了Microsoft.EntityFrameworkCore.SqlServer NuGet 包?
  • @GabrielLuci Microsoft.EntityFrameworkCore.SqlServer 默认使用 Microsoft.AspNetCore.App 元包添加到 ASP.NET Core 2.1 项目中
  • 什么时候遇到这个错误?您如何在代码中使用 dbContext?可能的原因请参考this link

标签: asp.net-core entity-framework-core


【解决方案1】:

您不应在EmplyeeDataAccessLayer 内实例化DBAngular5NetcoreEFContext 的新实例。相反,您应该注入它。

您还需要在DI容器中注册EmployeeDataAccessLayer并注入到EmployeeController

基本上,您让 DI 容器为您解决依赖关系。

public class Startup
{
    ...
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<DBAngular5NetcoreEFContext>
            (options => options.UseSqlServer(Configuration.GetConnectionString("DBAngular5NetcoreEFDatabase")));

        services.AddScoped<EmployeeDataAccessLayer>();
        ...        
    }
    ...
}

public class EmployeeController : Controller
{
    private readonly EmployeeDataAccessLayer objemployee;

    public EmployeeController(EmployeeDataAccessLayer employeeDataAccessLayer)
    {
        objemployee = employeeDataAccessLayer;
    }
}

public class EmployeeDataAccessLayer
{
    private readonly DBAngular5NetcoreEFContext _db;

    public EmployeeDataAccessLayer(DBAngular5NetcoreEFContext db)
    {
        _db = db;
    }
    ...
}

另一个想法是使用interface 而不是具体的实现。当你实施单元测试时,它会让你的生活更轻松。

【讨论】:

  • 我刚刚做了..但现在在同一行,我得到:处理请求时发生未处理的异常。 NullReferenceException:对象引用未设置为对象的实例。它指的是:return _db.TblEmployee.ToList();
【解决方案2】:

您面临的问题是,您没有使用依赖注入模式。 首先,您需要通过构造函数的依赖注入从服务中插入 DbContext

public class EmployeeDataAccessLayer 
{
   private DBAngular5NetcoreEFContext _db;

   public EmployeeDataAccessLayer(DBAngular5NetcoreEFContext db)
   {
      _db = db;
   }
}

其次,所有引用也应该被注入,所以在应用程序的每一层,对于像你的 EmployeeDataAccessLayer 这样的每个类,你应该 第一:使用Startup.cs -&gt; ConfigureServices()注册依赖注入:即services.AddScoped&lt;EmployeeDataAccessLayer&gt;();, 然后像上面的例子一样将它注入到Controller的构造函数中。

您可以从 Doc 中了解依赖注入和示例范围(Scoped、Transient、Singleton...)

为了安全起见,在您当前的场景中检查何时有未配置的上下文,您可以执行以下操作:

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
             throw new Exception("Context not configured");
        }
    }

以及“临时禁用”空构造函数

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多