我有一个独特的问题。我正在将一个dll注册为SQL Server数据库中的一个程序集,该数据库接收一个SQLXml变量以及两个字符串,并将数据序列化为JSON格式。
作为参考,这里是方法调用:
[SqlProcedure]
public static void Receipt(SqlString initiatorPassword,
SqlString initiatorId,
SqlXml XMLOut,
out SqlString strMessge)
如果这是任何其他类型的应用程序,我会使用Newtonsoft.Json或Jayrock这个应用程序。通常我会按照here给出的答案,做类似的事情:
XmlReader r = (XmlReader)XmlOut.CreateReader();
XmlDocument doc = new XmlDocument();
doc.load(r);
但是,由于我使用的是SQLClr,因此有一定的规则。其中之一是.Load()
和任何其他继承的方法都不能使用。我认为.Net框架说得最好:
System.InvalidOperationException:无法加载动态生成的序列化程序集。在某些托管环境中,组件加载功能受到限制,请考虑使用预生成的序列化程序。有关更多信息,请参阅内部异常。 ---> System.IO.FileLoadException: LoadFrom(),LoadFile(),Load(byte [])和LoadModule()已被主机禁用。
我无论如何都不能流利使用SqlClr,但是如果我正确理解this blog,这是由于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循环是一个混乱的调试,这里最好的方法是什么?通常讨论的另一种方法是使用匹配变量反序列化为Object,但我有一个相当大的XML来自SQL Server。我的循环是动态编程的尝试,因为有大约200个字段被用来制作这个XML。
注意:我正在使用Jayrock并在.Net Framework 2.0中工作。我目前无法更改框架版本。
您的代码抛出异常:
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
的方法的唯一时间是来自一个地方:
if (m.NodeType == XmlNodeType.Text)
{ //Writes text here. NOTE: m.Depth > lastdepth here!!!!!!!
w.WriteString(m.Value);
wt = true;
}
这意味着此处存在错误。也许您可以在这里尝试/捕获或改进代码。
我希望这适用于你,但除非你尝试,否则不会知道。来自here:
EXTERNAL_ACCESS解决了代码需要访问服务器外部资源的场景,例如文件,网络,注册表和环境变量。只要服务器访问外部资源,它就会模拟调用托管代码的用户的安全上下文。
UNSAFE代码权限适用于程序集不可验证安全或需要对受限资源(如Microsoft Win32 API)进行其他访问的情况。
我相信这两个中的一个是你需要的,可能是EXTERNAL_ACCESS
。更多:
我们建议从master数据库中的程序集文件创建非对称密钥。必须创建映射到此非对称密钥的登录名,并且必须授予登录外部访问程序集或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
我想你也想在项目中打开Generate serialization assembly。
这实际上回避了你的问题,但这确实是允许其他DLL成功加载的首选方法,因此你可以编写正确的代码。