Вот решение, которое я реализовал для аналогичной проблемы: как предлагает Хью, я использую помощник, унаследованный от 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.
<?xml version="1.0" encoding="utf-8" ?>
<root>
<SomeOtherNode>some (fixed) value</SomeOtherNode>
<MyNodeName tablename="MyTableName" fieldname="MyFieldName" value="0" />
<YetAnotherNode>
<SubNode>Foo</SubNode>
</YetAnotherNode>
</root>
Переменные и сообщения оркестровки
Вам нужно будет объявить
- переменная * queryValues * типа `Acme.QueryValues`
- переменная * resourceXmlDoc * типа `Acme.ResourceXmlDocument`
- сообщение типа `MySchemaType`
Собираем его вместе в форме назначения сообщения
внутри формы сообщения Construct, создающей сообщение 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
в утилите lib и ссылаюсь на нее из любого проекта BizTalk, который мне нужен. Различные документы шаблона Xml встроены в соответствующую сборку BizTalk.
РЕДАКТИРОВАТЬ с помощью 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);
}