Использование рефлексии для вызова веб-службы ASP.NET - PullRequest
7 голосов
/ 15 сентября 2008

Скажем, у меня есть веб-сервис 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'.

Любое руководство будет оценено.

Ответы [ 8 ]

2 голосов
/ 08 апреля 2009

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

    Type t = System.Web.Compilation.BuildManager.GetType("MyServiceClass", true);
    object act = Activator.CreateInstance(t);                
    object o = t.GetMethod("hello").Invoke(act, null);
2 голосов
/ 15 сентября 2008

Я не уверен, что это будет лучший способ сделать это. Самый очевидный способ для меня - это сделать 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()
1 голос
/ 15 сентября 2008

Вот быстрый ответ, который кто-то может расширить.

Когда вы используете приложение шаблонов 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 заботится об упаковке это как вызов мыла. Код @Dave Ward верен, если вы хотите обойти вызов веб-службы через HTTP - до тех пор, пока вы действительно сможете ссылаться на класс. Возможно, внутренний тип не «MyService» - вам нужно проверить код элемента управления, чтобы точно знать.

1 голос
/ 15 сентября 2008

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

Сделайте ваш WebService простым, поверхностным, вкратце: реализация шаблона фасада .

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

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

0 голосов
/ 18 сентября 2008

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

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

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

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

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

0 голосов
/ 15 сентября 2008

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

Вы говорите, что это не должно работать?

0 голосов
/ 15 сентября 2008

Хотя из вашего поста не могу сказать:

Следует помнить одну вещь: если вы используете отражение, вам нужно создать экземпляр автоматически сгенерированного класса веб-сервиса (тот, который создан из 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();
0 голосов
/ 15 сентября 2008

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

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

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

...