Вопрос

Допустим, у меня есть веб-сервис ASMX, MyService.У сервиса есть метод, myMethod.Я мог бы выполнить myMethod на стороне сервера следующим образом:

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

Мне нужно сделать аналогично, с сервисом и методом, неизвестными до времени выполнения.

Я предполагаю, что размышление - это способ добиться этого.К сожалению, мне трудно заставить это работать.Когда я выполняю этот код:

Type.GetType("MyService", true);

Он выдает эту ошибку:

Не удалось загрузить тип 'MyService' из сборки 'App_Web__ktsp_r0, версия=0.0.0.0, Культура = нейтральная, PublicKeyToken=null'.

Мы были бы признательны за любые рекомендации.

Это было полезно?

Решение

Я не уверен, что это был бы лучший способ сделать это.Наиболее очевидным способом для меня было бы сделать HTTP-запрос и вызвать веб-сервис, используя фактический HTTP GET или POST.Используя ваш метод, я не совсем уверен, как бы вы настроили данные, которые отправляете в веб-службу.Я добавил несколько примеров кода в 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()

Другие советы

// Попробуй это ->

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

Хотя я не знаю, почему отражение у вас там не работает (я предполагаю, что компилятор может создавать новый класс из вашего [WebService] аннотации), вот несколько советов, которые могли бы решить вашу проблему:

Сделайте свой веб-сервис простым, неглубоким, короче говоря:Реализация шаблона Фасада.

Сделайте так, чтобы ваш сервис делегировал вычисления классу реализации, который должен быть легко вызываем через Отражение.Таким образом, ваш класс WebService является всего лишь интерфейсом для вашей системы - вы даже можете добавить обработчик электронной почты, интерфейс XML-RPC и т.д., поскольку ваша логика связана не с WebService, а с реальным объектом бизнес-уровня.

Думайте о классах веб-сервисов как об объектах уровня пользовательского интерфейса в вашей архитектуре.

Вот краткий ответ, который кто-нибудь, вероятно, сможет дополнить.

Когда вы используете приложение шаблонов WSDL (WSDL.exe) для создания оболочек служб, оно создает класс типа SoapHttpClientProtocol.Вы тоже можете сделать это вручную:

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

Я не тестировал этот код, но я полагаю, что он должен работать автономно, без необходимости запускать инструмент WSDL.

Код, который я предоставил, - это код вызывающего абонента, который подключается к веб-службе через удаленный вызов (даже если по какой-либо причине вы на самом деле не хотите, чтобы он был удаленным). Метод Invoke заботится о том, чтобы упаковать его в виде вызова Soap.Код @Dave Ward верен, если вы хотите обойти вызов веб-службы через HTTP - при условии, что вы действительно можете ссылаться на класс.Возможно, внутренний тип не является "MyService" - вам нужно будет проверить код элемента управления, чтобы знать наверняка.

@Кибби:Мне нужно избежать снижения производительности HTTP.Это не будет удаленный вызов, так что все это добавит накладных расходов следует быть ненужным.

@Дарен:Я определенно согласен с этой философией дизайна.Проблема здесь в том, что я не собираюсь контролировать сервис или лежащую в его основе бизнес-логику.

Это для серверный элемент управления это нужно будет выполнить с произвольным сервисом / методом, ортогонально тому, как реализован сам веб-сервис.

Хотя я не могу судить по вашему сообщению:

Следует иметь в виду одну вещь: если вы используете отражение, вам необходимо создать экземпляр автоматически сгенерированного класса webservice (того, который создается из WSDL вашего веб-сервиса).Не создавайте класс, который отвечает за серверную часть службы.

Итак, если у вас есть веб-сервис

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

вы не можете ссылаться на эту сборку в своем клиенте и делать что-то вроде:

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

@Раду:Я могу создать экземпляр и вызвать метод точно так же.Например, если у меня есть этот 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";
  }
}

Я могу вызвать это из кода ASPX-страницы следующим образом:

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

Ты хочешь сказать, что это не должно сработать?

Я еще раз просмотрел этот вопрос и думаю, что вы столкнулись с тем, что код ASMX будет встроен в библиотеку DLL со случайным именем как часть динамической компиляции вашего сайта.Ваш код для поиска типа по умолчанию будет выполнять поиск только в своей собственной сборке (другая библиотека DLL App_Code, судя по полученной вами ошибке) и основных библиотеках.Вы могли бы предоставить конкретную ссылку на сборку "TypeName, AssemblyName" для GetType(), но это невозможно в случае автоматически генерируемых сборок, которые имеют новые имена после каждой перекомпиляции.

Решение....Я сам раньше этого не делал, но я считаю, что вы должны быть в состоянии использовать что-то подобное:

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

поскольку BuildManager знает о библиотеках DLL, которые он создал, и знает, где искать.

Я предполагаю, что это действительно не имеет отношения к веб-сервисам, но если бы это был ваш собственный код, Дарен был прав насчет шаблонов фасадов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top