【问题标题】:NLog with an Entity Framework connection string?带有实体框架连接字符串的 NLog?
【发布时间】:2012-02-03 21:04:05
【问题描述】:

我正在尝试使用'Database' NLog target 并希望 NLog 读取我的连接字符串以避免在同一个配置文件中设置两次。问题是我有一个Entity Framework-style connection string,所以使用connectionStringName 属性不起作用。

在 log4net 中,我可以使用 custom AdoNetAppender 并自己提取连接字符串的适当部分。有什么方法可以自定义 NLog 的数据库目标,以便我可以传入适当样式的连接字符串?

【问题讨论】:

    标签: .net entity-framework connection-string nlog


    【解决方案1】:

    NLog 4.5 增加了对从实体框架解析连接字符串的支持,因此它们可以直接使用:

    https://github.com/NLog/NLog/pull/2510

    NLog DatabaseTarget 也不再是密封的,所以如果需要特殊处理也可以这样做。

    进行特殊解析/查找逻辑的常规方法是注册一个自定义布局渲染器并在 ConnectionString-Layout 中引用它:

    https://github.com/NLog/NLog/wiki/How-to-write-a-custom-layout-renderer

    【讨论】:

      【解决方案2】:

      从 DbContext 获取正常连接字符串的方法如下:

      context.Database.Connection.ConnectionString
      

      假设您有适当格式的连接字符串,我认为像这样配置目标更容易:

      1) 在配置中定义目标

       <target name="database" type="Database" connectionString="${gdc:myConnectionString}">
          <commandText>
            ...
          </commandText>
      

      2) 在运行时设置连接字符串

      GlobalDiagnosticsContext.Set("myConnectionString", connectionString);
      

      这样,您不会对 db 目标行为进行硬编码。

      【讨论】:

      【解决方案3】:

      这个问题可以通过在代码中配置日志目标轻松解决:

          private DatabaseTarget CreateDatabaseTarget()
          {
              var entityFrameworkConnection = ConfigurationManager.ConnectionStrings["MyEntities"].ConnectionString;
              var builder = new EntityConnectionStringBuilder(entityFrameworkConnection);
              var connectionString = builder.ProviderConnectionString;
      
              var target = new DatabaseTarget()
              {
                  ConnectionString = connectionString,
                  CommandText = @"insert into Log ([DateTime], [Message]) values (@dateTime, @message);",
                  Parameters = {
                      new DatabaseParameterInfo("@dateTime", new NLog.Layouts.SimpleLayout("${date}")), 
                      new DatabaseParameterInfo("@message", new NLog.Layouts.SimpleLayout("${message}")), 
                 }
              };
              return target;
          }
      

      然后你可以用你的 NLog 配置注册它:

      var target = CreateDatabaseTarget();
      LogManager.Configuration.AddTarget("databaseTarget", CreateDatabaseTarget());
      LogManager.Configuration.LoggingRules.Add(new NLog.Config.LoggingRule("*", LogLevel.Warn, target));
      

      但是,如果您可以接受一些 Nuget 依赖项或想要更完整的解决方案,您可以查看 NLog.MvcNLog.EntityFramework 存储库,它们都有可用的 nuget 包...

      【讨论】:

      • 需要注意的是OP是你链接的NLog.EntityFramework包的创建者。
      • 是的,由于这个问题当时没有令人满意的答案而创建。 :-)
      【解决方案4】:

      无法自定义内置DatabaseTarget,因为它是sealed。 并且没有任何其他扩展点,因为 DatabaseTarget.InitializeTarget() 将始终抛出异常,因为它无法从 EF providerName="System.Data.EntityClient" 创建 DbProviderFactory

      因此,对于当前的 NLog 版本2.0.0.0,您必须选择以下选项:

      1. 您可以复制连接字符串,也可以使用DatabaseTarget DB 配置属性。
      2. 您基本上可以从头开始编写自己的custom target
      3. 您可以提交功能请求,然后等待其实施。

      【讨论】:

      • 该死,我担心这些是我唯一的选择。
      【解决方案5】:

      将变量添加到 NLog.config 文件中

      <variable name="connectionStringNLog" value="" />
      

      然后在目标元素中引用这个变量

      <target name="my-db"
              xsi:type="Database"
              dbProvider="System.Data.SqlClient"        
              connectionString="${var:connectionStringNLog}"
              commandType="StoredProcedure"
              commandText="[dbo].[LogEntryInsert]">
      

      然后在您的 contextfactory c# 文件中添加此行以分配连接字符串值,无论它来自其他配置文件还是 Key Vault:

      LogManager.Configuration.Variables["connectionStringNLog"] = conn.ConnectionString;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多