2017-10-19 60 views
5

在用户(“用户A”)可以使用SOAP设置自己的Web服务连接的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" 
    } 
]; 

该数组在进行反序列化之前以字符串的形式输入(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); 

但值的量以及可能根据用户的输入以及引用的转换顺序而改变,所以我需要更灵活的东西。我对SOAP调用非常陌生,所以尽可能愚蠢地回答,我们将不胜感激。

+0

您是否评估过任何现有模板引擎,如'nustache'(https://github.com/jdiamond/Nustache)或'handlebars.net'(https://github.com/rexm/Handlebars.Net)? –

+0

我没有自由向这个项目添加新的库。在不需要这些选项的情况下,这样的选择会有偏好。 – Patrick

回答

1

考虑创建一个函数,用它们各自的值替换占位符。

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); 

然而,您需要验证提供的值和密钥以避免可能对系统造成不利影响的注入。

+0

关于如何验证这些值,你有任何建议吗?问题在于,这涉及到一个用户为另一个用户提供消息来填充消息,因此没有关于这个消息或值可能包含什么的先验知识。 – Patrick

+0

@Patrick,那些是在转换消息之前需要处理的实现问题。考虑到您是代码的控制者,您可以在尝试转换消息之前始终验证提供的值是否与当前用户匹配。 – Nkosi

1

使用xml处理器而不是字符串替换来处理xml总是一个好主意。 我的交叉思维想法可能并不完全适合你的用例,我没有把你的大图片100%的我不得不承认。

无论如何,我的答案是,你可以使用xpaths作为关键,这将使你能够利用后端的XML处理工具。您现在不需要验证任何东西,这非常依赖于架构。

在我的脑海

所以,JavaScript提供这样的结构:

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

和后端:

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

这个想法是soap消息是由用户A提供的,并且这些值是由用户B提供的,因此,让用户A在xml选择器中思考可能会很复杂,但我绝对喜欢你的out-of-the箱子的想法。 – Patrick

0

此作业的最佳工具,恕我直言,是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上有一篇文章:

Wrap XML in SOAP envelope in .net

.NET支持XSLT开箱即用,因此您不需要任何第三方库。我会将JSON加载到一个XML对象中,并将其应用于您将修改的XSLT模板,以尊重您在内存中的XML结构。

在C#中使用的XmlLoader到您的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); 

加载.NET中的XSLT模板是非常简单的:

var xml = XDocument.Load(JsonReaderWriterFactory.CreateJsonReader(
Encoding.ASCII.GetBytes(jsonString), new XmlDictionaryReaderQuotas())); 

这是一个清洁和专业我认为符合您的标准。