起因:
合作公司提供了一个WebService供我调用,为了保证安全性,要求在SoapHeader中带用户名和密码进行校验。
在获取了对方的WSDL文件后,并未在文件中指明SoapHeader的格式以及要传递的用户名、密码的属性名称。按照C#中调用WebService的常规方法,在测试工程中“添加Web引用”或“添加服务引用”,只看到生成的*.discomap 和 *.wsdl 两个文件,并未找到生成的 *.cs 类文件,但在测试代码中可以直接调用WebService,未要求身份校验的服务方法可以正常调用,但对于有身份校验要求的方法,则无法设定SoapHeader,导致调用失败。
通过对网上一些案例的研究以及自己的摸索,发现一个解决方法。
步骤:
1、通过命令行,使用wsdl.exe工具手工生成服务接口类文件:
a) 开始菜单--》Microsoft Visual Studio 2010--》Visual Studio Tools--》Visual Studio Command Prompt (2010)
b) C:\*******\VC>wsdl /n:website /out:D:\******\website\InterfaceCls.cs http://XXX.XXX.XXX.XXX:81/axis2/services/InterfaceCls?wsdl
Microsoft(R) Web Services 描述语言实用工具
[Microsoft (R) .NET Framework, Version 4.0.30319.1]
Copyright (C) Microsoft Corporation. All rights reserved.
正在写入文件“D:\******\website\InterfaceCls.cs”。
c) 把生成的InterfaceCls.cs文件加入工程,例如:App_Code目录
2、创建自定义SoapHeader文件,性须继承自System.Web.Services.Protocols.SoapHeader。源码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/// <summary>
///WebsiteSoapHeader
/// </summary>
public class WebsiteSoapHeader : System.Web.Services.Protocols.SoapHeader
{
private string userName=string.Empty;
private string passWord=string.Empty;
/// <summary>
///
/// </summary>
public WebsiteSoapHeader()
{
}
/// <summary>
///
/// </summary>
/// <param name="userName">用户名</param>
/// <param name="passWord">密码</param>
public WebsiteSoapHeader(string userName, string passWord)
{
this.userName = userName;
this.passWord = passWord;
}
/// <summary>
///
/// </summary>
public string UserName
{
get { return userName; }
set { userName = value; }
}
/// <summary>
///
/// </summary>
public string PassWord
{
get { return passWord; }
set { passWord = value; }
}
}
3、修改InterfaceCls.cs 文件:
a) 增加类变量Authentication:
namespace website {
using System;
using System.Web.Services;
using System.Diagnostics;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Xml.Serialization;
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.0.30319.1")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name="InterfaceClsSoap11Binding", Namespace="http://ws.apache.org/axis2")]
public partial class InterfaceCls : System.Web.Services.Protocols.SoapHttpClientProtocol {
private System.Threading.SendOrPostCallback GetBuyHouseInfoOperationCompleted;
private System.Threading.SendOrPostCallback sayHelloOperationCompleted;
public WebsiteSoapHeader Authentication;//这是新增的类变量
/// <remarks/>
public InterfaceCls() {
……
}
}
}
b) 在有身份校验要求的服务方法上增加声明:
/// <remarks/>
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("urn:GetBuyHouseInfo", RequestNamespace="http://ws.apache.org/axis2", ResponseNamespace="http://ws.apache.org/axis2", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return: System.Xml.Serialization.XmlElementAttribute("return", Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=true)]
[System.Web.Services.Protocols.SoapHeader("Authentication")] //这是新增的声明,其中Authentication必须与前面的类变量同名
public string GetBuyHouseInfo() {
object[] results = this.Invoke("GetBuyHouseInfo", new object[0]);
return ((string)(results[0]));
}
4、在客户端调用时,增加给Authentication 变量的赋值:
/// <summary>
/// 测试通过SoapHeader来访问有用户鉴权的服务
/// </summary>
protected void testCallRemoteService()
{
website.InterfaceCls service = new website.InterfaceCls();
//以下红色部分是新增的代码
WebsiteSoapHeader header = new WebsiteSoapHeader();
header.UserName = "testuser";
header.PassWord = "111111";
service.Authentication = header; //给Authentication 赋值
string str = service.GetBuyHouseInfo();
}
5、至此,就解决了前面所说的问题。