CLRで特定のAPI関数を使用できるように、C#アセンブリを使用してネイティブコードAPI(C++ .dll)を実行しようとしていますSQL Serverのストアドプロシージャ私がC++ dllから使用しようとしている関数は、データヒストリアンの生データにアクセスし、アンマネージ型のデータを返します。その後、C#アセンブリに残してマーシャリングし、結果をSQL Serverにパイプします。SQL Server 2016 CLRストアドプロシージャエラー:「システムアサーションチェックに失敗しました」
私はC + +のDLLのソースコードを持っていないので、実際にはフードの下(サードパーティ製)で正確に何が起こっているのか分かりません。しかし、私は問題なくC#コンソールアプリでこれらのAPI関数にアクセスすることができます(私はhttps://lennilobel.wordpress.com/2014/01/29/calling-c-from-sql-clr-c-code/に.NETのC++ dllをラッピングすることに頼っていました)。私はC#コンソールアプリケーションを開発し、これをクラスライブラリに変換し、クラスを "[Microsoft.SqlServer.Server.SqlProcedure]"にラップし、UNSAFEモードで目的のSQLデータベースにアセンブリを追加しました。私はまた、SQL Serverでclrが有効で、私が使用しているデータベースでTRUSTWORTHYがオフであることを確認しました。
ただし、C#アセンブリを使用するストアドプロシージャを呼び出そうとすると、次の問題が発生します。
Location: AppDomain.cpp:2705
Expression: hr != E_POINTER
SPID: 66
Process ID: 3584
Msg 3624, Level 20, State 1, Procedure sp_direct_proficy_api, Line 0 [Batch Start Line 2]
A system assertion check has failed. Check the SQL Server error log for details. Typically, an assertion failure is caused by a software bug or data corruption. To check for database corruption, consider running DBCC CHECKDB. If you agreed to send dumps to Microsoft during setup, a mini dump will be sent to Microsoft. An update might be available from Microsoft in the latest Service Pack or in a Hotfix from Technical Support.
Msg 596, Level 21, State 1, Line 2
Cannot continue the execution because the session is in the kill state.
Msg 0, Level 20, State 0, Line 2
A severe error occurred on the current command. The results, if any, should be discarded.
私はシステムアサーションチェックでいくつかのGoogle検索を行い、通常はデータベースの破損の結果として発生していることがわかりました。私はDBCC CHECKDBを実行しており、すべてが正常に見えるので、これは問題ではありません。私は、上記のリンクからのLeonardの例を、私がはるかに単純なC++のdllで取り組んでいるのと本質的に同じプロセスであると複製しました。この例ではエラーは発生しなかったので、SQL ServerとC++ APIの間にappdomainの競合があると思います。
私の質問
が、これは私がしようとしています何のために予想される問題ですか? CLRストアドプロシージャを使用すると、SQL Serverがコンピュータのメモリにアクセスし、appdomainを要求する方法について多くのことはわかりませんが、SQL ServerとC++ APIの間でリソースの競合があるようです。
以下に、C#アセンブリの2つの部分(C#のハーネスからのC++ dllの呼び出しと、ストアドプロシージャによってアクセスされるクラス)を示します。アクセスCにストアドプロシージャで使用するC++
public class IHUAPI
{
const string DLLNAME = "IHUAPI.dll";
static class IHU64
{
[DllImport(DLLNAME, CallingConvention = CallingConvention.StdCall, EntryPoint = "[email protected]")]
public static extern ihuErrorCode ihuConnect(string server, string username, string password, out int serverhandle);
[DllImport(DLLNAME, CallingConvention = CallingConvention.StdCall, EntryPoint = "ihuReadRawDataByTime")]
public static extern ihuErrorCode ihuReadRawDataByTime(int serverhandle, string tagname, ref IHU_TIMESTAMP start, ref IHU_TIMESTAMP end, out int numberOfSamples, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4, ArraySubType = UnmanagedType.LPStruct)] out IHU_DATA_SAMPLE[] samples);
}
public static ihuErrorCode ihuConnect(string server, string username, string password, out int serverhandle)
{
return IHU64.ihuConnect(server, username, password, out serverhandle);
}
public static ihuErrorCode ihuReadRawDataByTime(int serverhandle, string tagname, IHU_TIMESTAMP start, IHU_TIMESTAMP end, out IHU_DATA_SAMPLE[] samples)
{
int numberOfSamples;
return IHU64.ihuReadRawDataByTime(serverhandle, tagname, ref start, ref end, out numberOfSamples, out samples);
}
}
C#アセンブリから
C#DLLのインポート++ API
[Microsoft.SqlServer.Server.SqlProcedure]
public static void API_Query(string tagname, DateTime start_date, DateTime end_date)
{
int handle;
ihuErrorCode result;
result = IHUAPI.ihuConnect("houmseosprf007", "", "", out handle);
IHU_DATA_SAMPLE[] values;
IHU_TIMESTAMP start = new IHU_TIMESTAMP(start_date);
IHU_TIMESTAMP end = new IHU_TIMESTAMP(end_date);
ihuErrorCode result_api = IHUAPI.ihuReadRawDataByTime(handle, tagname, start, end, out values);
SqlMetaData[] md = new SqlMetaData[3];
md[0] = new SqlMetaData("tagname", SqlDbType.Text);
md[1] = new SqlMetaData("return_value", SqlDbType.NVarChar, 50);
md[2] = new SqlMetaData("timestamp", SqlDbType.DateTime);
SqlDataRecord row = new SqlDataRecord(md);
SqlContext.Pipe.SendResultsStart(row);
DateTime p;
string p2;
for (int i = 1; i < (values == null ? 0 : values.Length); i++)
{
using (IHU_DATA_SAMPLE sample = values[i])
{
if (sample.ValueDataType != ihuDataType.Array)
{
p = sample.TimeStamp.ToDateTime();
p2 = sample.ValueObject.ToString();
row.SetValue(0, tagname);
row.SetValue(1, p2);
row.SetValue(2, p);
}
else
{
p = sample.TimeStamp.ToDateTime();
ihuArrayValue aValue = (ihuArrayValue)Marshal.PtrToStructure(sample.Value.ArrayPtr, typeof(ihuArrayValue));
p2 = aValue.GetArrayValue.ToString();
row.SetValue(0, tagname);
row.SetValue(1, p2);
row.SetValue(2, p);
}
}
SqlContext.Pipe.SendResultsRow(row);
}
SqlContext.Pipe.SendResultsEnd();
}
良いアドバイス。ストアドプロシージャを使用してSQL ServerインスタンスをホストするボックスでWebサービスをホストするのと同じ問題が発生しますか? – bidout
私は信じられませんが、テストする必要があります。同じサーバーを使用しても問題ありませんが、SQL Serverが実際に何をするかは、それが何をするかについての意見よりも重要です。 "IHU"サービスがSQL Serverと同じサーバー上に既に存在する場合は、このWebサービスを実行して、リモートサービスが元のサーバーにコールバックするようにネットワークを呼び出さないようにします。しかし、 "IHU"が別のサーバー上にある場合は、SQL Serverが取得できる物理RAMの量が多くなるので、Webサーバーに格納することを選択します。 –
アンマネージドコード部分用のWeb APIをまとめました。ストアドプロシージャはクライアントを呼び出し、クライアントはC++ dllを呼び出すWeb APIを呼び出します。ストアドプロシージャを実行するのと同じコンピュータでホストをテストしましたが、これまで問題なく動作していました。上記のRAMの理由から、APIサーバーを別のサーバーに移行することになります。 – bidout