Domanda

Supponiamo che io abbia un servizio Web ASMX, MyService.Il servizio ha un metodo, MyMethod.Potrei eseguire MyMethod sul lato server come segue:

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

Devo fare qualcosa di simile, con servizio e metodo non noti fino al runtime.

Presumo che la riflessione sia la strada da percorrere.Purtroppo faccio fatica a farlo funzionare.Quando eseguo questo codice:

Type.GetType("MyService", true);

Genera questo errore:

Impossibile caricare il tipo "MyService" dall'assembly "App_Web__ktsp_r0, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null".

Qualsiasi consiglio sarebbe apprezzato.

È stato utile?

Soluzione

Non sono sicuro che questo sarebbe il modo migliore per procedere.Il modo più ovvio per me sarebbe quello di effettuare una richiesta HTTP e chiamare il servizio web utilizzando un vero HTTP GET o POST.Utilizzando il tuo metodo, non sono del tutto sicuro di come imposteresti i dati che stai inviando al servizio web.Ho aggiunto del codice di esempio in 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()

Altri suggerimenti

// Prova questo ->

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

Anche se non so perché Reflection non funzioni per te lì (presumo che il compilatore stia creando una nuova classe dal tuo [WebService] annotazioni), ecco alcuni consigli che potrebbero risolvere il problema:

Mantieni il tuo servizio Web semplice, superficiale, in breve:Un'implementazione del modello di facciata.

Fai in modo che il tuo servizio deleghi il calcolo a una classe di implementazione, che dovrebbe essere facilmente richiamabile tramite Reflection.In questo modo, la tua classe WebService è solo una facciata per il tuo sistema: puoi anche aggiungere un gestore di posta elettronica, un frontend XML-RPC ecc., poiché la tua logica non è accoppiata al WebService, ma a un vero e proprio oggetto del livello aziendale.

Pensa alle classi WebService come oggetti del livello UI nella tua architettura.

Ecco una risposta rapida che qualcuno potrebbe probabilmente approfondire.

Quando utilizzi l'app di modelli WSDL (WSDL.exe) per generare wrapper di servizi, crea una classe di tipo SoapHttpClientProtocol.Puoi farlo anche 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]));
    }
}

Non ho testato questo codice ma immagino che dovrebbe funzionare in modo autonomo senza dover eseguire lo strumento WSDL.

Il codice che ho fornito è il codice chiamante che si collega al servizio web tramite una chiamata remota (anche se, per qualsiasi motivo, non vuoi che sia remoto). Il metodo Invoke si occupa di impacchettarlo come un Chiamata al sapone.Il codice di @Dave Ward è corretto se desideri ignorare la chiamata al servizio Web tramite HTTP, purché tu sia effettivamente in grado di fare riferimento alla classe.Forse il tipo interno non è "MyService": dovresti controllare il codice del controllo per saperlo con certezza.

@Kibbee:Devo evitare il calo delle prestazioni HTTP.Non sarà una chiamata remota, quindi tutto ciò ha aggiunto un sovraccarico Dovrebbe essere inutile.

@Daren:Sono assolutamente d'accordo con quella filosofia di design.Il problema qui è che non avrò il controllo del servizio o della sua logica aziendale sottostante.

Questo è per un controllo del server che dovrà essere eseguito rispetto a un servizio/metodo arbitrario, ortogonalmente al modo in cui viene implementato il servizio web stesso.

Anche se non posso dirlo dal tuo post:

Una cosa da tenere a mente è che se usi la riflessione, devi creare un'istanza della classe del servizio web generata automaticamente (quella creata dal WSDL del tuo servizio web).Non creare la classe responsabile del lato server del servizio.

Quindi, se hai un webservice

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

non puoi fare riferimento a quell'assembly nel tuo client e fare qualcosa del tipo:

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

@Radu:Sono in grado di creare un'istanza e chiamare il metodo esattamente in questo modo.Ad esempio, se ho questo 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";
  }
}

Sono in grado di chiamarlo dal codebehind di una pagina ASPX in questo modo:

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

Stai dicendo che non dovrebbe funzionare?

Ho ripensato a questa domanda e penso che quello che stai affrontando sia che il codice ASMX verrà integrato in una DLL con un nome casuale come parte della compilazione dinamica del tuo sito.Il codice per cercare il tipo, per impostazione predefinita, cercherà solo il proprio assembly (un'altra DLL App_Code, dall'aspetto dell'errore ricevuto) e le librerie principali.È possibile fornire un riferimento all'assembly specifico "TypeName, AssemblyName" a GetType() ma ciò non è possibile nel caso degli assembly generati automaticamente, che hanno nuovi nomi dopo ogni ricompilazione.

Soluzione....Non l'ho mai fatto prima, ma credo che dovresti essere in grado di usare qualcosa del genere:

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

poiché BuildManager è a conoscenza delle DLL che ha creato e sa dove cercare.

Immagino che questo non abbia davvero a che fare con i servizi Web, ma se fosse il tuo codice, Daren ha ragione riguardo ai modelli di facciata.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top