Pergunta

Digamos que eu tenha um serviço web ASMX, MyService.O serviço possui um método, MyMethod.Eu poderia executar MyMethod no lado do servidor da seguinte forma:

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

Preciso fazer o mesmo, com serviço e método desconhecidos até o tempo de execução.

Presumo que a reflexão seja a maneira de fazer isso.Infelizmente, estou tendo dificuldades para fazê-lo funcionar.Quando executo este código:

Type.GetType("MyService", true);

Isso gera este erro:

Não foi possível carregar o tipo 'MyService' do assembly 'App_Web__ktsp_r0, Versão=0.0.0.0, Culture=neutral, PublicKeyToken=null'.

Qualquer orientação seria apreciada.

Foi útil?

Solução

Não tenho certeza se essa seria a melhor maneira de fazer isso.A maneira mais óbvia para mim seria fazer uma solicitação HTTP e chamar o serviço da web usando um HTTP GET ou POST real.Usando seu método, não tenho certeza de como você configuraria os dados que está enviando para o serviço da web.Adicionei alguns exemplos de código em 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()

Outras dicas

//Tente isso ->

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

Embora eu não saiba por que o Reflection não está funcionando para você (presumo que o compilador possa estar criando uma nova classe a partir do seu [WebService] anotações), aqui estão alguns conselhos que podem resolver seu problema:

Mantenha seu WebService simples, superficial, resumindo:Uma implementação do Padrão Fachada.

Faça com que seu serviço delegue a computação para uma classe de implementação, que deve ser facilmente chamada por meio do Reflection.Dessa forma, sua classe WebService é apenas uma fachada para seu sistema - você pode até adicionar um manipulador de email, frontend XML-RPC etc., já que sua lógica não está acoplada ao WebService, mas sim a um objeto real da camada de negócio.

Pense nas classes WebService como objetos da camada UI em sua arquitetura.

Aqui está uma resposta rápida que alguém provavelmente pode expandir.

Quando você usa o aplicativo de modelo WSDL (WSDL.exe) para gerar wrappers de serviço, ele cria uma classe do tipo SoapHttpClientProtocol.Você também pode fazer isso 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]));
    }
}

Não testei esse código, mas imagino que ele deva funcionar de forma independente, sem a necessidade de executar a ferramenta WSDL.

O código que forneci é o código do chamador que se conecta ao serviço da Web por meio de uma chamada remota (mesmo que, por qualquer motivo, você não queira que seja remoto). O método Invoke se encarrega de empacotá-lo como um Chamada de sabonete.O código de @Dave Ward está correto se você deseja ignorar a chamada de serviço da web via HTTP - desde que você consiga fazer referência à classe.Talvez o tipo interno não seja "MyService" - você teria que inspecionar o código do controle para ter certeza.

@Kibbee:Preciso evitar o impacto no desempenho do HTTP.Não será uma chamada remota, então toda essa sobrecarga adicional deve ser desnecessário.

@Daren:Eu definitivamente concordo com essa filosofia de design.A questão aqui é que não terei controle do serviço ou de sua lógica de negócios subjacente.

Isso é para um controle de servidor que precisará ser executado em um serviço/método arbitrário, ortogonalmente à forma como o próprio serviço da web é implementado.

Embora eu não possa dizer pela sua postagem:

Uma coisa a ter em mente é que se você usar reflexão, precisará criar uma instância da classe de serviço web gerada automaticamente (aquela criada a partir do WSDL do seu serviço web).Não crie a classe responsável pelo lado servidor do serviço.

Então, se você tem um webservice

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

você não pode fazer referência a esse assembly em seu cliente e fazer algo como:

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

@Radu:Consigo criar uma instância e chamar o método exatamente assim.Por exemplo, se eu tiver 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";
  }
}

Consigo chamá-lo a partir do codebehind de uma página ASPX assim:

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

Você está dizendo que isso não deveria funcionar?

Analisei esta questão e acho que o que você está enfrentando é que o código ASMX será incorporado em uma DLL com um nome aleatório como parte da compilação dinâmica do seu site.Seu código para procurar o tipo irá, por padrão, pesquisar apenas seu próprio assembly (outra DLL App_Code, pela aparência do erro que você recebeu) e bibliotecas principais.Você poderia fornecer uma referência de assembly específica "TypeName, AssemblyName" para GetType(), mas isso não é possível no caso de assemblies gerados automaticamente, que possuem novos nomes após cada recompilação.

Solução....Eu não fiz isso antes, mas acredito que você deveria ser capaz de usar algo assim:

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

pois o BuildManager está ciente das DLLs que criou e sabe onde procurar.

Acho que isso realmente não tem a ver com serviços da Web, mas se fosse seu próprio código, Daren está certo sobre os padrões Facade.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top