Вот ситуация. У меня есть последовательность из 12 задач интеграции, которые нужно запускать каждые 15 минут, большинство из них на самом деле считывают что-то с сервера оракула и отправляют это в веб-службу. Я создал порт как для оракула, так и для веб-службы, а также создал основную оркестровку, которая зацикливается каждые 15 минут и вызывает другие оркестровки, которые будут выполнять свои задачи.
Теперь моя проблема заключается в том, что эти оркестровки не вызываются прибытием сообщения, и мне нужно создать сообщение, которое я отправлю на порт оракула. Тот, который будет выглядеть так:
Я знаю, какими будут значения узла, но я не знаю, как построить сообщение, кроме как использовать "магические строки" и конкатенировать строки, которые я буду загружать в xmlDoc с помощью LoadXml, а затем назначать это параметрам сообщения, которые мне бы очень хотелось избегать по многим причинам (начиная с изменения пространства имен в будущем). Есть ли способ для оркестровки создать "пустое" сообщение, которое я затем заполню?
Может быть, вопрос очень простой, и я не вижу дерева из леса, но все образцы, которые я видел в сети, упрощены (то есть кто-то просто бросает готовый xml в отслеживаемую папку, чтобы вызвать оркестрацию) и не помогают мне .
Вот решение, которое я реализовал для аналогичной проблемы: как предлагает Хью, я использую помощник, наследуемый от XmlDocument.
Класс шаблона Xml
using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Xml;
namespace Acme
{
[Serializable]
public class ResourceXmlDocument : XmlDocument
{
public ResourceXmlDocument(Type assemblyType, string resourceName, QueryValues queryValues)
{
try
{
Assembly callingAssembly = Assembly.GetAssembly(assemblyType);
if (null == callingAssembly)
{
throw new ResourceException("GetExecutingAssembly returned null");
}
Stream resourceStream = callingAssembly.GetManifestResourceStream(resourceName);
Load(resourceStream);
if (null == queryValues)
{
throw new ResourceException("queryValues not initialized");
}
if (queryValues.Keys.Count < 1)
{
throw new ResourceException("queryValues.Keys must have at least one value");
}
foreach (string querycondition in queryValues.Keys)
{
XmlNode conditionNode = this.SelectSingleNode(querycondition);
if (null == conditionNode)
{
throw new ResourceException(string.Format(CultureInfo.InvariantCulture, "Condition: '{0}' did not return a XmlNode", querycondition));
}
XmlAttribute valueAttribute = conditionNode.Attributes["value"];
if (null == valueAttribute)
{
throw new ResourceException(string.Format(CultureInfo.InvariantCulture, "Condition: '{0}' with attribute 'value' did not return an XmlAttribute ", querycondition));
}
valueAttribute.Value = queryValues[querycondition];
}
}
catch (Exception ex)
{
throw new ResourceException(ex.Message);
}
}
}
}
Конечно, мой пример предназначен для установки фиксированного атрибута value, поэтому вам придется адаптировать его к вашим потребностям.
Вспомогательный класс QueryValues
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Acme
{
[Serializable]
public class QueryValues : Dictionary<string, string>
{
public QueryValues()
{
}
protected QueryValues(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}
Шаблон Xml
Добавьте документ Xml MyTemplate.xml в свой проект и измените действие компиляции на Embedded Resource, чтобы ResorceXmlDocument мог загрузить его через Reflection.
переменная *resourceXmlDoc* типа `Acme.ResourceXmlDocument`
сообщение типа `MySchemaType`
Объединение в форму назначения сообщений
внутри формы Construct Message, создающей Message MyRequest типа MySchemaType
queryValues = new Acme.QueryValues();
queryValues.Add("//MyNodeName[@tablename='MyTableName' and @fieldname='MyFieldName']", "MyValueToSet");
resourceXmlDoc = new Acme.ResourceXmlDocument(typeof(Acme.MySchemaType), "MyTemplate.xml", queryValues);
MyRequest = resourceXmlDoc;
Я храню ResourceXmlDocument и QueryValues в служебной библиотеке и ссылаюсь на нее из любого проекта BizTalk, который мне нужен. Различные документы шаблона Xml встроены в соответствующую сборку BizTalk.
EDIT by OP: На самом деле единственный способ заставить это работать - также реализовать ISerializable на ResourceXmlDocument и сохранить сообщение, используя пользовательскую сериализацию OuterXml. XmlDocument в базе просто не сериализуем сам по себе. Если есть другой подход, не стесняйтесь редактировать его.
[Serializable]
public class ResourceXmlDocument : XmlDocument, ISerializable
{
...
protected ResourceXmlDocument(SerializationInfo info, StreamingContext context)
{
if (info == null) throw new System.ArgumentNullException("info");
Load(info.GetString("content"));
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null) throw new System.ArgumentNullException("info");
info.AddValue("content", this.OuterXml);
}
Ответ 2 · рейтинг 2 · tom redfern
Создайте статическую вспомогательную функцию, которая возвращает тип XmlDocument. Вызовите эту функцию из формы назначения.
Внутри вспомогательной функции вы можете загрузить настройки (пространство имен и т. д. или даже полное сообщение) из файла конфигурации или текстового файла.
Для лучшей практики вы должны хранить эту конфигурацию в SSO. Если вам нужна помощь с этим, дайте мне знать.
Ответ 3 · рейтинг 1 · StuartLC
Йосси Дахан сравнивает эти методы (сопоставление, назначение и использование недокументированного API) здесь
Метод API использует Microsoft.BizTalk.Component.Interop.DocumentSpec - ссылки здесь и здесь, но, как упоминает Йосси, намного медленнее чем карты или XmlDocument.LoadXml
Несколько замечаний по использованию:
Сборка - это TestSchema, версия = 1.0.0.0, культура = нейтральная, publicKeyToken = xxxxxxxxxxxxxxxx";
имя_схемы - TestSchema.MyTestSchema[+myRootNode1]
Примечание зависит от версии - если версия сборки изменится, создание не удастся, если не обновить строку версии.
Новое сообщение, созданное таким образом, не обязательно допустимо для XSD. например DateTimes и Ints будут просто пустыми элементами, даже если они могут быть нулевыми (и это не установит nillable=true в XML)
Ответ 4 · TJ Amas
Рассматривали ли вы возможность использования формы преобразования для создания экземпляра схемы, которую вы хотите отправить в ORACLE?
Это одна из альтернатив созданию сообщения в форме назначения сообщения. Дайте мне знать, если вам нужна более подробная информация!