无法从 NET Core 2.2 Web API 连接到 docker sql server
Posted
技术标签:
【中文标题】无法从 NET Core 2.2 Web API 连接到 docker sql server【英文标题】:Can't connect to docker sql server from NET Core 2.2 Web API 【发布时间】:2020-01-11 08:42:25 【问题描述】:在收集结合 docker 编写 .NET Core Web API 的知识时,我遇到了一个我无法解决的错误。我已经在互联网上进行了研究,但不知何故,提供的解决方案都不适合我。
我有一个名为 Catalog.API
的 Web 服务(类似于 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;
如您所见,我只有一种方法应该从外部数据库返回所有 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();
appsettings.json
看起来像这样:
"Logging":
"LogLevel":
"Default": "Warning"
,
"AllowedHosts": "*",
"ConnectionStrings":
"Default": "Server=localhost,1433;Initial Catalog=Test.Services.CatalogDb;User Id=sa;Password=Pass@word"
为了构建这个 Web 服务,我创建了一个从 docker-compose.yml
调用的 docker 文件:
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"]
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
如前所述,除了 Catalog.API Web 服务之外,我还在 docker 容器中运行 SQL Server 数据库。出于开发目的,我使用 localhost 或我的机器 ip 作为主机地址(localhost
或 192.168.2.101
)从 DataGrip 连接到此 SQL Server。两种方式都可以正常工作,我可以毫无问题地在 DataGrip 中建立连接。
我的问题是我无法从我的CatalogController
中的 docker 容器内部连接到 SQL Server,该容器在 localhost:80 上运行。通常,当我调用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、String newPassword、SecureString newSecurePassword、Boolean redirectedUserInstance、SqlConnectionString userConnectionOptions、SessionData reconnectSessionData、Boolean applyTransientFaultHandling、String 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 poolKey,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,布尔 allowCreate,布尔 onlyOneCheckConnection,DbConnectionOptions userOptions,DbConnectionInternal& 连接) 在 System.Data.ProviderBase.DbConnectionPool.WaitForPendingOpen() --- 从之前抛出异常的位置结束堆栈跟踪 ---
在 Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(布尔错误预期,CancellationToken cancelToken) 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
我愿意接受所有可以解决我问题的帮助。 提前致谢。
【问题讨论】:
两个docker服务需要在同一个network 问题在于您的连接字符串An error occurred using the connection to database 'Test.Services.CatalogDb' on server 'localhost,1433'
。添加:在服务器名称中,您添加了逗号。 Server=localhost:1433;
一切看起来都很好。
Docker 容器可以在同一个网络中通过服务名互相访问。您可以将 'localhost,1433' 更改为 'sqldata'
在深入研究 .net 代码之前,您可以从命令行连接吗?例如sqlcmd -S localhost,1433
?
@JinnaBalu:逗号没问题。它必须在那里而不是 :.
【参考方案1】:
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 不同。要访问 SQL Server 容器,您必须将docker container exec
放入其中一个容器中,然后从那里运行命令(sqldata
主机名将存在),或者您必须使用容器的 IP 地址,您可以通过运行 docker container ls
来获取容器 id (guid),然后运行 docker inspect container id
。 IP 地址将在生成的 JSON 的 NetworkSettings
部分中。
【讨论】:
感谢您的评论,我在研究此错误时也遇到了这个问题,但我无法解决这个问题。使用服务名称作为主机名有效。但是现在,每当我使用 dotnet ef 迁移添加 xyz 和 dotnet ef 数据库更新时,我都会收到一条错误消息,提示找不到数据库或无法访问。所以,现在连接是可能的,但我不能再使用 dotnet ef.. 也感谢您对 dotnet ef 的编辑。我确实按照您关于 docker inspect 的第二部分来获取容器的 IP 地址。再次检索 docker 容器的 IP 后,我将其粘贴到连接字符串中,它似乎可以工作。我以前已经这样做了,但不知何故,它没有用。无论如何,现在它正在工作。谢谢 好吧,IP 不是恒定的,所以你不应该真正坚持像appsettings.json
这样的东西。不过,您可以将连接字符串与dotnet ef
命令一起传递。
好点。将连接字符串与 dotnet ef 命令一起传递的最佳方式是什么?
对不起。我在想scaffold
命令。其他人不支持。这里的主要问题是这真的不是你应该处理的事情(一半进/一半出容器)。理想情况下,映像构建应输出 SQL 脚本或 DACPAC,然后您可以在容器启动时使用自定义入口点将其应用于 SQL Server 容器。网上有指南,但是这里太复杂了。以上是关于无法从 NET Core 2.2 Web API 连接到 docker sql server的主要内容,如果未能解决你的问题,请参考以下文章
本地 Javascript Fetch Post 请求失败,调用 ASP.NET Core 2.2 Web API。 CORS 已启用
如何将 AzureAD 和 AzureADBearer 添加到 asp.net core 2.2 web api
从 ASP.NET MVC 项目调用 .NET CORE 5 Web API 微服务时无法检索 BadRequest 错误
Azure 静态 Web 应用 Blazor WASM .Net Core API 和标识 - 无法从“_configuration”加载设置
如何测试返回 Ok(object) 的 ASP.NET Core 2.2 Web API GET IActionResult?