這幾天一直在學習WebService的知識。正好現在有一個項目,需要在WebService實現如下接口:
String Login(string username, string password) // 登錄方法,返回值用來指名是不是登錄成功,並且這個值在之後的接口中用來找到相對應的服務器上的session。
因此WebService需要使用到Session,而網上大部分資料是說WebService是無狀態的(StateLess),不怎麼支持Session。因此難題出現了,首先在Web Serivice
放上聲明如下Attribute,[WebMethod(EnableSession = true)],此為表示在webService上能使用Session。
現在放上我寫的WebService的例子代碼(service端):
view plaincopy to clipboardprint?/// <summary>
/// Summary description for Service1
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class Bussiness : System.Web.Services.WebService
{
[WebMethod(Description = "登錄方法,返回值用來指名是不是登錄成功,並且這個值在之後的接口中用來找到相對應的服務器上的session",
EnableSession = true)]
public string Login(string username, string password)
{
string state = "";
if (IsLogin(username))
state = "Logined";
else
{
state = UserHelper.Login(username, password);
if (state != null && state != "Failed")//
{
//Session.Timeout = 1;
Session[state] = username;
}
}
return state;
}
[WebMethod(Description = "判斷是否登錄",
EnableSession = true)]
private bool IsLogin(string name)
{
if (name != null && Session[name]!=null&& Session[name].ToString() == name)
return true;
return false;
}
/// <summary>
/// Summary description for Service1
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class Bussiness : System.Web.Services.WebService
{
[WebMethod(Description = "登錄方法,返回值用來指名是不是登錄成功,並且這個值在之後的接口中用來找到相對應的服務器上的session",
EnableSession = true)]
public string Login(string username, string password)
{
string state = "";
if (IsLogin(username))
state = "Logined";
else
{
state = UserHelper.Login(username, password);
if (state != null && state != "Failed")//
{
//Session.Timeout = 1;
Session[state] = username;
}
}
return state;
}
[WebMethod(Description = "判斷是否登錄",
EnableSession = true)]
private bool IsLogin(string name)
{
if (name != null && Session[name]!=null&& Session[name].ToString() == name)
return true;
return false;
}
客戶端代碼,我用的是soap方式寫的,soap方式調用WebService的方法,我參看了《Programing Web Service with SOAP》。具體方式參看第三章的。我的客戶端SOAP代碼(我新建一個類)如下:
view plaincopy to clipboardprint?using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Serialization;
namespace Test
{
[WebServiceBinding(Name = "BusServiceSoap", Namespace = "http://tempuri.org/")]
public class BusService : SoapHttpClientProtocol
{
public BusService()
{
// this.Url = "http://localhost:4243/Bussiness.asmx";
this.Url = "http://localhost/Bussiness/Bussiness.asmx";
}
[System.Web.Services.Protocols.SoapDocumentMethod(
"http://tempuri.org/Login",
RequestNamespace = "http://tempuri.org/",
ResponseNamespace = "http://tempuri.org/",
Use = System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string Login(string username, string password)
{
object[] result = this.Invoke("Login",
new object[] { username, password });
return (string)result[0];
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Serialization;
namespace Test
{
[WebServiceBinding(Name = "BusServiceSoap", Namespace = "http://tempuri.org/")]
public class BusService : SoapHttpClientProtocol
{
public BusService()
{
// this.Url = "http://localhost:4243/Bussiness.asmx";
this.Url = "http://localhost/Bussiness/Bussiness.asmx";
}
[System.Web.Services.Protocols.SoapDocumentMethod(
"http://tempuri.org/Login",
RequestNamespace = "http://tempuri.org/",
ResponseNamespace = "http://tempuri.org/",
Use = System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string Login(string username, string password)
{
object[] result = this.Invoke("Login",
new object[] { username, password });
return (string)result[0];
}
}
}
客戶點調用代碼,也就是用戶端的調用代碼,我寫的是控制台的測試代碼,如下:
view plaincopy to clipboardprint?namespace Test
{
public class Program
{
static void Main(string[] args)
{
string name = "admin";
string password = "123";
TestLogin tl = new TestLogin(name, password);
string state = tl.Login();
Console.WriteLine("State = " + state);
state = tl.Login();
Console.WriteLine("State = " + state);
Console.Read();
}
}
public class TestLogin
{
public string name = "";
public string psw = "";
BusService bus = new BusService();
public TestLogin(string name, string psw)
{
this.name = name;
this.psw = psw;
}
public string Login()
{
return bus.Login(this.name, this.psw);
}
}
}
namespace Test
{
public class Program
{
static void Main(string[] args)
{
string name = "admin";
string password = "123";
TestLogin tl = new TestLogin(name, password);
string state = tl.Login();
Console.WriteLine("State = " + state);
state = tl.Login();
Console.WriteLine("State = " + state);
Console.Read();
}
}
public class TestLogin
{
public string name = "";
public string psw = "";
BusService bus = new BusService();
public TestLogin(string name, string psw)
{
this.name = name;
this.psw = psw;
}
public string Login()
{
return bus.Login(this.name, this.psw);
}
}
}
寫到這裡進行運行,感覺一切應該按照自己想想的正確的打印出來。打印結果應該是如下這樣的:
State = admin
State = Logined
結果實際運行的效果與自己設想的不太一樣,實際運行的結果是
State = admin
State = admin
這樣的運行結果說明,WebService 的Server端的Session,根本沒有保存。通過斷點調試發現,第二次讀取的Session為空,就是沒有保存。
因此只在Server端進行聲明EnableSession = true,是不夠的,這只是說明Server端現在能用session了。
經過上網查閱資料得知:要想使用Session,在進行上一步的聲明之後,還要在客戶端實例話WebService對象時,對其CookieContainer也要進行初始化方可使用Session的存儲狀態。另外在多個webservice代理中,只要含有相同的cookie,就能共用相同的session,其中的cookie通過代理類的CookieContainer.GetCookies(new Uri(s.Url))["ASP.NET_SessionId"]取得,如果其他的webserivce代理類需要用相同的session則可以用CookieContainer.Add方法,將取得的cookie加入即可(還沒進行測試)。
知道了如何使用後,修改客戶端的Soap代碼即可,修改後的代碼(紅色部分為修改的代碼)如下:
view plaincopy to clipboardprint? [WebServiceBinding(Name = "BusServiceSoap", Namespace = "http://tempuri.org/")]
public class BusService : SoapHttpClientProtocol
{
<strong><span style="color:#ff0000;">private static System.Net.CookieContainer cookieContainer;</span>
<span style="color:#ff0000;">static BusService()
{
cookieContainer = new System.Net.CookieContainer();
}</span></strong>
public BusService()
{
this.Url = "http://localhost:4243/Bussiness.asmx";
<strong><span style="color:#ff6666;"> this.CookieContainer = new System.Net.CookieContainer();
</span></strong> // this.Url = "http://localhost/Bussiness/Bussiness.asmx";
}
[System.Web.Services.Protocols.SoapDocumentMethod(
"http://tempuri.org/Login",
RequestNamespace = "http://tempuri.org/",
ResponseNamespace = "http://tempuri.org/",
Use = System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string Login(string username, string password)
{
object[] result = this.Invoke("Login",
new object[] { username, password });
return (string)result[0];
}
}
[WebServiceBinding(Name = "BusServiceSoap", Namespace = "http://tempuri.org/")]
public class BusService : SoapHttpClientProtocol
{
<strong><span style="color:#ff0000;">private static System.Net.CookieContainer cookieContainer;</span>
<span style="color:#ff0000;">static BusService()
{
cookieContainer = new System.Net.CookieContainer();
}</span></strong>
public BusService()
{
this.Url = "http://localhost:4243/Bussiness.asmx";
<strong><span style="color:#ff6666;"> this.CookieContainer = new System.Net.CookieContainer();
</span></strong> // this.Url = "http://localhost/Bussiness/Bussiness.asmx";
}
[System.Web.Services.Protocols.SoapDocumentMethod(
"http://tempuri.org/Login",
RequestNamespace = "http://tempuri.org/",
ResponseNamespace = "http://tempuri.org/",
Use = System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string Login(string username, string password)
{
object[] result = this.Invoke("Login",
new object[] { username, password });
return (string)result[0];
}
}
修改完了之後,進行測試,測試結果與設想的結果一樣。
摘自:示申 言舌 的專欄