Sql-Server

SQL Server CLR 函式中的 System.Web

  • October 31, 2019

我對這個主題做了一些簡單的研究,我想知道所有的優點和缺點,或者在 SQL Server 中啟用/註冊這個特定的 .dll 是什麼?

返回資訊 - 我們正在與第三方應用程序集成(不幸的是,這不是我的決定),其中一些需要此 .dll 其他 .dll。我需要 CLR 函式的目的是能夠在 SSMS 中編寫 SQL 查詢,並將該數據發送到第三方應用程序的 API,然後該 API 將執行正確的數據載入/更改(插入和刪除此應用程序有通過其 API 完成)。

編輯 - 也許我應該包括這個細節

在嘗試註冊我的 c# 類時,我顯然得到了錯誤“system.web not registered blah blah blah”,這反過來又促使我對這個主題進行研究。

結束編輯

所以,我的難題是,為了能夠註冊我的 C# 類/.dll,我必須註冊所有依賴的 .dll,但是根據我的研究,我知道這個特定的可能會很成問題。

所以看到我對Google研究之外的陷阱不是很熟悉,我想知道你們中的一個人是否可以幫助我了解如何在這方面做出最好的決定。

另外,我還能在這篇文章中添加什麼,以便更容易提供洞察力?我不太確定 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;
           }
       }
   }

3rd 方軟體需要 DLL 在這裡似乎無關緊要。看來問題很簡單:

我需要……能夠在 SSMS 中編寫 SQL 查詢並將該數據發送到第三方應用程序的 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 請求以及減少對性能的潛在負面影響的選項。

如果您說您正在使用 3rd 方應用程序的 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. 這本質上不是問題,但確實允許很容易成為問題的行為。例如,如果此第 3 方 DLL 使用的任何程式碼路徑使用靜態變數來記憶體資訊,如果該值不是標準的(即它可以在呼叫此程式碼之間甚至期間更改),那麼您可以由於 SQL Server 使用共享的應用程序域並且所有會話共享相同的記憶體/靜態數據,因此進入競爭狀態。

UNSAFE由於不在“支持”列表中,因此必須載入一些程式碼,並且它包含違反安全策略的內容,即使您永遠不會使用該特定程式碼路徑。在這些情況下,程式碼在技術上可以是“安全的”,但如果沒有看到原始碼,你就無法確定。所以你需要測試,但測試需要超過 1 個人點擊幾次:它需要多個並發會話點擊此程式碼以查看是否存在競爭條件。但是還有其他更難測試的場景,例如由於異常導致的記憶體洩漏。受支持的庫中的某些方法因此受到限制,但可能沒有人知道不受支持的庫中的方法是否存在此類問題,因為我不相信它們已經過測試。

如果此功能旨在非面向使用者(即係統程序、公司內部功能等),那麼您可以通過啟動 SQL Server Express 實例並載入來緩解大多數問題(安全性、性能、穩定性)你在那裡的項目。這會將非理想 SQLCLR 功能與您的生產應用程序隔離/隔離。假設您已經在使用正常的外部SqlConnection(不是內部/受信任的連接),那麼這不需要對您的程式碼進行任何更改。

使用這種方法(即,將 SQLCLR 項目載入到隔離實例中)無法減輕的唯一風險是,如果 Microsoft 更新System.Web(或將其載入到 SQL Server 時被吸入的任何依賴項),程式碼可能會中斷是一個混合模式庫。這可能永遠不會發生,但如果發生了,那麼除非他們切換到 using ,否則您將無法載入該 3rd 方 DLL HttpWebRequest,而且他們幾乎沒有理由進行此類更改。

更新

OP 回復了一個相關問題,他們選擇將項目類型更改為控制台應用程序,並且最有可能使用 SQL 代理來安排它(但也可以使用 Windows 任務計劃程序

相關文章(在 StackOverflow 上):

  1. CREATE PROCEDURE 為 SQLCLR 儲存過程獲取“消息 6567,級別 16,狀態 2”
  2. 帶有 CLR 函式的 System.Security.SecurityException

引用自:https://dba.stackexchange.com/questions/252077