在上一篇講到,如果將BLL層的每一個類都轉化爲*.svc,這是一個不實在的想法。它會使服務變化複雜,難於管理。
這時候,我們第一時間想到的是23個簡單開發模式中的Factory,在這裏,Factory正好派上用場。我們把這個Factory稱之爲管道(pipeline) ,通過這個管道客戶端可以隨意調用服務器BLL層裏面的類。
(關於管道的概念,建議參考Cory Isaacson的傑作《多核應用架構關鍵技術—軟件管道與soa》)
當你使用B/S方式開發UI層時,只要瞭解此開發模式,使用Ajax加上WCF裏面的WebHttpBinding綁定和WebHttpBehavior行爲,可以說是天衣無縫的組合。
首先,開發一個數據契約,其中包括程序集名稱,類名,構造函數的參數,方法名,方法中的參數
[DataContract]
public class Communication
{
[DataMember]
public string Assembly
{
get;
set;
}
[DataMember]
public string Class
{
get;
set;
}
[DataMember]
public object[] ConstructedParameters
{
get;
set;
}
[DataMember]
public string Method
{
get;
set;
}
[DataMember]
public object[] Parameters
{
get;
set;
}
}
爲了證明客戶端可以通過Ajax能夠直接調用服務器WCF,我們先在MyAssembly程序集裏面開發一個User類,然後生成MyAssembly.dll程序集作爲測試。
namespace MyAssembly
{
[DataContract]
public class User
{
[DataMember]
public int ID
{ get; set; }
[DataMember]
public string Name
{ get; set; }
[DataMember]
public int Age
{ get; set; }
}
public class UserManager
{
public List<User> GetList()
{
List<User> entities = new List<User>();
User user = new User();
user.ID = 0;
user.Age = 26;
user.Name = "Leslie";
entities.Add(user);
return entities;
}
}
}
好,現在已經做好準備,現在我們新建一個“啓動了AJAX的WCF服務”
[ServiceContract(Namespace = "myNamespace")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
//注意必須將RequirementsMode設置爲AspNetCompatibilityRequirementsMode.Allowed
public class Service
{
private static Hashtable assemblies = new Hashtable();
private static Hashtable types = new Hashtable();
[OperationContract]
[WebGet]
// 要使用 HTTP GET,請添加 [WebGet] 特性。
public string DoWork(Communication communication)
{
Type classType = GetType(communication);
if (classType != null)
{
object reflectedObject;
if (communication.ConstructedParameters != null)
reflectedObject = Activator.CreateInstance(classType, communication.ConstructedParameters);
else
reflectedObject = Activator.CreateInstance(classType);
MethodInfo methodInfo = classType.GetMethod(communication.Method);
if (methodInfo != null)
{
object data = methodInfo.Invoke(reflectedObject, communication.Parameters);
if (data != null)
return Formate(data, methodInfo.ReturnType);
else
return null;
}
else
return null;
}
return null;
}
//因爲結果供於Ajax頁面使用,所以將結果轉化爲Json形式
//其實本項目已經是啓動了AJAX,所以在默認情況下結果會自己轉化爲JSON,但因爲不能事先實現返回的類型,所以
//此處手動將結果轉換成JSON字符串
public string Formate(object data,Type type)
{
using (Stream stream = new MemoryStream())
{
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(type);
jsonSerializer.WriteObject(stream, data);
byte[] byteData = new byte[stream.Length];
stream.Seek(0,0);
stream.Read(byteData, 0, (int)stream.Length);
stream.Close();
return Encoding.UTF8.GetString(byteData);
}
}
//加載程序集
private Assembly GetAssembly(Communication communication)
{
if (!assemblies.ContainsKey(communication.Assembly))
{
Assembly myAssembly = Assembly.Load(communication.Assembly);
assemblies.Add(communication.Assembly, myAssembly);
}
return (Assembly)assemblies[communication.Assembly];
}
//加載類
private Type GetType(Communication communication)
{
if (!types.ContainsKey(communication.Class))
{
Assembly assembly=GetAssembly(communication);
types.Add(communication.Class, assembly.GetType(communication.Class));
}
return (Type)types[communication.Class];
}
}
服務器端會自動爲你配置.config文件
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<behaviors>
<endpointBehaviors>
<behavior name="ServiceAspNetAjaxBehavior">
<enableWebScript />
//注意啓動enableWebScript
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
//注意此處啓動了httpGetEnabled
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Service" behaviorConfiguration="ServiceBehavior">
<endpoint address="" behaviorConfiguration="ServiceAspNetAjaxBehavior"
binding="webHttpBinding
" contract="Service" /> //注意綁定的是webHttpBinding
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
</configuration>
好吧,現在萬事俱備的時候,讓我們開發一個測試頁面
<body>
<form id="form1" runat="server">
<script type="text/javascript">
window.onload = function () {
myNamespace.Service.set_path("http://localhost:8080/Service.svc/");
var communication = { "Assembly": "MyAssembly", "Class": "MyAssembly.UserManager", "ConstructedParameters": null, "Method": "GetList", "Parameters": null };
//把Communication參數轉化爲Json形式
myNamespace.Service.DoWork(communication, OnSucceed, OnFail, null);
}
function OnSucceed(result) {
if (result != null)
alert(result);
}
function OnFail(result) {
alert(result);
}
</script>
</form>
</body>
測試成功:
恭喜你終於學會如何使用Ajax+WCF進行頁面數據顯示了。
你應該初步瞭解到如何使用管道Pipeline進行客戶端與服務器端的通訊,自此之後,每逢你進行簡單的網站開發時都可使用此方式。好處在於頁面無需瞭解數據是從何處獲取的,數據存儲的Web服務跟網站可以處於不同的服務器或者不同的IIS應用程序池,所以這樣做可以把服務器壓力降到最低。同時你可以使用異步的服務,來進一步提高數據站點的線程池效率。(異步服務可參考ASP.NET服務器端多線程設計 )
即便是這樣,此開發方式只適合用於普通的頁面開發,還不算是完善,因爲SOA是面向多方面的。試想一下如果系統調用的是公司的內部管理系統的服務,其中必然會夾雜着複雜的工作流,其處理方式與返回結果也有不同,全部使用JSON作爲返回值也會造成不必要的性能損耗,這時候應該怎麼決定呢?
下面就爲大家開始講解一下使用Web服務與WF結合開發以發揮其強大功能。
對NET系統開發有興趣的朋友,請加入QQ羣:NET技術開發聯盟 59557329 一起討論
熱門話題:使用WCF實現SOA面向服務編程(一)——SOA的概念
熱門話題:使用WCF實現SOA面向服務編程(二)——實現簡單的WCF開發實例
熱門話題:使用WCF實現SOA面向服務編程(三)——使用AJAX+WCF服務頁面開發
熱門話題:使用WCF實現SOA面向服務編程(四)—— 通過Web服務調用Workflow工作流(基礎實例)
熱門話題:使用WCF實現SOA面向服務編程(五)—— 通過Web服務調用Workflow工作流(開發持久化工作流)
熱門話題:使用WCF實現SOA面向服務編程(六)—— 通過InvokeWebServiceActivity在Workflow工作流中調用Web服務
熱門話題:使用WCF實現SOA面向服務編程(七)—— WF與WCF互相調用(利用ReceiveActivity把WF發佈爲WCF)