SQL Server CLR 函数中的 System.Web

Dou*_*ats 5 sql-server c# sql-clr web-service api

我对这个主题做了一些简单的研究,我想知道什么是所有的优点和缺点,或者在 SQL Server 中启用/注册这个特定的 .dll?

返回信息 - 我们正在与第三方应用程序集成(不幸的是,这不是我的决定),它需要这个 .dll 来处理其他一些 .dll。我需要 CLR 函数的目的是能够在 SSMS 中编写 SQL 查询并将该数据发送到第三方应用程序的 API,然后第三方应用程序的 API 将依次执行正确的数据加载/更改(向/从该应用程序插入和删除)将通过其 API 完成)。

编辑 - 也许我应该包括这个细节

在尝试注册我的 c# 类时,我显然收到了错误“system.web 未注册等等等等”,这反过来又促使我对这个主题进行研究。

结束编辑

所以,我的难题是,为了能够注册我的 C# 类/.dll,我必须注册所有依赖的 .dll,但是根据我的研究,我知道这个特定的可能会有很大的问题。

因此,看到我对谷歌研究之外的陷阱并不十分熟悉,我想知道你们中的一个好人是否可以帮助我了解如何在这方面做出最佳决定。

另外,我还能在这篇文章中添加什么,以便更容易提供洞察力?我不太确定 C# 代码是否相关?我知道这可能有点宽泛,但我希望它足够具体而不会被标记?

更具体地说明这里发生的事情(根据所罗门的要求)

  1. 第 3 方应用程序使用“API”(松散使用,因为我被告知它不是一个很好的 API)来回发送数据。您会注意到它调用了一个 Importer 函数,该函数只接受它转换的数据表或 excel 文件。我别无选择,因为公司告诉我通过普通 XML 插入和删除非常慢并且有意外行为。

  2. 引用 System.Web 的 .DLL 在我的 C# 类中被引用,这是首先需要能够向它发送数据的。

  3. 关于:

    为什么你不能使用我提到的方法?它们已经存在于 SQL Server 的 CLR 主机中。这是一个网络服务,对吧

我不确定我对 API 的总体了解是否足以回答这个问题。我很愿意而且只是缺乏这样做的知识和经验。这也可能是因为我对如何与这个特定的 API 交互有限制,我不确定这些限制如何应用于这些方法。(我会进一步调查,看看我是否可以自己回答这个问题)。

尽管我考虑得越多,我可以创建一个 SQL Server 可以调用的“中间人”类,然后它会调用另一个类,该类将拥有所有正确的引用,这可能会让我摆脱当前的情况。但是,我仍然对具体的反馈感兴趣,以便我可以从中学习。

这是我的 C# 类:

    using Perfion.Api;   -- this .DLL references System.Web. 
    using Perfion.Api.Import;
    using System;
    using System.Data;
    using System.Data.SqlClient;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading.Tasks;

    namespace PerfInsert
    {
        public static class PerfionInsert 
        {
            public static bool CreateCommand(string tblString, string featureName, string connectionString, string perfionConnectionString, string logFile)
            {
                StringBuilder logInfo = new StringBuilder();
                try
                {
                    var wList = new Regex(@"[^0-9a-z\.\[\]_]#", RegexOptions.IgnoreCase);
                    if (wList.IsMatch(tblString))
                    {
                        logInfo.AppendLine($"{DateTime.UtcNow} - Regex Validation Failed for Table Name!");
                        return false;
                    }
                    using (SqlConnection connection = new SqlConnection(connectionString))
                    {
                        var qryString = "SELECT * FROM " + tblString;
                        using (SqlCommand command = new SqlCommand(qryString, connection))
                        {
                            connection.Open();
                            using (var dataReader = command.ExecuteReader())
                            using (var dataTable = new DataTable())
                            {
                                dataTable.Load(dataReader);
                                PerfionApi api = new PerfionApi(perfionConnectionString);
                                Importer importer = new Importer(api.Connection);
                                importer.Status += (sender, e) => { logInfo.AppendLine($"{DateTime.UtcNow} - {e.Title}"); };
                                importer.LoadData(dataTable);
                                importer.ImportToDatabase(featureName);
                            }
                        }
                    }
                    return true;
                }
                catch (Exception ex)
                {
                    logInfo.AppendLine($"{DateTime.UtcNow} - {ex.ToString()}");
                }
                finally
                {
                    File.AppendAllText(logFile, logInfo.ToString());
                }
                return false;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

Sol*_*zky 7

第 3 方软件需要 DLL 似乎与此无关。问题似乎很简单:

我需要 ... 能够在 SSMS 中编写 SQL 查询并将该数据发送到第三方应用程序的 API,然后第三方应用程序的 API 将依次执行正确的数据加载/更改(向/从该应用程序插入和删除必须是通过其 API 完成)。

我相信你最好的两个选择是:

  1. 如果这个过程像您所说的一样简单,并且您真的想坚持使用System.Web,那么为什么不创建一个控制台应用程序来执行查询,然后将您需要的任何内容发布到 API?如果需要定期执行此操作,则可以在 Windows 任务计划程序或 SQL Server 代理中进行计划(通过“操作系统 (CmdExec)”作业步骤)。

  2. 如果这个过程是一个有点复杂和/或需要在一个更动态/特设的方式做这些查询的能力,那么System.Web是不是必需的,它只是使一些编码更容易。Intead,查看HttpWebRequestHttpWebResponse。这两个包含在 中System.Net,它是 SQLCLR 支持的 .NET Framework 库之一。主要区别在于您需要手动构建 XML 请求。处理响应也是如此。这种方法比导入更稳定和安全System.Web

    按照这些思路,对于需要此类功能但不想(或无法)对其进行编码的任何人,我编写了一个 SQLCLR 函数和过程库 — SQL# — 其中包括一个存储过程INET_GetWebPages,它实现了这两种方法。虽然有免费版本,但此特定存储过程仅在完整(即付费)版本中可用。但是,它确实处理了各种选项/场景,包括:设置各种 HTTP 标头、可选的基本身份验证、代理服务器、发送 GET 与 POST 数据、处理 PUT 请求以及减少对性能的潜在负面影响的选项。

如果您说您正在使用第 3 方应用程序的 DLL 通过他们提供的方法进行 API 调用,并且引用和使用的是他们的 DLL System.Web(而不是您的代码直接),那么很难完全确定是什么所有的影响都是。但这里有一些关于这种方法需要考虑的事情:

System.Web不在SQLCLR的“支持的 .NET Framework 库”列表中。这至少意味着:

  1. 不保证此库可在 SQL Server 中加载。即使当前可以加载,SQL Server 也只允许纯 MSIL 库,而不会加载混合模式库(即其中包含托管和非托管代码的 DLL)。没有办法绕过这个限制。由于此库不在列表中,因此它可以在未来的 .NET Framework 更新中从纯更改为混合。如果发生这种情况,此代码将停止工作,因为这是一个框架库并加载到 GAC 中,并且加载到 SQL Server 和 GAC 中的库必须是完全相同的版本(因此您不能继续使用旧的工作版本) . 这种从纯到混合的变化并不经常发生,但以前发生过。
  2. 这个库需要加载为UNSAFE. 这本质上不是问题,但确实允许很容易成为问题的行为。例如,如果此 3rd 方 DLL 使用的任何代码路径使用静态变量来缓存信息,如果该值不标准(即它可以在调用此代码之间甚至在调用此代码期间更改),那么您可以进入竞争条件,因为 SQL Server 使用共享应用程序域并且所有会话共享相同的内存/静态数据。

有些代码UNSAFE由于不在“支持”列表中而必须加载,并且它包含违反安全策略的内容,即使您永远不会使用该特定代码路径。在这些情况下,代码在技术上可能是“安全的”,但如果没有看到源代码,您就无法确定。所以你需要测试,但测试需要超过 1 个人点击几次:它需要多个并发会话点击此代码以查看是否存在竞争条件。但是还有其他更难测试的场景,例如由于异常导致的内存泄漏。受支持的库中的某些方法因此受到限制,但可能没有人知道不受支持的库中的方法是否存在此类问题,因为我认为它们没有经过测试。

如果此功能旨在非面向用户(即系统流程、公司内部功能等),那么您可以通过启动 SQL Server Express 实例并加载来缓解大多数问题(安全性、性能、稳定性)你的项目在那里。这会将非理想的 SQLCLR 功能与您的生产应用程序隔离/隔离。假设您已经在使用常规的外部SqlConnection(不是内部/受信任的连接),那么这不需要对您的代码进行任何更改。

使用此方法(即,将 SQLCLR 项目加载到隔离的实例中)无法缓解的唯一风险是,如果 Microsoft 更新System.Web(或将其加载到 SQL Server 时被吸入的任何依赖项),则代码可能会中断成为一个混合模式的库。这可能永远不会发生,但如果确实发生了,那么除非他们切换到 using HttpWebRequest,否则您将无法加载该 3rd 方 DLL ,并且他们几乎没有理由进行此类更改。

更新

OP 回复了一个相关的问题,他们选择将项目类型更改为控制台应用程序,并且很可能会使用 SQL 代理来安排它(但也可以使用 Windows 任务计划程序

相关帖子(在 StackOverflow 上):

  1. CREATE PROCEDURE 获取 SQLCLR 存储过程的“消息 6567,级别 16,状态 2”
  2. System.Security.SecurityException 与 CLR 函数