我对SOAP协议几乎没有任何经验。我需要连接的服务需要头文件。在Java中,我认为这是一种标准方法,但在C#中,必须手动创建此头文件。
有没有人能够连接到类似的服务:已经创建了头文件,或者甚至知道一些标准库可以简化头文件的创建?您能分享一些代码或参考资料吗?
我还发现一个线索,使用WS2005可能会生成头文件,因为它有一个WS3插件。有没有人能够评论一下这个?快速查看这个插件后,我发现与安全头部相似的字段,但仍然无法创建头文件。
我们通过以下代码解决了这个问题:
public class SecurityHeader : System.ServiceModel.Channels.MessageHeader {
public string userName;
public string password;
protected override void OnWriteStartHeader (System.Xml.XmlDictionaryWriter writer, System.ServiceModel.Channels.MessageVersion messageVersion)
{
writer.WriteStartElement("wsse", Name, Namespace);
writer.WriteXmlnsAttribute("wsse", Namespace);
}
protected override void OnWriteHeaderContents (System.Xml.XmlDictionaryWriter writer, System.ServiceModel.Channels.MessageVersion messageVersion)
{
writer.WriteStartElement("wsse", "UsernameToken", Namespace);
writer.WriteStartElement("wsse", "Username", Namespace);
writer.WriteValue(userName);
writer.WriteEndElement();
writer.WriteStartElement("wsse", "Password", Namespace);
writer.WriteValue(password);
writer.WriteEndElement();
writer.WriteEndElement();
}
public override string Name
{
get { return "Security"; }
}
public override string Namespace
{
get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
}
}
这段代码编写了DataPower盒子所需的标题。
如何使用SecurityHeader类
public static void Main(string[] args)
{
var webService = new ServiceReference1.MyWebService();
....
webService.Open();
using (OperationContextScope scope = new OperationContextScope((IContextChannel)webService.InnerChannel))
{
var myObjRequest = GetMyObjRequest();
MessageHeaders messageHeadersElement = OperationContext.Current.OutgoingMessageHeaders;
messageHeadersElement.Add(SecurityHeader("UserName", "Password"))
var res = webService.MyServe(myObjRequest);
Console.WriteLine(res.ToString());
}
}
在.Net中,为您的Web服务代理添加SOAP标头通常非常容易。以下是一个快速的代码示例。
创建一个新的SOAP标头
using System.Web.Services.Protocols;
public class SoapAuthHeader : SoapHeader
{
public string Username;
public string Password;
}
在您的Web服务代理类中:
public class MyWebServicesProxy : System.Web.Services.Protocols.SoapHttpClientProtocol {
public SoapAuthHeader AuthHeader;
...
}
然后使用:
SoapAuthHeader authHeader = new SoapAuthHeader();
authHeader.Username = "username";
authHeader.Password = "password";
MyWebServicesProxy myProxy = new MyWebServicesProxy();
myProxy.AuthHeader = authHeader;
SoapExtension
来实现它,它使用ChainStream
来保留原始流的副本,在BeforeDeserialize
期间仅复制流,并在AfterSerialize
期间添加头文件。ChainStream
返回)的内容读入XML文档(在我的情况下是XDocument
),添加头部,然后将其写入传递给ChainStream
的原始流中。SoapHeader
大部分地方代替了上述方法,为Web服务的每个方法添加了适当的属性和字段/属性,其中包含所需标头的实例 - 但是SOAP序列化目前让我头疼,因为要指定正确的元素名称(带命名空间)。 这是我计划在有时间时向其他人询问的问题。谢谢大家。以下是您所有的代码和想法。
public class SecurityHeader : System.ServiceModel.Channels.MessageHeader
{
public string userName;
public string password;
public SecurityHeader(string userName, string password)
{
this.userName = userName;
this.password = password;
}
protected override void OnWriteStartHeader(System.Xml.XmlDictionaryWriter writer, System.ServiceModel.Channels.MessageVersion messageVersion)
{
writer.WriteStartElement("wsse", Name, Namespace);
writer.WriteXmlnsAttribute("wsse", Namespace);
}
protected override void OnWriteHeaderContents(System.Xml.XmlDictionaryWriter writer, System.ServiceModel.Channels.MessageVersion messageVersion)
{
writer.WriteStartElement("wsse", "UsernameToken", Namespace);
writer.WriteStartElement("wsse", "Username", Namespace);
writer.WriteValue(userName);
writer.WriteEndElement();
writer.WriteStartElement("wsse", "Password", Namespace);
writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
writer.WriteValue(password);
writer.WriteEndElement();
writer.WriteEndElement();
}
public override string Name
{
get { return "Security"; }
}
public override string Namespace
{
get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
}
}
using (IdsTestSvc.MedulaIlacDagitimSistemiIslemleriClient client = new IdsTestSvc.MedulaIlacDagitimSistemiIslemleriClient("MedulaIlacDagitimSistemiIslemleriPort"))
{
using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
{
MessageHeaders messageHeadersElement = OperationContext.Current.OutgoingMessageHeaders;
messageHeadersElement.Add(new SecurityHeader(_main.IdsFirmCode, _main.IdsFirmCode));
....Do something
}
}
有一个名为ClearUserNameBinding的开源自定义绑定,该绑定有助于在Http上将UserNameToken作为明文传递。当需要使用WCF客户端消耗基于Java的Web服务时,这对我很有帮助。
http://code.google.com/p/wcf-clear-username-binding/ http://webservices20.blogspot.com/2008/11/introducing-wcf-clearusernamebinding.html
在编程相关内容中,以下是由Domenico Zinzi提出的解决方案,对我非常有用:
我在SecurityHeader类中创建了一个构造函数:
public SecurityHeader(string userName, string password){
userName = userName;
password = password;
}
在调用时,我使用了“New”关键字,如下所示:
messageHeadersElement.Add(New SecurityHeader("UserName", "Password"))
然后就可以正常工作啦 :)
P.S. 无法添加评论,所以在此处添加。
writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
谢谢! - Luís Deschamps Rudge