Pregunta

Digamos que tengo un servicio web ASMX, MyService.El servicio tiene un método, MyMethod.Podría ejecutar MyMethod en el lado del servidor de la siguiente manera:

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

Necesito hacer algo similar, con el servicio y el método desconocidos hasta el tiempo de ejecución.

Supongo que la reflexión es la forma de hacerlo.Desafortunadamente, me está costando hacerlo funcionar.Cuando ejecuto este código:

Type.GetType("MyService", true);

Lanza este error:

No se pudo cargar el tipo 'MyService' desde el ensamblado 'App_Web__ktsp_r0, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.

Se agradecería cualquier orientación.

¿Fue útil?

Solución

No estoy seguro de si esta sería la mejor manera de hacerlo.La forma más obvia para mí sería realizar una solicitud HTTP y llamar al servicio web mediante un HTTP GET o POST real.Usando su método, no estoy del todo seguro de cómo configuraría los datos que envía al servicio web.Agregué un código de muestra 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()

Otros consejos

// Prueba esto ->

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

Aunque no sé por qué Reflection no funciona allí (supongo que el compilador podría estar creando una nueva clase a partir de su [WebService] anotaciones), aquí hay algunos consejos que podrían resolver su problema:

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

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

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

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.También puedes hacerlo manualmente:

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 imagino que debería funcionar de forma independiente sin tener que ejecutar la herramienta WSDL.

El código que proporcioné 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 no desea que sea remoto). El método Invoke se encarga de empaquetarlo como un 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.Quizás el tipo interno no sea "MyService"; tendría que inspeccionar el código del control para estar seguro.

@Kibbee:Necesito evitar el impacto en el rendimiento de HTTP.No será una llamada remota, por lo que todo eso agregará gastos generales. debería ser innecesario.

@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 un control de servidor que deberá ejecutarse contra un servicio/método arbitrario, de forma ortogonal a cómo se implementa el servicio web en sí.

Aunque no puedo decirlo por tu publicación:

Una cosa a tener en cuenta es que si usa la reflexión, necesita crear una instancia de la clase de servicio web generada automáticamente (la que se crea a partir del WSDL de su servicio web).No cree la clase que sea responsable del lado del servidor del servicio.

Entonces, si tienes un servicio web

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

no puedes hacer referencia a ese ensamblaje en tu cliente y hacer algo como:

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

@Radu:Puedo crear una instancia y llamar al método exactamente así.Por ejemplo, si tengo este 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";
  }
}

Puedo llamarlo desde el código subyacente de una página ASPX de esta manera:

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

¿Estás diciendo que eso no debería funcionar?

Volví a revisar esta pregunta y creo que lo que enfrenta es que el código ASMX se integrará 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, de forma predeterminada, solo buscará su propio ensamblado (otra DLL App_Code, por el aspecto del error que recibió) y bibliotecas principales.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 antes, pero creo que deberías poder usar algo como esto:

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

ya que BuildManager conoce las DLL que ha creado y sabe dónde buscar.

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 Facade.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top