无法从NET Core 2.2 Web API连接到docker sql服务器

时间:2019-09-09 14:49:15

标签: c# sql-server docker asp.net-core asp.net-core-webapi

在收集与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作为主机地址(localhost192.168.2.101)从DataGrip连接到此SQL Server。两种方法都可以正常工作,并且我可以在DataGrip中建立连接而没有问题。

我的问题是我无法从运行在localhost:80的CatalogController中的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,String newPassword,SecureString newSecurePassword,布尔型redirectedUserInstance,SqlConnectionString userConnectionOptions,SessionData reconnectSessionData,Boolean
/>   在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()
  ---从上一个引发异常的位置开始的堆栈跟踪---

     在Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync中的

(布尔错误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

我乐意为您解决所有问题。 预先感谢。

1 个答案:

答案 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部分中。