在收集与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数据库。出于开发目的,我使用本地主机或我的机器ip作为主机地址(localhost
或192.168.2.101
)从DataGrip连接到此SQL Server。两种方法都可以正常工作,并且我可以在DataGrip中建立连接而没有问题。
我的问题是我无法从运行在localhost:80的CatalogController
中的docker容器内部连接到SQL Server。通常,当我调用localhost:80/api/catalog
时,应该将所有项目都从数据库中取出(请参阅开头的控制器),但是不知何故,我会收到此错误:
失败:Microsoft.EntityFrameworkCore.Database.Connection [20004]
在System.Data.SqlClient.SqlInternalConnectionTds..ctor中的
使用到服务器'localhost,1433'上的数据库'Test.Services.CatalogDb'的连接时发生错误。
System.Data.SqlClient.SqlException(0x80131904):建立与SQL Server的连接时发生与网络相关或特定于实例的错误。服务器未找到或无法访问。验证实例名称正确,并且已将SQL Server配置为允许远程连接。 (提供者:TCP提供程序,错误:40-无法打开与SQL Server的连接)(DbConnectionPoolIdentity身份,SqlConnectionString connectionOptions,SqlCredential凭据,对象providerInfo,String newPassword,SecureString newSecurePassword,布尔型redirectedUserInstance,SqlConnectionString userConnectionOptions,SessionData reconnectSessionData,Boolean
在Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync中的
/> 在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,仅布尔值OneCheckConnection,DbConnectionOptions userOptions,DbConnectionInternal&连接)
在System.Data.ProviderBase.DbConnectionPool.WaitForPendingOpen()
---从上一个引发异常的位置开始的堆栈跟踪---(布尔错误Expected,CancellationToken cancelToken) ClientConnectionId:00000000-0000-0000-0000-000000000000
我已经尝试使用服务器IP(本地主机,我的机器IP +码头工人检查中的IP),但是没有一个起作用。
Server=192.168.2.101,1433;Initial Catalog=Test.Services.CatalogDb;User Id=sa;Password=Pass@word
我乐意为您解决所有问题。 预先感谢。
答案 0 :(得分:1)
SQL Server实例不在本地主机上。在Web应用程序的上下文中,本地主机是Web应用程序运行所在的容器,而不是SQL Server所在的容器。
使用Docker Compose时,服务名称最终以主机名结尾,这意味着您可以简单地连接到sqldata,1433
。
添加服务名称而不是IP是可行的,但是每当我使用“ dotnet ef迁移添加xyz”和“ dotnet ef数据库更新”来迁移数据库时,都会出现错误。它说,找不到服务器或无法访问服务器。所以现在我可以连接了,但不能使用dotnet ef。
主机名仅在运行docker容器的VLAN内有效,该虚拟机与台式机所在的VLAN不相同。要访问SQL Server容器,您必须docker container exec
进入其中一个容器并从那里运行命令(将存在sqldata
主机名),或者您必须使用容器的IP地址,可以通过运行docker container ls
获得容器的IP地址(GUID),并然后运行docker inspect {container id}
。 IP地址将在生成的JSON的NetworkSettings
部分中。