2008-09-15 8 views
7

Dites que j'ai un service Web ASMX, MyService. Le service a une méthode, MyMethod. Je pouvais exécuter MyMethod sur le côté serveur comme suit:Utilisation de la réflexion pour appeler un service Web ASP.NET

MyService service = new MyService(); 
service.MyMethod(); 

que je dois faire la même, avec le service et la méthode pas connu avant l'exécution. Je suppose que la réflexion est la façon de procéder. Malheureusement, j'ai du mal à le faire fonctionner. Lorsque j'exécute ce code:

Type.GetType("MyService", true); 

Il lance cette erreur:

Could not load type 'MyService' from assembly 'App_Web__ktsp_r0, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.

Toute orientation serait appréciée.

Répondre

2

Je ne suis pas sûr si ce serait la meilleure façon de s'y prendre. Le moyen le plus évident pour moi serait de faire une requête HTTP, et d'appeler le webservice en utilisant un HTTP GET ou POST. En utilisant votre méthode, je ne suis pas entièrement sûr de la façon dont vous allez configurer les données que vous envoyez au service Web. J'ai ajouté quelques exemples de code dans VB.Net

Dim HTTPRequest As HttpWebRequest 
Dim HTTPResponse As HttpWebResponse 
Dim ResponseReader As StreamReader 
Dim URL AS String 
Dim ResponseText As String 

URL = "http://www.example.com/MyWebSerivce/MyMethod?arg1=A&arg2=B" 

HTTPRequest = HttpWebRequest.Create(URL) 
HTTPRequest.Method = "GET" 

HTTPResponse = HTTPRequest.GetResponse() 

ResponseReader = New StreamReader(HTTPResponse.GetResponseStream()) 
ResponseText = ResponseReader.ReadToEnd() 
1

Bien que je ne sais pas pourquoi la réflexion ne fonctionne pas là pour vous (je suppose que le compilateur pourrait être de créer une nouvelle classe de vos annotations [WebService]), ici Voici quelques conseils qui pourraient résoudre votre problème:

Gardez votre WebService simple, peu profond, en un mot: Une implémentation du motif de façade. Faites votre service déléguer le calcul à une classe d'implémentation, qui devrait facilement être appelable via Reflection. De cette façon, votre classe WebService n'est qu'une façade pour votre système - vous pouvez même ajouter un gestionnaire de messagerie, une interface XML-RPC etc., puisque votre logique n'est pas couplée au WebService, mais à un objet de couche de gestion réel. Pensez aux classes WebService en tant qu'objets de couche d'interface utilisateur dans votre architecture.

0

@Kibbee: Je dois éviter le coup de performance HTTP. Il ne s'agira pas d'un appel à distance, donc tout ce surchargé sera inutile.

@Daren: Je suis définitivement d'accord avec cette philosophie de conception. Le problème ici est que je ne vais pas être en contrôle du service ou de sa logique métier sous-jacente.

Ceci est pour a server control qui devra s'exécuter par rapport à un service/méthode arbitraire, orthogonalement à la façon dont le service Web lui-même est implémenté.

0

Bien que je ne peux pas dire de votre message:

Une chose à garder à l'esprit est que si vous utilisez la réflexion, vous devez créer une instance de la classe autogenerated webservice (celui créé à partir du WSDL de votre webservice). Ne créez pas la classe responsbile pour le côté serveur du service.

Donc, si vous avez un webservice

[WebService(Namespace = "http://tempuri.org/")] 
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 
    [ToolboxItem(false)] 
    public class WebService1 : System.Web.Services.WebService 
    { 
    ... 
    } 

vous ne pouvez pas faire référence à cette assemblée dans votre client et faire quelque chose comme:

WebService1 ws = new WebService1(); 
ws.SomeMethod(); 
0

@Radu: Je suis en mesure de créer une instance et appel la méthode exactement comme ça. Par exemple, si j'ai ASMX:

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

je peux l'appeler d'un codebehind ce la page ASPX comme:

MyService service = new MyService(); 
Response.Write(service.HelloWorld());

Voulez-vous dire qu'il ne faut pas travailler?

+0

Il wil "travail", mais probablement pas comme vous le souhaitez à. Il retournera la chaîne "Hello World", mais la méthode sera exécutée localement sur le client et non sur le serveur. – Radu094

+0

Ce n'est pas ce qui se passe. Essayez-le. –

1

Voici une réponse rapide que quelqu'un peut probablement développer. Lorsque vous utilisez l'application de modèle WSDL (WSDL.exe) pour générer des wrappers de service, il génère une classe de type SoapHttpClientProtocol. Vous pouvez le faire manuellement aussi:

public class MyService : SoapHttpClientProtocol 
{ 
    public MyService(string url) 
    { 
     this.Url = url; 
     // plus set credentials, etc. 
    } 

    [SoapDocumentMethod("{service url}", RequestNamespace="{namespace}", ResponseNamespace="{namespace}", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] 
    public int MyMethod(string arg1) 
    { 
     object[] results = this.Invoke("MyMethod", new object[] { arg1 }); 
     return ((int)(results[0])); 
    } 
} 

Je ne l'ai pas testé ce code, mais je suppose qu'il doit fonctionner de façon autonome sans avoir à exécuter l'outil WSDL.

Le code que j'ai fourni est le code de l'appelant qui se connecte au service Web via un appel distant (même si, pour une raison quelconque, vous ne voulez pas qu'il soit distant.) La méthode Invoke prend en charge l'emballage comme un appel de savon. Le code de @Dave Ward est correct si vous voulez contourner l'appel de service Web via HTTP - tant que vous êtes en mesure de référencer la classe. Peut-être que le type interne n'est pas "MyService" - vous devrez inspecter le code du contrôle pour être sûr.

0

J'ai regardé en arrière à cette question et je pense que ce que vous affrontez est que le code ASMX sera construit dans une DLL avec un nom aléatoire dans le cadre de la compilation dynamique de votre site. Votre code pour rechercher le type, par défaut, recherchera uniquement son propre assembly (une autre DLL App_Code, selon l'apparence de l'erreur que vous avez reçue) et les bibliothèques de base. Vous pouvez fournir une référence d'assembly spécifique "TypeName, AssemblyName" à GetType() mais cela n'est pas possible dans le cas des assemblys générés automatiquement, qui ont de nouveaux noms après chaque recompilation.

Solution .... Je n'ai pas fait moi-même avant, mais je crois que vous devriez être en mesure d'utiliser quelque chose comme ceci:

System.Web.Compilation.BuildManager.GetType("MyService", true) 

comme BuildManager est conscient des DLL qu'il a créé et sait où regarder.

Je suppose que cela n'a vraiment rien à voir avec les services Web, mais si c'était votre propre code, Daren a raison sur les modèles de façade.

1

// Essayez ceci ->

Type t = System.Web.Compilation.BuildManager.GetType("MyServiceClass", true); 
    object act = Activator.CreateInstance(t);     
    object o = t.GetMethod("hello").Invoke(act, null);