无法从 NET Core 2.2 Web API 连接到 docker sql server

Tja*_*tte 5 c# sql-server docker asp.net-core asp.net-core-webapi

在收集结合 docker 编写 .NET Core Web API 的知识时,我遇到了一个无法解决的错误。我已经在互联网上进行了研究,但不知何故,所提供的解决方案都不适合我。

我有一个名为的 Web 服务Catalog.API(类似于 Microsoft 的 eShopOnContainers 项目),其中有一个名为 的控制器CatalogController

这是来自控制器的代码:

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Catalog.API.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Catalog.API.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class CatalogController : ControllerBase
    {
        private readonly CatalogItemContext _context;

        public CatalogController(CatalogItemContext context)
        {
            _context = context;
        }

        public async Task<List<CatalogItem>> GetItemsAsync()
        {
            var items = await _context.CatalogItems.Where(model => model.Id < 10).ToListAsync();
            return items;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我只有一种方法应该从外部数据库返回 id 小于 10 的所有项目。

数据库添加在Startup.cs

namespace Catalog.API
{
    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.AddDbContext<CatalogItemContext>(builder =>
            {
                builder.UseSqlServer(Configuration.GetConnectionString("Default"));
            });

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

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // 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.UseMvc();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

看起来appsettings.json像这样:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "Default": "Server=localhost,1433;Initial Catalog=Test.Services.CatalogDb;User Id=sa;Password=Pass@word" 
  }
}
Run Code Online (Sandbox Code Playgroud)

为了构建此 Web 服务,我创建了一个从以下位置调用的 docker 文件docker-compose.yml

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80

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

COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj /src/csproj-files/

WORKDIR ./csproj-files
RUN dotnet restore

WORKDIR /src

COPY . .
WORKDIR /src/src/Services/Catalog/Catalog.API/
RUN dotnet publish -c Release -o /app

FROM build AS publish

FROM base as final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Catalog.API.dll"]
Run Code Online (Sandbox Code Playgroud)

看起来docker-compose.yml像这样:

version: '3.4'

services:

  sqldata:
    ports:
      - 1433:1433
    image: mcr.microsoft.com/mssql/server:2017-latest-ubuntu
    environment:
      - ACCEPT_EULA=Y
      - SA_PASSWORD=Pass@word

  catalog.api:
    ports:
      - 80:80
    build:
      context: .
      dockerfile: src/Services/Catalog/Catalog.API/Dockerfile
    depends_on:
      - sqldata
Run Code Online (Sandbox Code Playgroud)

如前所述,除了 Catalog.API Web 服务之外,我还在 Docker 容器内运行 SQL Server 数据库。localhost出于开发目的,我使用 localhost 或我的计算机 IP 作为主机地址(或)从 DataGrip 连接到此 SQL Server 192.168.2.101。两种方法都工作正常,我可以毫无问题地在 DataGrip 内部建立连接。

我的问题是我无法从在CatalogControllerlocalhost:80 上运行的 docker 容器内部连接到 SQL Server。通常,当我调用 时localhost:80/api/catalog,我应该从数据库中获取所有项目(请参阅开头的控制器),但不知何故,我收到此错误:

失败:Microsoft.EntityFrameworkCore.Database.Connection[20004]
使用服务器“localhost,1433”上的数据库“Test.Services.CatalogDb”的连接时发生错误。
System.Data.SqlClient.SqlException (0x80131904): 建立与 SQL Server 的连接时发生网络相关或特定于实例的错误。服务器未找到或无法访问。验证实例名称是否正确以及 SQL Server 是否配置为允许远程连接。(提供程序:TCP 提供程序,错误:40 - 无法打开与 SQL Server 的连接)

在System.Data.SqlClient.SqlInternalConnectionTds ..ctor(DbConnectionPoolIdentity标识,SqlConnectionString connectionOptions,SqlCredential凭据,对象providerInfo,字符串newPassword,SecureString newSecurePassword,布尔redirectedUserInstance,SqlConnectionString userConnectionOptions,SessionData reconnectSessionData,布尔applyTransientFaultHandling,字符串accessToken)在System.Data
。 SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions选项,DbConnectionPoolKey poolKey,对象poolGroupProviderInfo,DbConnectionPool池,DbConnection owningConnection,DbConnectionOptions userOptions)
在System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool池,DbConnection owningObject,DbConnectionOptions选项,DbConnectionPoolKey池键、DbConnectionOptions userOptions)
在System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject,DbConnectionOptions userOptions,DbConnectionInternal oldConnection)
在System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject,DbConnectionOptions userOptions,DbConnectionInternal oldConnection)
在System.Data.ProviderBase.DbConnectionPool.TryGetConnection (DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowedCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionPool.WaitForPendingOpen()
--- 从抛出异常的上一个位置开始的堆栈跟踪结束 ---

在 Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(布尔错误预期,CancellationToken取消令牌)ClientConnectionId:00000000-0000-0000-0000-000000000000

我已经尝试使用多个 ips(本地主机、我的机器 ip + docker 检查的 ip),但没有一个有效。

Server=192.168.2.101,1433;Initial Catalog=Test.Services.CatalogDb;User Id=sa;Password=Pass@word
Run Code Online (Sandbox Code Playgroud)

我愿意接受任何可以解决我的问题的帮助。提前致谢。

Chr*_*att 7

SQL Server 实例不在本地主机上。在 Web 应用程序的上下文中,localhost 是运行 Web 应用程序的容器,它与 SQL Server 所在的容器不同。

使用 Docker Compose 时,服务名称最终作为主机名,这意味着您可以简单地连接到sqldata,1433.

添加服务名称而不是 IP 是有效的,但是每当我使用“dotnet ef migrations add xyz”和“dotnet ef database update”迁移数据库时,我都会收到错误。它说,服务器未找到或无法访问。所以现在我可以连接,但无法使用 dotnet ef。

主机名仅在运行 docker 容器的 VLAN 内有效,该 VLAN 与桌面计算机所在的 VLAN 不同。要访问 SQL Server 容器,您必须docker container exec进入其中一个容器并从那里运行命令 (主机名将存在的位置sqldata)或者您必须使用容器的 IP 地址,您可以通过运行docker container ls获取容器 id (guid) 然后运行 ​​来获取该 IP 地址docker inspect {container id}。IP 地址将位于NetworkSettings生成的 JSON 部分中。