2012-06-20 18 views
7

Tengo un problema único. Estoy registrando un dll como un ensamblado dentro de una base de datos de SQL Server que toma una variable SQLXml, junto con dos cadenas, y serializa los datos en formato JSON.Deserialización de XML en JSON sin utilizar la función XmlDocument.Loadxml()

Para referencia, aquí es la llamada al método:

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

usaría Newtonsoft.Json o Jayrock para esta aplicación si se trataba de cualquier otro tipo de aplicación. Normalmente yo sigo la respuesta dada here y hacer algo similar a:

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

Sin embargo, desde que estoy usando SQLCLR, hay ciertas reglas de la carretera. Una de ellas es que .Load() y cualquier otro método heredado no se puede utilizar. Creo que el .Net Framework lo dijo mejor:

System.InvalidOperationException: No se puede cargar el ensamblaje de serialización generado dinámicamente. En algunos entornos de alojamiento la funcionalidad de carga del ensamblaje está restringida, considere usar un serializador pregenerado. Por favor vea la excepción interna para más información. ---> System.IO.FileLoadException:
LoadFrom(), LoadFile(), Load (byte []) y LoadModule() han sido deshabilitados por el host.

No soy fluido en SQLCLR por cualquier medio, pero si yo soy la inteligencia this blog correctamente, esto es causado por las reglas de SQLCLR no permitir .load() y heredó métodos sin ser firmado para y que tiene un nombre seguro. Mi DLL y los DLL de terceros que estoy usando no tienen un nombre fuerte ni puedo reconstruirlos y firmarlos yo mismo. Por lo tanto, esto me deja trabado al intentar completar esta tarea sin usar carga (a menos que alguien sepa otra forma en que esto se puede hacer)

Mi única solución que podría surgir es un ciclo muy desagradable que no funciona correctamente , He estado obteniendo una "Jayrock.Json.JsonException: un valor de miembro JSON dentro de un objeto JSON debe estar precedido por su nombre de miembro" excepción. Aquí está el bucle mientras escribía (no es mi mejor código, lo sé):

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(); 
} 

Mi pregunta es, ya que no puedo usar .load() y mi bucle while es un desastre de depurar, lo que sería la mejor acercarse aquí? El otro enfoque comúnmente discutido es la deserialización en un objeto con variables coincidentes, pero tengo un XML bastante grande que sale de SQL Server. Mi ciclo es un intento de programación dinámica ya que hay ~ 200 campos que se están extrayendo para hacer este XML.

Nota: Estoy usando Jayrock y estoy trabajando en .Net Framework 2.0. No puedo cambiar la versión del marco en este momento.

+0

AFAIK 'XmlDocument.LoadXml()' no necesita dirigir ensamblados dinámicos. ¿Estás seguro de que no estás tratando de usar la serialización XML en su lugar? ¿Podría publicar el rastro de la pila de la excepción? – svick

Respuesta

0

Code For JayRock

Su código está lanzando una excepción:

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

Esta excepción viene del método:

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."); 
    } 

La llamada que contiene de ese código es de:

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

La única vez que el código llama a un método que llama EnsureMemberOnObjectBracket es de un lugar:

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

Esto significa que hay un error aquí. Tal vez podría intentar/capturar o refinar su código aquí.

1

Espero que esto sea aplicable a usted, pero no lo sabrá a menos que lo intente. De here:

EXTERNAL_ACCESS dirige a escenarios en los que el código necesita para acceder a los recursos fuera del servidor, tales como archivos, red, registro, y variables de entorno. Cuando el servidor accede a un recurso externo , se apropia del contexto de seguridad del usuario que llama al código administrado .

permiso de código no seguro es para aquellas situaciones en las que un ensamblado se no verificable seguro o requiere un acceso adicional a los recursos restringidos , como la API de Win32 de Microsoft.

Creo que uno de estos dos es lo que necesita, probablemente EXTERNAL_ACCESS. Más:

Recomendamos que se cree una clave asimétrica a partir del archivo de ensamblaje en la base de datos maestra. A continuación, se debe crear un inicio de sesión asignado a esta clave asimétrica y se debe otorgar permiso de acceso EXTERNAL ACCESS ASSEMBLY o UNSAFE ASSEMBLY.

Nota: Debe crear un nuevo inicio de sesión para asociar con la clave asimétrica. Este inicio de sesión solo se usa para otorgar permisos; no tiene que ser asociado con un usuario o utilizado dentro de la aplicación.

Y el código correspondiente (he utilizado esto con éxito en el pasado):

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 

Imagino que también quiere Generar ensamblado de serialización activada en su proyecto.

Esto elude su pregunta en realidad, pero esta es realmente la forma preferida de permitir que otras DLL se carguen correctamente para que pueda escribir el código correcto.

+0

AH! Ojalá hubiera visto esto antes de cambiar mi programa completo debido a este error. ¡Muchas gracias, estoy seguro de que tendré que usar esto pronto! – ScruffMcGruff

Cuestiones relacionadas