我已经在Docker上部署了我的ASP.NET Core Web API.我的应用程序也在Docker容器中与SQL Server交互.

这是我的docker-compose.yml%文件:

 version: '3'
 services:
     db:
         image: mcr.microsoft.com/mssql/server
         container_name: db
         ports:
             - 1533:1433
         environment:
             - TZ=Asia/Tehran
             - ACCEPT_EULA=Y
             - MSSQL_SA_PASSWORD=******
         user: root
         volumes:
             - ./mssql:/var/opt/mssql/data
    kava-service:
        image: service:1.0.0
        container_name: service
        expose:
            - 9001
        ports:
            - 9001:9001
        depends_on:
            - db
        environment:
            - ASPNETCORE__ENVIRONMENT=Production
            - TZ=Asia/Tehran
            - AUTO__MIGRATE=true
            - ConnectionStrings__BusinessDomainConnectionString=Server=db;Initial Catalog=Kava.BusinessDomain;User ID=sa;pwd=****;MultipleActiveResultSets=true;
            - ConnectionStrings__RecordsConnectionString=Server=db;Initial Catalog=Kava.Records;User Id=sa;pwd=****;MultipleActiveResultSets=true;

当我运行Docker容器(使用docker-compose)时,它工作得很好.但是如果我重新启动这个容器,它不工作,应用程序退出并显示以下消息:

Login failed for user 'sa'. Reason: Failed to open the explicitly specified database 'Kava.BusinessDomain' [CLIENT: 172.18.0.4] kava-service
Unhandled exception. Microsoft.Data.SqlClient.SqlException (0x80131904): Database 'Kava.BusinessDomain' already exists. Choose a different database name.

当我删除这个数据库一切工作,但我不想删除它.

在开发阶段(我指的是Visual Studio)一切都很好,但在生产阶段(Docker),迁移并不能像预期的那样工作.

以下是我的迁移命令:

 BusinessDomainContext businessDomainContext = serviceScope.ServiceProvider.GetRequiredService<IBusinessDomainDatabaseFactory>().Get() as BusinessDomainContext;
 await businessDomainContext.Database.MigrateAsync();

推荐答案

您的迁移过程可能正在try 创建已存在的数据库.您的ASP.NET Core应用程序应该判断数据库是否存在,并只应用必要的迁移,而不是每次都try 创建新数据库(使用"resolving a service at app start up").

using (var scope = app.ApplicationServices.CreateScope())
{
    var services = scope.ServiceProvider;
    var context = services.GetRequiredService<BusinessDomainContext>();

    // Check if the database exists and apply migrations if necessary
    if (context.Database.CanConnect())
    {
        // context.Database.GetPendingMigrations().Any() is another option.
        if (!context.Database.GetAppliedMigrations().SequenceEqual(context.Database.GetMigrations()))
        {
            await context.Database.MigrateAsync();
        }
    }
    else
    {
        // Logic to handle the scenario where the database does not exist
        // That might include creating the database, if that is your intention
    }
}

Login failed for user 'sa'错误可能是当您的应用程序try 连接时,SQL Server容器未完全准备好的症状.您可以使用connection string测试为数据库连接实现重试策略,如"Implement resilient Entity Framework Core SQL connections"所示.

services.AddDbContext<BusinessDomainContext>(options =>
    options.UseSqlServer(
        Configuration.GetConnectionString("BusinessDomainConnectionString"),
        sqlServerOptionsAction: sqlOptions =>
        {
            sqlOptions.EnableRetryOnFailure(
                maxRetryCount: 5, 
                maxRetryDelay: TimeSpan.FromSeconds(10),
                errorNumbersToAdd: null);
        }));

这将设置重试策略,其中应用程序将try 重新连接数据库最多五次,两次重试之间的延迟为10秒.


此外,出于调试目的,请try 增强这些操作的日志(log)记录. 并使用docker-compose up -d; docker-compose logs -f在后台运行服务,然后跟踪容器的任何输出.

在应用程序内部,可以使用日志(log)框架记录消息.在ASP.NET Core应用程序中,可以使用built-in logging framework.您可以在Program.csStartup.cs文件中配置它以将消息记录到控制台,然后由Docker拾取.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        })
        .ConfigureLogging(logging =>
        {
            logging.ClearProviders();
            logging.AddConsole();
        });

您可以将ASPNETCORE_ENVIRONMENT environment variable设置为Development,以从ASP.NET Core应用程序获取更详细的日志(log).

That can be done, in your docker-compose.yml file, with a command field to your service to override the default command that your Docker image runs when a container is started.
That can be useful for adding flags or arguments to enable more verbose logging.

例如,如果您的应用程序接受--verbose标志以启用更详细的日志(log),则可以添加如下command字段:

services:
  service:
    image: service:1.0.0
    command: ["./your-app", "--verbose"]
    # rest of your service configuration

在ASP.NET Core应用程序的上下文中,您可以使用环境变量控制日志(log)级别.例如,您可以从set Logging__LogLevel__DefaultDebugInformation来获取更详细的日志(log):

services:
  service:
    image: service:1.0.0
    environment:
      - ASPNETCORE__ENVIRONMENT=Development
      - AzureFunctionsJobHost__logging__logLevel__default=Debug
    # rest of your service configuration

这会将应用程序中所有类别的日志(log)的日志(log)级别设置为Debug.您还可以使用environment variables like Logging__LogLevel__Microsoft=Information设置特定类别的日志(log)级别.

Csharp相关问答推荐

禁用AutoSuggestBox项目更改时的动画?

EF Core 8—应用客户端投影后无法转换集操作

如何在NServicebus中配置学习传输的文件夹(NService bus 8)

在多对多关系上不删除实体

当通过Google的Gmail Api发送邮件时,签名会产生dkim = neutral(正文散列未验证)'

查找表中的模式

无法创建';';类型的';DbContext';.异常';无法解析类型';Microsoft.EntityFrameworkCore.DbContextOptions`1[Comm的服务

最新的Mediatr和具有同步方法的处理程序Handle:并非所有代码路径都返回值"

静态对象构造顺序

注册所有IMediatR类

WinForms在Linux上的JetBrains Rider中的应用

N层解决方案上的依赖注入-删除样板

带有可选参数的模拟方法返回意外的不同值,具体取决于可选的默认值

C#按名称从类获取属性值类型<;t>;,我需要反射吗?

如何正确处置所有动态控件?

在同一个捕获中可以有多种类型的异常吗?

NETSDK1201:对于面向.NET 8.0和更高版本的项目,默认情况下,指定RUNTIME标识符将不再生成自包含的应用程序

将列表转换为带有逗号分隔字符串形式的值的字典

我可以阻止类型上的Object.ToString()吗?

ASP.NET Core 7空字符串