Динамически вызывать сервис SOAP из собственного языка сценариев - PullRequest
1 голос
/ 11 августа 2010

У моего приложения есть собственный язык сценариев, от которого я не могу избавиться (написано много пользовательских сценариев).Теперь мои клиенты спрашивают, можно ли вызвать сервис SOAP из этого языка сценариев.Конечно, сервис SOAP, который необходимо вызвать, будет отличаться для каждого клиента.Это оставляет мне несколько вариантов:

  • Использование утилиты WSDL для генерации клиентских прокси-серверов SOAP и помещения специфичной для клиента логики в мое приложение
  • Использование утилиты WSDL для генерацииКлиентские прокси-серверы SOAP, ориентированные на клиента, помещают клиентскую логику в специфичные для клиента DLL-библиотеки и предусматривают систему плагинов, в которой приложение может вызывать плагин универсальным образом
  • Создать универсальный модуль, который динамическигенерирует вызов SOAP

Первые 2 варианта не являются реальной альтернативой в моем случае, так как я не хочу никакой пользовательской логики в приложении или пользовательских DLL.

Для меня третий вариант, в долгосрочной перспективе, является лучшим, поскольку он позволяет моим коллегам-консультантам вызывать службу SOAP через мой язык сценариев без каких-либо специфических для клиента разработок.Динамическое добавление функций к моему языку сценариев не является проблемой, генерация динамического вызова SOAP:

Я начал с просмотра вывода утилиты WSDL.Потом я начал убирать вещи, пока они больше не работали.Следующий фрагмент кода по-прежнему работает:

[System::CodeDom::Compiler::GeneratedCodeAttribute(L"wsdl", L"4.0.30319.1"), 
System::Diagnostics::DebuggerStepThroughAttribute, 
System::ComponentModel::DesignerCategoryAttribute(L"code"),
System::Web::Services::WebServiceBindingAttribute(Name=L"MyOwnScriptingSoapClient", Namespace=L"http://microsoft.com/webservices/")]
public ref class MyWebService : public System::Web::Services::Protocols::SoapHttpClientProtocol
   {
    public:
      MyWebService() {}

    public:
      [System::Web::Services::Protocols::SoapDocumentMethodAttribute(L"http://microsoft.com/webservices/GetPrimeNumbers", RequestNamespace=L"http://microsoft.com/webservices/", 
       ResponseNamespace=L"http://microsoft.com/webservices/", Use=System::Web::Services::Description::SoapBindingUse::Literal, ParameterStyle=System::Web::Services::Protocols::SoapParameterStyle::Wrapped)]
      System::String^  GetPrimeNumbers(System::Int32 max);
  };

inline System::String^  MyWebService::GetPrimeNumbers(System::Int32 max) {
    cli::array< System::Object^  >^  results = this->Invoke(L"GetPrimeNumbers", gcnew cli::array< System::Object^  >(1) {max});
    return (cli::safe_cast<System::String^  >(results[0]));
}

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

Добавление общего метода, подобного этому, по-прежнему работает:

...
[System::Web::Services::Protocols::SoapDocumentMethodAttribute(L"http://microsoft.com/webservices/GetPrimeNumbers", RequestNamespace=L"http://microsoft.com/webservices/", 
 ResponseNamespace=L"http://microsoft.com/webservices/", Use=System::Web::Services::Description::SoapBindingUse::Literal, ParameterStyle=System::Web::Services::Protocols::SoapParameterStyle::Wrapped)]
cli::array< System::Object^  >^  CallWs(cli::array< System::Object^  >^ args);
...

inline cli::array< System::Object^  >^  MyWebService::CallWs(cli::array< System::Object^  >^ args) {
    cli::array< System::Object^  >^  results = this->Invoke(L"GetPrimeNumbers", args);
    return results;

Но как только я удаляю метод GetPrimeNumbers, вызов больше не работает и выдает следующую ошибку:

Unhandled Exception: System.ArgumentException: GetPrimeNumbers Web Service method name is not valid.
   at System.Web.Services.Protocols.SoapHttpClientProtocol.BeforeSerialize(WebRequest request, String methodName, Object[] parameters)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
   at MyWebService.CallWs(Object[] args)
   at main(Int32 argc, SByte** argv)
   at _mainCRTStartup()

Кроме того, изменение имени веб-службы в атрибуте SoapDocumentMethodAttribute (например, на GetPrimo) выдает такую ​​же ошибку.

Поэтому мои вопросы:

  • Есть ли смысл продолжать идти по этому пути, то есть смотреть на сгенерированную WSDL-логику, пытаясь «обобщить» вызов (любой) службы SOAP, или это просто никогда не сработает?
  • Есть ли другие хорошие способыгенерации вызова SOAP динамическим способом (с использованием .Net)?
  • Или это единственный метод для создания XML (Soap Envelope) самостоятельно для выполнения вызова SOAP?
  • Есть ли шансеПример кода, над которым я могу продолжать работать?

Заранее спасибо, Патрик

Ответы [ 3 ]

1 голос
/ 11 августа 2010

Вы можете попытаться сгенерировать динамический код на лету, используя компилятор сборки.
Либо непосредственно из кода (используя провайдера кода, например http://msdn.microsoft.com/en-us/library/microsoft.csharp.csharpcodeprovider.aspx), либо напрямую создав класс (см. ).http://msdn.microsoft.com/en-us/library/system.codedom.compiler.codedomprovider.aspx для примера)

Генерация кода может быть выполнена несколькими способами:

  • сгенерировать код вручную (в C ++)
  • , оборачивая wsdl.exe. Может быть сложно, потому что я думаю, что вы не имеете права распространять exe, ваши клиенты должны будут загрузить SDK.
  • Реализовать некоторые WSDL-подобные функциональные возможности, как этот парень: http://www.west -wind.com/Weblog/posts/625014.aspx
  • Используйте библиотеку, которая делает то же самое для вас: http://www.wcfstorm.com/wcf/home.aspx (коммерческая)
1 голос
/ 11 августа 2010

На языке сценариев можно указать механизм вызова внешней сборки .NET. Вы можете использовать отражение, чтобы найти функцию и вызвать их. Подобно тому, как плагины работают во многих приложениях.

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

Или, если вы не хотите полагаться на то, что ваш клиент пишет .NET-сборки, вы можете сами генерировать SOAP-запросы, спрашивая у пользователя имя сообщения SOAP, имена параметров, их тип и значения, URL службы и т. Д. это не будет легким путем, и я признаю, что никогда сам этого не делал.

0 голосов
/ 11 августа 2010

Не зная возможностей вашего языка сценариев, трудно ответить.

Одной из идей может быть создание более мощной службы на другом языке, имеющей фабричный шаблон для вызова службы соответствующих клиентов и возврата к информации вашего сценария в формате, который не зависит от клиента.

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

Может быть, что-то вроде Managed Extensibility Framework (или MEF для краткости) может работать и для вас.

...