8

私は少しユニークな問題を抱えています。SQLXml 変数と 2 つの文字列を取り込み、データを JSON 形式にシリアル化する SQL Server データベース内のアセンブリとして dll を登録しています。

参考までに、メソッド呼び出しは次のとおりです。

[SqlProcedure]
public static void Receipt(SqlString initiatorPassword,
                           SqlString initiatorId,
                           SqlXml XMLOut,
                           out SqlString strMessge)

これが他の種類のアプリである場合、このアプリケーションには Newtonsoft.Json または Jayrock を使用します。通常、私はここで与えられた答えに従い、次のようなことをします:

XmlReader r = (XmlReader)XmlOut.CreateReader();
XmlDocument doc = new XmlDocument();
doc.load(r);

ただし、SQLClr を使用しているため、一定のルールがあります。そのうちの 1 つはそれで.Load()あり、他の継承されたメソッドは使用できません。 .Net フレームワークが最もよく言っていると思います。

System.InvalidOperationException: 動的に生成されたシリアル化アセンブリを読み込めません。一部のホスティング環境では、アセンブリの読み込み機能が制限されているため、事前に生成されたシリアライザーの使用を検討してください。詳細については、内部例外を参照してください。---> System.IO.FileLoadException:
LoadFrom()、LoadFile()、Load(byte[])、および LoadModule() がホストによって無効にされました。

私は決して SqlClr に精通しているわけではありませんが、このブログを正しく理解していれば、これは SqlCLR のルールが .Load() と継承されたメソッドを署名なしで許可せず、厳密な名前を持たないことが原因です。私の DLL と私が使用しているサード パーティの DLL には厳密な名前がなく、自分で再構築して署名することもできません。したがって、これにより、ロードを使用せずにこのタスクを完了しようとすることに行き詰まります(誰かがこれを行うことができる別の方法を知っていない限り)

私が思いついた唯一の解決策は、正しく機能していない非常に醜い while ループです。「Jayrock.Json.JsonException: JSON オブジェクト内の JSON メンバー値は、そのメンバー名の前に置く必要があります」という例外が発生しました。 . これが私が書いたwhileループです(私の最高のコードではありません、私は知っています):

 int lastdepth = -1;
 Boolean objend = true;
 Boolean wt = false;
//Write Member/Object statements for the header omitted
JsonWriter w = new JsonTextWriter()
 while (m.Read())
                {
                    if ((lastdepth == -1) && (m.IsStartElement()))
                    {//Checking for root element
                        lastdepth = 0;
                    }
                    if ((m.IsStartElement()) && (lastdepth != -1))
                    {//Checking for Start element ( <html> )
                        w.WriteMember(m.Name);
                        if (objend)
                        { //Check if element is new Parent Node, if so, write start object
                            w.WriteStartObject();
                            objend = false;
                        }
                    }
                    if (m.NodeType == XmlNodeType.Text)
                    { //Writes text here.  NOTE: m.Depth > lastdepth here!!!!!!!
                        w.WriteString(m.Value);
                        wt = true;
                    }
                    if (m.NodeType == XmlNodeType.Whitespace) //If whitespace, keep on truckin
                    { m.Skip(); }
                    if ((m.NodeType == XmlNodeType.EndElement) && (wt == false) && (lastdepth > m.Depth))
                    {//End element that ends a series of "Child" nodes
                        w.WriteEndObject();
                        objend = true;
                    }
                    if ((m.NodeType == XmlNodeType.EndElement) && (wt == true))//Standard end of an el
                    { wt = false; }
                    lastdepth = m.Depth;
                }
                w.WriteEndObject();
                jout = w.ToString();
}

私の質問は、使用できず.load()、while ループをデバッグするのが面倒なので、ここでの最善のアプローチは何でしょうか? 一般的に議論されているもう 1 つのアプローチは、一致する変数を使用したオブジェクトへの逆シリアル化ですが、SQL Server からかなり大きな XML が出力されます。この XML を作成するためにプルされるフィールドが 200 まであるため、私のループは動的プログラミングの試みです。

注: 私は Jayrock を使用しており、.Net Framework 2.0 で作業しています。現時点では、フレームワークのバージョンを変更できません。

4

2 に答える 2

1

これがあなたに当てはまることを願っていますが、試してみないとわかりません。ここから:

EXTERNAL_ACCESS は、ファイル、ネットワーク、レジストリ、環境変数など、コードがサーバー外のリソースにアクセスする必要があるシナリオに対応します。サーバーが外部リソースにアクセスするときは常に、マネージ コードを呼び出すユーザーのセキュリティ コンテキストを偽装します。

UNSAFE コード アクセス許可は、アセンブリが検証可能なほど安全でない場合、または Microsoft Win32 API などの制限されたリソースへの追加アクセスが必要な場合に使用します。

おそらく、この 2 つのうちの 1 つが必要だと思いますEXTERNAL_ACCESS。もっと:

master データベースのアセンブリ ファイルから非対称キーを作成することをお勧めします。次に、この非対称キーにマップされたログインを作成し、そのログインに EXTERNAL ACCESS ASSEMBLY または UNSAFE ASSEMBLY 権限を付与する必要があります。

注:非対称キーに関連付けるには、新しいログインを作成する必要があります。このログインは、権限を付与するためにのみ使用されます。ユーザーに関連付ける必要も、アプリケーション内で使用する必要もありません。

そして関連するコード(私は過去にこれをうまく使ったことがあります):

USE master; 
GO  

CREATE ASYMMETRIC KEY SQLCLRTestKey FROM EXECUTABLE FILE = 'C:\MyDBApp\SQLCLRTest.dll'   
CREATE LOGIN SQLCLRTestLogin FROM ASYMMETRIC KEY SQLCLRTestKey   
GRANT EXTERNAL ACCESS ASSEMBLY TO SQLCLRTestLogin; 
GO 

プロジェクトでシリアル化アセンブリの生成もオンにしたいと思います。

これは実際にはあなたの質問を回避しますが、これは他のDLLを正常にロードできるようにするための推奨される方法であり、正しいコードを書くことができます.

于 2012-06-21T21:14:49.293 に答える
0

JayRock のコード

あなたのコードは例外をスローしています:

A JSON member value inside a JSON object must be preceded by its member name.

この例外は次のメソッドから発生します。

    private void EnsureMemberOnObjectBracket() 
    {
        if (_state.Bracket == JsonWriterBracket.Object)
            throw new JsonException("A JSON member value inside a JSON 
             object must be preceded by its member name.");
    }

そのコードからの包含呼び出しは次のとおりです。

    public sealed override void WriteString(string value)
    {
        if (Depth == 0)
        {
            WriteStartArray(); WriteString(value); WriteEndArray();
        }
        else
        {
            EnsureMemberOnObjectBracket();
            WriteStringImpl(value);
            OnValueWritten();
        }
    }

コードが呼び出すメソッドを呼び出すのEnsureMemberOnObjectBracketは、1 つの場所からのみです。

if (m.NodeType == XmlNodeType.Text)
{ //Writes text here.  NOTE: m.Depth > lastdepth here!!!!!!!
 w.WriteString(m.Value);
 wt = true;
}

これは、ここにエラーがあることを意味します。おそらく、ここでコードの try/catch や改良を行うことができます。

于 2012-06-21T21:58:00.273 に答える