【发布时间】: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:逗号没问题。它必须在那里而不是 :.
标签: c# sql-server docker asp.net-core asp.net-core-webapi