我正在尝试设置一个路由服务,它将位于我的网络的DMZ中,并允许外部人员访问一些内部托管的WCF服务。我已经设置好所有工作,但是当我转发MEX服务时,它会将我们的外部客户端指向我们的内部地址,这显然是他们无法访问的。
Microsoft seems to recommend making a copy of the wsdl,它可能会起作用,但每次服务定义发生变化时都需要我制作wsdl的新副本,而这些副本经常发生,而且看起来有点过分。唯一需要改变的是mex消息中的地址。
<endpoint address="http://appsrv1:8781/ProcessManagementService/"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IProcessManagementService"
contract="IProcessManagementService" name="WSHttpBinding_IProcessManagementService" />
似乎使用IDispatchMessageInspector
,我应该能够拦截mex消息并用外部服务器名称替换内部服务器名称,然后我只需要在需要时触摸路由服务添加或删除服务,而不是每次我做任何更改。
我对XML阅读器,编写器等没有太多经验,所以我正在寻找有关如何继续的一些指导。如果我可以将xml内容读入字符串,我可以执行替换操作以替换内部地址的外部地址,然后用我的修改版本替换回复的消息内容。我该如何去做,或者有更好的方法来修改WCF消息的内容?
编辑:所以这就是我到目前为止拼凑的东西。
public class EndpointReplacementInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
var ms = new MemoryStream();
var w = XmlWriter.Create(ms, new XmlWriterSettings { Indent = true, IndentChars = " ", OmitXmlDeclaration = true });
var bodyReader = reply.GetReaderAtBodyContents();
w.WriteStartElement("s", "Body", "http://schemas.xmlsoap.org/soap/envelope/");
while (bodyReader.NodeType != XmlNodeType.EndElement && bodyReader.LocalName != "Body" && bodyReader.NamespaceURI != "http://schemas.xmlsoap.org/soap/envelope/")
{
if (bodyReader.NodeType != XmlNodeType.Whitespace)
{
w.WriteNode(bodyReader, true);
}
else
{
bodyReader.Read(); // ignore whitespace; maintain if you want
}
}
w.WriteEndElement();
w.Flush();
var body = Encoding.UTF8.GetString(ms.ToArray());
body = body.Replace("internalserver", "externalserver");
var replacedMessage = Message.CreateMessage(XmlReader.Create(new StringReader(body)), int.MaxValue, reply.Version);
replacedMessage.Headers.CopyHeadersFrom(reply.Headers);
replacedMessage.Properties.CopyProperties(reply.Properties);
reply = replacedMessage;
}
}
似乎主要是工作。但是,XMLReader
抛出异常“根级别的数据无效。第1行,位置1”。当我尝试创建消息时。我不知道从那里开始。
编辑2:
好的,现在我有一个方法将消息提取到xdocument中,然后将其发送到字符串,然后对其进行编辑,然后将其拉回到xdocument中,当我获得“连接强制关闭”时发回包含该已编辑消息的消息。可怕。
编辑3:
经过测试,只需从回复xdoc中提取消息然后将其加载到新消息中就足以导致“连接强制关闭”问题。这绝不是编辑邮件的正确方法。我正在寻找有关如何最好地解决这个问题的示例或经验。
答案 0 :(得分:10)
我从MSDN Forums得到了答案。我的问题是我正在改变字符串的长度,但没有重置MemoryStream的长度,这意味着最后的字节没有被报告。
这是一个有效的替换功能。
public Message ChangeString(Message oldMessage, string from, string to)
{
MemoryStream ms = new MemoryStream();
XmlWriter xw = XmlWriter.Create(ms);
oldMessage.WriteMessage(xw);
xw.Flush();
string body = Encoding.UTF8.GetString(ms.ToArray());
xw.Close();
body = body.Replace(from, to);
ms = new MemoryStream(Encoding.UTF8.GetBytes(body));
XmlDictionaryReader xdr = XmlDictionaryReader.CreateTextReader(ms, new XmlDictionaryReaderQuotas());
Message newMessage = Message.CreateMessage(xdr, int.MaxValue, oldMessage.Version);
newMessage.Properties.CopyProperties(oldMessage.Properties);
return newMessage;
}
答案 1 :(得分:1)
如果您使用的是.NET 4.0,则只需要为您的服务配置代码中的<useRequestHeadersForMetadataAddress>
或UseRequestHeadersForMetadataAddressElement
。
答案 2 :(得分:1)
对于那些喜欢使用Linq to XML的人。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<!-- Include the plugin's CSS and JS: -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-multiselect/0.9.13/js/bootstrap-multiselect.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-multiselect/0.9.13/css/bootstrap-multiselect.css" type="text/css"/>
<script type="text/javascript">
$(document).ready(function() {
$('#example-optionClass').multiselect({
optionClass: function(element) {
var value = $(element).val();
if (value%2 == 0) {
return 'even';
}
else {
return 'odd';
}
}
});
});
</script>
<style type="text/css">
#example-optionClass-container .multiselect-container li.odd {
background: #eeeeee;
}
</style>
</head>
<body>
<div class="container">
<h2>Bootstrap Multiselect Test</h2>
<p>I want to change the Multiselect <b>background color</b> If 'None Selected'</p>
<div id="example-optionClass-container">
<select id="example-optionClass" multiple="multiple">
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
<option value="4">Option 4</option>
<option value="5">Option 5</option>
<option value="6">Option 6</option>
</select>
</div>
</div>
</body>
</html>