2008-09-15 15 views
7

Supongamos que tengo un servicio web ASMX, MyService. El servicio tiene un método, MyMethod. Podría ejecutar MiMetodo en el lado del servidor de la siguiente manera:Usar la reflexión para llamar a un servicio web ASP.NET

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

que necesito hacer similar, con el servicio y el método no se conoce hasta que el tiempo de ejecución.

Supongo que la reflexión es la forma de hacerlo. Lamentablemente, estoy teniendo dificultades para que funcione. Cuando ejecuto este código:

Type.GetType("MyService", true); 

Se lanza este error:

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

Cualquier orientación sería apreciada.

Respuesta

2

No estoy seguro de si esta sería la mejor manera de hacerlo. La forma más obvia para mí sería hacer una solicitud HTTP y llamar al servicio web utilizando un HTTP GET o POST real. Usando su método, no estoy del todo seguro de cómo configurar los datos que está enviando al servicio web. He añadido un código de ejemplo en 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

Aunque no sé qué reflexión no está trabajando para usted allí (supongo que el compilador podría ser la creación de una nueva clase de sus [WebService] anotaciones), aquí es un consejo que podría resolver su problema:

Mantenga su WebService simple, superficial, en resumen: una implementación del patrón de fachada.

Haga que su servicio delegue el cálculo a una clase de implementación, que debería ser fácilmente llamable a través de Reflection. De esta forma, su clase de WebService es solo una fachada para su sistema; incluso puede agregar un manejador de correo electrónico, un frontend XML-RPC, etc., ya que su lógica no está acoplada al WebService, sino a un objeto de capa empresarial real.

Considere las clases de WebService como objetos de la capa UI en su arquitectura.

0

@Kibbee: Necesito evitar el golpe de rendimiento HTTP. No será una llamada remota, por lo tanto, toda esa sobrecarga añadida debería ser innecesaria.

@Daren: Definitivamente estoy de acuerdo con esa filosofía de diseño. El problema aquí es que no voy a tener el control del servicio ni de su lógica empresarial subyacente.

Esto es para a server control que deberá ejecutar contra un servicio/método arbitrario, ortogonalmente a cómo se implementa el servicio web en sí.

0

Aunque no puedo decir de su mensaje:

Una cosa a tener en cuenta es que si se utiliza la reflexión, es necesario crear una instancia de la clase de servicio web autogenerado (el creado a partir de WSDL del servicio web). No cree la clase que es responsable del lado del servidor del servicio.

Así que si usted tiene un servicio web

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

no se puede hacer referencia a que el montaje en su cliente y hacer algo como:

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

@Radu: Soy capaz de crear una instancia y llamada el método exactamente así. Por ejemplo, si tengo esta 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"; 
    } 
}

soy capaz de llamar desde el código subyacente de una página ASPX como esto:

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

¿Quiere decir que no hay que trabajar?

+0

Wil "trabajo", pero probablemente no lo quiere instalar. Devolverá la cadena "Hello World", pero el método se ejecutará localmente en el cliente y no de forma remota en el servidor. – Radu094

+0

Eso no es lo que sucede. Intentalo. –

1

Aquí hay una respuesta rápida que alguien probablemente pueda ampliar.

Cuando utiliza la aplicación de plantillas WSDL (WSDL.exe) para generar contenedores de servicios, crea una clase de tipo SoapHttpClientProtocol. Puede hacerlo de forma manual, también:

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

No he probado este código, pero me imagino que debería funcionar independiente sin tener que ejecutar la herramienta WSDL.

El código que he proporcionado es el código de la persona que llama que se conecta al servicio web a través de una llamada remota (incluso si por alguna razón, realmente no desea que sea remota). El método Invoke se ocupa de empaquetarlo como una llamada de jabón. El código de @Dave Ward es correcto si desea omitir la llamada al servicio web a través de HTTP, siempre que pueda hacer referencia a la clase. Tal vez el tipo interno no es "MiServicio". Tendría que inspeccionar el código del control para estar seguro.

0

Volví a mirar esta pregunta y creo que lo que enfrenta es que el código ASMX estará integrado en una DLL con un nombre aleatorio como parte de la compilación dinámica de su sitio. Su código para buscar el tipo buscará de manera predeterminada su propio ensamblado (otro DLL App_Code, por el aspecto del error que recibió) y las bibliotecas centrales. Puede proporcionar una referencia de ensamblado específica "TypeName, AssemblyName" a GetType() pero eso no es posible en el caso de los ensamblados generados automáticamente, que tienen nuevos nombres después de cada recompilación.

solución .... No he hecho esto por mí mismo antes, pero creo que usted debería ser capaz de usar algo como esto:

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

como el BuildManager es consciente de las DLL que ha creado y sabe dónde mirar

Supongo que esto realmente no tiene que ver con los servicios web, pero si fuera su propio código, Daren tiene razón sobre los patrones de fachada.

1

// probar este ->

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