2009-05-30 10 views
7

J'utilise une classe dans un projet C# ASP.NET pour permettre à un script écrit dans un langage de script aléatoire d'exposer dynamiquement les méthodes de service web - en d'autres termes, le script devrait être capable d'exposer une méthode de n'importe quel nom avec n'importe quelle signature (tant que c'est valide, de toute façon) au monde extérieur via cette interface SOAP (capable de les ajouter et les supprimer à volonté, sans avoir besoin d'un changement de code dur), et en tant que tel je dois pouvoir créer une classe webservice en C# tout en étant capable d'ajouter et de supprimer dynamiquement des méthodes lors de l'exécution. Maintenant, le meilleur plan que j'ai pu trouver jusqu'à présent est (runtime) de générer du code C# pour représenter le webservice, en utilisant System.Reflection.Emit pour le compiler et ensuite charger l'assembly à l'exécution - tout chaque fois que le script ajoute ou supprime une méthode à/du service (ne devrait pas arriver très souvent, l'esprit).Webservice C# .NET dynamique

Est-ce que quelqu'un a une meilleure idée que cela?

Répondre

5

Vous pouvez modifier WSDL en utilisant la classe SoapExtensionReflector. De Kirk Evans Blog:

Le SoapExtensionReflector est appelée lorsque le type est réfléchi sur de fournir la définition WSDL pour votre service. Vous pouvez tirer parti de ce type pour intercepter l'appel de réflexion et modifier la sortie WSDL.

L'exemple suivant supprime la première méthode de 2 méthodes de service 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; 
    } 
} 

Créer une classe héritée 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); 
     } 
     } 
    } 
} 

Ajouter ce à la configuration/section system.web dans web.config:

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

Ceci devrait vous donner un point de départ pour supprimer dynamiquement des méthodes du document WSDL. Vous devrez également lancer NotImplementedException à partir de la méthode web si elle est désactivée. Enfin, vous devez désactiver la documentation de service Web produite en appelant le point final .asmx sans le paramètre? WSDL. Définissez l'attribut href de l'élément wsdlHelpGenerator sur une URL. Vous pouvez utiliser DefaultWsdlHelpGenerator.aspx comme point de départ pour votre propre gestionnaire de documentation. Voir la question sur la documentation du service Web au XML Files, August 2002.

1

Est-ce que ce doit être une interface SOAP? Cela semble être plus approprié pour une API basée sur route/REST/etc. Vous pouvez faire quelque chose dans ASP.NET MVC (avec une méthode personnalisée IController.Execute qui résout l'action à la méthode) assez facilement (en fait, je travaille sur quelque chose de très similaire pour some of my own code pour le moment).

Par exemple, vous pourriez avoir des itinéraires:

http://myserver/myservice/mymethod 

qui accepte (soit dans le corps ou args) la charge utile (paramètres) et renvoie le résultat dans la réponse. En non-MVC, vous devriez être capable de faire quelque chose de similaire avec un gestionnaire générique mappé générique.

+0

Merci pour la réponse rapide - malheureusement, il doit être SOAP. J'utilisais XMLRPC jusqu'à présent, mais l'interfaçage avec un tiers qui ne veut pas utiliser XMLRPC signifie que je dois le souiller avec SOAP. :( –

+0

Hmm ... "bonne chance avec ça" ... –

2

XMLRPC est assez mort, n'est-ce pas?

SOAP implique un WSDL. Comment générez-vous le WSDL dynamiquement?

Vous devriez envisager d'utiliser WCF. Je pense que vous serez en mesure de prendre le contrôle du processus de génération du WSDL (et d'autres métadonnées), mais vous devriez également être en mesure de prendre le contrôle du traitement des messages entrants. En particulier, vous pourrez examiner les messages entrants pour déterminer quel script exécuter, quels paramètres passer, etc.

+0

Eh bien, pour autant que je puisse dire que XMLRPC n'est pas mort, ce n'est pas dans le même "marché" que le SOAP, je pense. ce projet, car il nécessitait une interface simple et dynamique, facilement lisible/modifiable par l'homme, beaucoup de développement a été fait - malheureusement, nous avons maintenant un projet écrit en utilisant XMLRPC et un tiers têtu qui refuse de faire quelque chose où ils ne peuvent pas avoir Visual Studio faire le travail pour eux. :( –

+0

Intéressant.Pour http://en.wikipedia.org/wiki/XML-RPC, il m'avait toujours semblé que, depuis XML-RPC a évolué dans SOAP, il était devenu un peu un "dinosaure". –

2

Vous pouvez créer un service WCF avec un type d'entrée et de sortie de xs:any et gérer la demande entrante comme suit: un Message brut. Cela vous permettrait d'accepter n'importe quel type de données et de renvoyer tout type de données. Vous n'utiliseriez pas de contrats de données ou de types statiques, juste un Message et un Message.

Le problème avec cette approche est que la génération d'un proxy à partir du WSDL ne fait rien pour aider le consommateur autre que de fournir un wrapper pour appeler la méthode. Fournir des données acceptables pour la méthode nécessiterait des types de données roulants à la main, etc. Ce qui n'est pas si difficile, ce n'est pas aussi intuitif qu'un contrat dur et typé.