Как я могу создать запрос SOAP из типа объекта?
Позвольте мне сначала описать мое намерение, а затем перейти к моему вопросу.
Я пытаюсь создать систему, которая взаимодействует с SOAP-сервисом, где SOAP-запрос несколько неизвестен во время выполнения. В конечном итоге мне нужно сгенерировать SOAP-запрос из неизвестных объектов. Я буду динамически создавать объекты с нуля с соответствующими атрибутами и свойствами, а затем передам это методу "запроса" моей службы для отправки в службу SOAP. Вот код, с которым я работал, а затем полученная ошибка.
Клиент SOAP:
/// <summary>
/// GOSService proxy class
/// </summary>
[DebuggerStepThroughAttribute()]
[DesignerCategoryAttribute("code")]
[WebServiceBindingAttribute(Name = "ServiceSoapBinding", Namespace = "service.domain.com", ConformsTo = WsiProfiles.None)]
[SoapRpcService(RoutingStyle = SoapServiceRoutingStyle.RequestElement)]
public partial class TestService : SoapHttpClientProtocol
{
/// <summary>
/// Initializes a new instance of the TestService class.
/// </summary>
public TestService()
{
this.Url = "https://restsv01.domain.com/ServiceTest/services/TestService";
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(OnRemoteCertificateValidationCallback);
}
/// <summary>
/// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication.
/// </summary>
/// <param name="sender">An object that contains state information for this validation.</param>
/// <param name="certificate">The certificate used to authenticate the remote party.</param>
/// <param name="chain">The chain of certificate authorities associated with the remote certificate.</param>
/// <param name="sslPolicyErrors">One or more errors associated with the remote certificate.</param>
/// <returns>A Boolean value that determines whether the specified certificate is accepted for authentication.</returns>
private bool OnRemoteCertificateValidationCallback(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}
/// <summary>
///
/// </summary>
/// <param name="order"></param>
/// <returns></returns>
[SoapRpcMethodAttribute("", RequestNamespace = "service.domain.com", ResponseNamespace = "service.domain.com")]
[SampleSoap.LoggerSoapExtensionAttribute]
[return: SoapElementAttribute("requestReturn")]
public object request(object parm)
{
object[] results = this.Invoke("request", new object[] { parm });
return ((object)(results[0]));
}}
Тестовая модель: (Предварительно определенных моделей не будет, они будут генерироваться динамически. Но для целей тестирования я использую эту модель для тестирования)
[SerializableAttribute()]
[DebuggerStepThroughAttribute()]
[DesignerCategoryAttribute("code")]
[SoapTypeAttribute(Namespace = "http://entity.domain.com")]
public class ParentNode
{
private string nameField = "1";
[SoapElementAttribute(IsNullable = true)]
public string Name
{
get { return this.nameField; }
set { this.nameField = value; }
}
}
Тестовый код вызова:
Services.Soap.Models.ParentNode parent = new Services.Soap.Models.ParentNode();
parent.Name = "John Doe";
Services.Soap.TestService service = new Services.Soap.TestService();
object resp = service.request(parent);
Когда я запускаю этот код, в этой строке возникает ошибка:
object[] results = this.Invoke("request", new object[] { parm });
Это ошибка:
Тип Services.Soap.Models+ParentNode не ожидался. Используйте атрибут XmlInclude или SoapInclude, чтобы указать типы, которые не известны статически.
Теперь, если я изменю параметр метода "request" службы на строгий тип, запрос будет хорошо скомпонован и передан службе SOAP следующим образом.
public object request(ParentNode parm)
Я пробовал, вероятно, 50 вещей, чтобы заставить это работать, включая передачу Type в качестве параметра в метод запроса и создание "динамического" экземпляра объекта для передачи.
public object request(object parm, Type t)
{
dynamic converted = Convert.ChangeType(parm, t);
object[] results = this.Invoke("request", new object[] { converted });
return ((object)(results[0]));
}
Это не сработало, потому что "преобразованный" все еще считался типом объекта.
Я также пытался перехватить мыльный конверт в методе "GetWriterForMessage", чтобы я мог создать свой собственный конверт, но я не смог его использовать.
Итак, мой вопрос, как я могу получить SOAP-запрос для успешной сборки с параметром типа объекта? Есть ли другой подход, который я должен использовать, чтобы моя архитектура работала правильно?
1 ответ
Ваше описание системы, которую вы внедряете, мне не совсем понятно. Вы упоминаете, что будете отправлять "динамические" запросы на SOAP-сервер? Или вы создаете какой-то сервис с "динамическими" операциями. Эти детали немного мутны для меня, но я записал некоторые мысли.
Короче говоря, вы открываете для себя мир боли, если хотите сделать это в SOAP. REST может подойти лучше, так как у него нет WSDL, но если вы используете WADL, RAML и эти новые стандарты, ваш пробег может варьироваться. Я не собираюсь даже пытаться ответить на технический вопрос для вас, но постараюсь, чтобы вы поняли, почему это билет в один конец в ад.
Эта реализация действительно нарушает концепции SOA (в частности, стандартизированный контракт на обслуживание), что может оказаться неприменимым в вашем случае, поскольку простая реализация динамического WSDL с неизвестным содержимым дисквалифицирует архитектуру как НЕ SOA. Это также противоречит всему смыслу WSDL. WSDL - это определение интерфейса в XML. Таким образом, для динамического сервиса потребуется динамический интерфейс, который затем квалифицирует его как НЕ интерфейс. Таким образом, когда вы используете тип объекта в качестве параметра, WSDL и интерфейс не совпадают.
Когда другие системы используют ваши сервисы SOAP, они будут делать это на основе опубликованного WSDL. Если WSDL изменится, их программы прервутся, поскольку определение или WSDL не будут соответствовать сгенерированным ими типам данных. Служба, работающая по протоколу HTTP, получающая запросы и отправляющая ответы и не имеющая WSDL, НЕ является службой SOAP, это служба на основе XML, использующая порты HTTP. Они принципиально разные. У вашего поставщика услуг, т.е. службы SOAP, от которой вы запрашиваете данные, нет WSDL? Если нет, то это не те дроиды, которых вы ищете:)
Интерфейс - это согласованный контракт, который приложения могут использовать для запроса сервиса. По сути, вы говорите о структурированных и неструктурированных объектах данных (по крайней мере, во время выполнения).
Если вы хотите этот тип шаблона, вам нужно взглянуть на архитектуру подписки на публикацию, похожую на MQTT, которая проста в использовании, или другой пример - JMS с темами.
Если вы используете веб-службу, о которой вы упомянули, будет WSDL, который ваше приложение.Net может использовать для генерации типов данных и связанных классов C#. Классы будут включать в себя как передаваемые данные, так и операции, предоставляемые сервисом.
В официальных мирах SOAP не существует такого понятия, как динамический сервис, поскольку он нарушает всю парадигму того, что мы согласны как сервер и клиент обмениваться данными через эту форму XML во время операций.