Используя отражение для вызова веб-службы ASP.NET
-
09-06-2019 - |
Вопрос
Допустим, у меня есть веб-сервис 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, которые он создал, и знает, где искать.
Я предполагаю, что это действительно не имеет отношения к веб-сервисам, но если бы это был ваш собственный код, Дарен был прав насчет шаблонов фасадов.