2009-05-30 13 views
7

Estoy utilizando una clase en un proyecto C# ASP.NET para permitir que un script escrito en un lenguaje de scripting aleatorio exponga dinámicamente los métodos del servicio web; en otras palabras, el script debería poder exponer un método de cualquier nombre con cualquier firma (siempre y cuando sea válido) para el mundo exterior a través de esta interfaz SOAP (capaz de agregar y eliminar a voluntad, sin necesidad de un cambio de código), y como tal necesito poder crear una clase de servicio web en C# mientras se pueden agregar y eliminar métodos dinámicamente en tiempo de ejecución.Dynamic C# .NET Webservice

Ahora, el mejor plan al que he podido llegar hasta ahora es (tiempo de ejecución) generar código C# para representar el servicio web, utilizando System.Reflection.Emit para compilarlo y luego cargar el ensamblado en tiempo de ejecución, todo siempre que el script agregue o elimine un método del servicio (no debería ocurrir muy a menudo, tenga en cuenta).

¿Alguien tiene una idea mejor que esta?

Respuesta

5

Puede modificar WSDL utilizando la clase SoapExtensionReflector. De Kirk Evans Blog:

El SoapExtensionReflector se llama cuando el tipo se está reflejando a proporcionar la definición WSDL para el servicio. Puede aprovechar este tipo para interceptar la llamada de reflexión y modificar la salida de WSDL.

El ejemplo siguiente elimina el primer método de métodos de servicio 2 web:

[WebService(Namespace = "http://tempuri.org/")] 
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 
[System.ComponentModel.ToolboxItem(false)] 
public class Service1 : System.Web.Services.WebService 
{ 
    [WebMethod] 
    public string HelloWorld() 
    { 
     return "Hello World"; 
    } 

    [WebMethod] 
    public int Multiply(int a, int b) 
    { 
     return a * b; 
    } 
} 

Crear una clase heredada de SoapExtensionReflector:

namespace TestWebservice 
{ 
    public class MyReflector : SoapExtensionReflector 
    { 
     public override void ReflectMethod() 
     { 
     //no-op 
     } 

     public override void ReflectDescription() 
     { 
     ServiceDescription description = ReflectionContext.ServiceDescription; 
     if (description.PortTypes[0].Operations.Count == 2) 
      description.PortTypes[0].Operations.RemoveAt(0); 
     if (description.Messages.Count == 4) 
     { 
      description.Messages.RemoveAt(0); 
      description.Messages.RemoveAt(0); 
     } 
     foreach (Binding binding in description.Bindings) 
     { 
      if (binding.Operations.Count == 2) 
       binding.Operations.RemoveAt(0); 
     } 
     if (description.Types.Schemas[0].Items.Count == 4) 
     { 
      description.Types.Schemas[0].Items.RemoveAt(0); 
      description.Types.Schemas[0].Items.RemoveAt(0); 
     } 
     } 
    } 
} 

añadir esto a la configuración de sección/system.web en web.config:

<webServices> 
    <soapExtensionReflectorTypes> 
     <add type="TestWebservice.MyReflector, TestWebservice" /> 
    </soapExtensionReflectorTypes> 
</webServices> 

Esto debería darle un punto de partida para eliminar dinámicamente los métodos del documento WSDL. También necesitaría tirar NotImplementedException del método web si está deshabilitado.

Finalmente, debe deshabilitar la documentación del servicio web producida invocando el punto final .asmx sin el parámetro? WSDL. Establezca el atributo href del elemento wsdlHelpGenerator en alguna URL. Puede usar DefaultWsdlHelpGenerator.aspx como punto de partida para su propio manejador de documentación. Consulte la pregunta sobre la documentación del servicio web en XML Files, August 2002.

1

¿Tiene que ser una interfaz SOAP? Parece que podría ser más adecuado para una API basada en ruta/REST/etc. Podría hacer algo en ASP.NET MVC (con un método personalizado IController.Execute que resuelve la acción con el método) bastante fácilmente (de hecho, estoy trabajando en algo muy similar para some of my own code en este momento).

Por ejemplo, es posible que tenga rutas:

http://myserver/myservice/mymethod 

que acepta (ya sea en el cuerpo o args) la carga útil (parámetros), y devuelve el resultado en la respuesta. En MVC no debería ser capaz de hacer algo similar con un controlador genérico mapeado comodín.

+0

Gracias por la respuesta rápida - desafortunadamente debe ser SOAP. Estaba usando XMLRPC hasta este punto, pero interactuar con un tercero que no está dispuesto a usar XMLRPC significa que debo contaminarlo con SOAP. :( –

+0

Hmm ... "buena suerte con eso" ... –

2

XMLRPC está bastante muerto, ¿no?

SOAP implica un WSDL. ¿Cómo se genera el WSDL dinámicamente?

Debería considerar el uso de WCF. Espero que pueda tomar el control del proceso de generación de WSDL (y otros metadatos), pero también debe poder controlar el procesamiento de los mensajes entrantes. En particular, podrá examinar los mensajes entrantes para determinar qué script ejecutar, qué parámetros pasar, etc.

+0

Bueno, por lo que pude ver, XMLRPC no está muerto, simplemente no está en el mismo "mercado" que SOAP, creo. XMLRPC fue elegido para este proyecto porque requiere una interfaz simple y dinámica que sea fácilmente legible/editable por los humanos. Se ha hecho mucho desarrollo en torno a eso, así que ahora, desafortunadamente, tenemos un proyecto escrito usando XMLRPC y un tercero obstinado que se niega a hacerlo cualquier cosa donde no puedan hacer que Visual Studio haga el trabajo por ellos. :( –

+0

Interesante. Por http://en.wikipedia.org/wiki/XML-RPC, siempre me ha parecido que, desde que evolucionó XML-RPC en SOAP, se había convertido en algo así como un "dinosaurio". –

2

Puede crear un servicio WCF con un tipo de entrada y salida de xs:any y manejar la solicitud entrante como un Message crudo. Eso le permitiría aceptar cualquier tipo de datos y devolver cualquier tipo de datos. No usaría contratos de datos o tipos estáticos, solo un Message en y un Message fuera.

El problema con este enfoque es que la generación de un proxy del WSDL realmente no ayuda al consumidor, además de proporcionar un contenedor para llamar al método. Proporcionar datos que sean aceptables para el método requeriría tipos de datos manuales, etc., que no es tan difícil, simplemente no es tan intuitivo como un contrato difícil, mecanografiado.