Вставка значений из массива в сообщение SOAP на основе ключа


В an ASP.NET приложение, в котором пользователи ("пользователь а") могут устанавливать свои собственные подключения к веб-сервисам с помощью SOAP, я позволяю им вставлять свой собственный конверт, который, например, может быть чем-то вроде:

//Formatted for Clarity
string soapMessage = 
"<soap: Envelope //StandardStuff>
  <soap:Header //StandardStuff>
    <wsse:UsernameToken>
      <wsse: Username>{F1}</wsse:Username>
      <wsse: Password Type''>{F2}</wsse:Password>  
    </wsse:UsernameToken>
  </soap:Header>
  <soap:Body>
    <ref:GetStuff>
      <ref:IsActive>{F3}</ref:IsActive>
    </ref:GetStuff>
  </soap:Body>
</soap:Envelope>"

В то же время я "пользователь B", который отправляет массив данных, передаваемых из Javascript в виде json, который выглядит примерно так:

[
  { 
    key: "F1", 
    value: "A" 
  },
  { 
    key: "F2", 
    value: "B" 
  },
  { 
    key: "F3", 
    value: "C" 
  }
];

Этот массив входит в fray в виде строки перед десериализацией (dynamic JsonObject = JsonConvert.DeserializeObject(stringifiedJson);).

Теперь я хотел бы быть возможность вставлять соответствующие значения в конверт, желательно с такой степенью безопасности, которая не позволит людям делать странные вещи, вставляя странные значения в массив (регулярное выражение, вероятно, будет моим последним средством).

До сих пор я знаю о концепции построения строки так (с заменой {} в сообщении soap на {0}, {1} & {2}):

string value1 = "A";
string value2 = "B";
string value3 = "C";
var body = string.Format(@soapMessage, value1, value2, value3);

request.ContentType = "application/soap+xml; charset=utf-8";
request.ContentLength = body.Length;
request.Accept = "text/xml";
request.GetRequestStream().Write(Encoding.UTF8.GetBytes(body), 0, body.Length);

Но количество значений в этом массиве, а также может меняться в зависимости от ввода пользователя, а также порядка сдвига ссылок, так что мне нужно что-то более гибкое. Я очень новичок в том, чтобы делать звонки с мылом,так что как можно более глупый ответ будет оценен.

3 5

3 ответа:

Подумайте о создании функции, которая заменила бы заполнители соответствующими значениями.

private string FormatMessage(string soapMessage, IDictionary<string, string> parameters) {
    var message = soapMessage;
    foreach (var kvp in parameters) {
        var placeholder = "{" + kvp.Key + "}";
        if (message.IndexOf(placeholder) > -1) {
            message = message.Replace(placeholder, kvp.Value);
        }
    }
    return message;
}

Где словарь был извлечен из JSON, предоставленного функции.

var parameters = JsonConvert.DeserializeObject<IDictionary<string, string>>(json);

string body = FormatMessage(soapMessage, parameters);

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

Всегда полезно обрабатывать xml с помощью xml-процессоров вместо замены строк. Моя идея перекрестного мышления, возможно, не совсем подходит для вашего использования, я не получил вашу общую картину на 100% , я должен признать.

В любом случае мой ответ заключается в том, что вы можете использовать XPath в качестве ключа, который позволит вам использовать инструменты обработки xml на бэкэнде. Вам не обязательно проверять что-либо на этом этапе, это очень зависит от архитектуры.

Итак, по моему мнению, javascript обеспечивает эту структуру:

[
  { 
    key: "//family-name", 
    value: "Michael" 
  },
  { 
    key: "//nickname", 
    value: "Jackson" 
  }
];

И бэкэнд:

XmlElement foo = (XmlElement)doc.SelectSingleNode(key);
foo.InnerText = value;

Лучший инструмент для этой работы, ИМХО, это XSLT:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:crs="CRS610MI" exclude-result-prefixes="crs">
<xsl:output method="xml"/>
<xsl:template match="/">
  <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <soap:Body>
    <xsl:apply-templates select="node()|@*"/>
    </soap:Body>
  </soap:Envelope>
</xsl:template>
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

Есть пост на SO, касающийся этой конкретной темы:

Оберните XML в конверт SOAP в .net

.NET поддерживает XSLT из коробки, поэтому вам не понадобятся сторонние библиотеки. Я бы загрузил JSON в объект XML и применил его к шаблону XSLT, который вы измените, чтобы уважать вашу структуру XML в памяти.

Используйте XmlLoader в C# для загрузки JSON в XML объект:

XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);

// To convert JSON text contained in string json into an XML node
XmlDocument doc = JsonConvert.DeserializeXmlNode(json);

Загрузка шаблона XSLT в .NET довольно проста:

var xml = XDocument.Load(JsonReaderWriterFactory.CreateJsonReader(
Encoding.ASCII.GetBytes(jsonString), new XmlDictionaryReaderQuotas()));
Это чистый и профессиональный подход, который, я считаю, соответствует вашим критериям.