【问题标题】:EF Core SQL Database connection error in a Docker container applicationDocker 容器应用程序中的 EF Core SQL 数据库连接错误
【发布时间】:2021-12-17 22:49:18
【问题描述】:

我有一个简单的 Entity Framework Core (5.0.11) 应用程序,它与 SQL Server 的 localhost 实例连接。从 IDE 运行时它运行良好,但从 Docker 容器运行时出现 SQL 连接错误。

我没有为 SQL 服务器使用独立容器,而是连接到我机器上的本地主机。

我使用的连接字符串如下

  "ConnectionStrings": {
    "DefaultConnectionString": "Server=localhost;Database=LOCALDatabase;User id=userId;password=password"
  }

以下是docker容器错误

"EventId":20004,"LogLevel":"Error","Category":"Microsoft.EntityFrameworkCore.Database.Connection","Message":"An 使用与数据库的连接发生错误 \u0027LOCALDatabase\u0027 在服务器上 \u0027localhost\u0027.","State":{"Message":"使用时发生错误 与服务器上的数据库 \u0027LOCALDatabase\u0027 的连接 \u0027localhost\u0027.","database":"LOCALDatabase","server":"localhost","{OriginalFormat}":"An 使用与数据库 \u0027{database}\u0027 的连接时发生错误 在服务器 \u0027{服务器}\u0027 上。”

我已经使用虚拟数据(不是来自数据库)测试了容器化应用程序,它工作正常,因此端口映射或容器化应用程序的可访问性没有问题。

Docker构建和运行命令如下

docker build -t test-api:v1 .

docker run -it -p 7277:80 --name testapi test-api:v1

更新

以下是代码文件

//Data Access Layer Project
namespace DAL.Repositories
{
    public interface ITable1Repository
    {
        Task<IEnumerable<Dbtable1>> GetAsync();
    }
}

public class Table1Repository : ITable1Repository
{
    private readonly LOCALDbContext _dbContext;
    public Table1Repository(LOCALDbContext dbContext)
    {
        _dbContext = dbContext;
    }
    public async Task<IEnumerable<Dbtable1>> GetAsync()
    {
        return await _dbContext.Dbtable1s.ToListAsync();
    }
}

//Database entity
namespace DAL.Entities
{
    [Table("DBTable1")]
    public partial class Dbtable1
    {
        [Key]
        public int Column1 { get; set; }
        [StringLength(50)]
        public string Column2 { get; set; }
        [StringLength(50)]
        public string Column3 { get; set; }
    }
}

//DbContext
public partial class LOCALDbContext : DbContext
{
    public LOCALDbContext()
    {
    }

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

    public virtual DbSet<Dbtable1> Dbtable1s { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasAnnotation("Relational:Collation", "Latin1_General_CI_AS");

        modelBuilder.Entity<Dbtable1>(entity =>
        {
            entity.Property(e => e.Column1).ValueGeneratedNever();
        });

        OnModelCreatingPartial(modelBuilder);
    }

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}


//API Project
//Controller
namespace API.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class TestController : ControllerBase
    {
        private readonly ITable1Repository _table1Repository;
        public TestController(ITable1Repository table1Repository)
        {
            _table1Repository = table1Repository;
        }

        // GET: <TestController>
        [HttpGet]
        public async Task<IEnumerable<Dbtable1>> Get()
        {
            return await _table1Repository.GetAsync();
        }
    }
}

//Program.cs
using DAL.Data;
using DAL.Repositories;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new() { Title = "API", Version = "v1" });
});

var connectionString = builder.Configuration.GetConnectionString("DefaultConnectionString");
builder.Services.AddDbContext<LOCALDbContext>(options => options.UseSqlServer(connectionString));

builder.Services.AddScoped<ITable1Repository, Table1Repository>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "API v1"));
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();


//appsettings.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "DefaultConnectionString": "Server=localhost;Database=LOCALDatabase;User id=userid;password=password"
  }
}

//appsettings.Docker.json
{
  "ConnectionStrings": {
    "DefaultConnectionString": "Server=host.docker.internal;Database=LOCALDatabase;User id=userid;password=password"
  }
}

//DockerFile
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src

COPY *.sln ./
COPY ./src/API/API.csproj ./src/API/
COPY ./src/DAL/DAL.csproj ./src/DAL/

RUN dotnet restore
COPY . .

RUN dotnet publish -c Release -o out

FROM base
WORKDIR /app

COPY --from=build /src/out .
ENTRYPOINT ["dotnet", "API.dll"]

docker 构建和运行命令 docker build -t test-api:v1 。搬运工运行 -it -p 7277:80 -e "ASPNETCORE_ENVIRONMENT=Docker" --name testapi test-api:v1

我已经使用一些本地数据(非 Db)测试了容器化应用程序,它工作正常,但 SQL 连接导致了问题。

这是我的解决方案文件夹结构

以下是数据库表脚本

USE [LOCALDatabase]
GO
/****** Object:  Table [dbo].[DBTable1]    Script Date: 04/11/2021 13:50:33 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[DBTable1](
    [Column1] [int] NOT NULL,
    [Column2] [nvarchar](50) NULL,
    [Column3] [nvarchar](50) NULL,
 CONSTRAINT [PK_DBTable1] PRIMARY KEY CLUSTERED 
(
    [Column1] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
INSERT [dbo].[DBTable1] ([Column1], [Column2], [Column3]) VALUES (1, N'Richard', N'King')
INSERT [dbo].[DBTable1] ([Column1], [Column2], [Column3]) VALUES (2, N'Stuart', N'Philip')

【问题讨论】:

  • 您能提供如何运行 docker 容器吗? docker-compose 文件或启动容器的 docker cli 命令
  • 我正在使用 docker cli 命令。我已经用构建和运行命令更新了我的问题。

标签: sql-server docker entity-framework-core


【解决方案1】:

问题在于,当您在连接字符串中指定 localhost 时,它会解析为容器而不是外部主机,以解决使用 host.docker.internal 而不是 localhost 和 127.0.0.1 的问题

此外,为了保持您现有的从 docker 外部运行 API 的方法可操作,您可以创建一个新的应用设置文件:

appSettings.Docker.json

"ConnectionStrings": {
    "DefaultConnectionString": "Server=host.docker.internal;Database=LOCALDatabase;User id=userId;password=password"
  }

并将您的 docker cli 更改为:

docker build -t test-api:v1 .

docker run -it -p 7277:80 -e "ASPNETCORE_ENVIRONMENT=Docker" --name testapi test-api:v1

来源:

【讨论】:

  • 仍然得到同样的错误@milo "EventId":20004,"LogLevel":"Error","Category":"Microsoft.EntityFrameworkCore.Database.Connection","Message":"一个错误使用连接到服务器 \u0027host.docker.internal\u0027 上的数据库 \u0027LOCALDatabase\u0027 时发生。","State":{"Message":"在服务器 \u0027host 上连接到数据库 \u0027LOCALDatabase\u0027 时发生错误.docker.internal\u0027.","database":"LOCALDatabase","server":"host.docker.internal","{OriginalFormat}":"使用数据库连接发生错误\u0027{database}\服务器上的 u0027 \u0027{server}\u0027。"
  • 我已经添加了 appsettings.Docker.json 文件,其中包含建议的“Server=host.docker.internal”,并按照建议在我的 docker run 命令中包含了环境标记,但看不到任何错误差异?
  • 我试过了,它对我有用,你能提供一个Minimal, Complete, and Verifiable example 吗?
  • 我已经用所有代码和 Docker 文件 @milo 更新了我的原始问题。
【解决方案2】:

我通过在连接字符串中提供主机的 IP 地址(ipv4 地址)和端口号使其工作。解决方案在this 线程中进行了解释。为了更清晰,我添加了屏幕截图。

"DefaultConnectionString": "Server=192.168.*.*,1433;Database=LOCALDatabase;User id=mydbuserid;password=mydbpassword"

使用 IP 和端口号进行操作的步骤

  1. 从 Window + R,打开 compmgmt.msc
  2. 检查是否启用了 MSSQLSERVER 协议的 TCP/IP。
  3. 1433 是 SQL Server 使用的默认端口。双击 TCP/IP 并转到 IP 地址选项卡并检查 IPAAll 部分下的 TCP 端口是否存在 1433 端口。
  4. 从服务部分重新启动 SQL Server 服务
  5. 按照these 说明允许通过Windows 防火墙访问端口1433

【讨论】:

    猜你喜欢
    • 2016-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 2015-05-29
    • 2016-11-29
    • 2019-07-19
    • 1970-01-01
    相关资源
    最近更新 更多