小喵最近有個需求,系統必須提供給舊系統呼叫小喵的 COM+ 元件,本來與其他系統負責人溝通後,最好能夠傳回 JSON 內容,並已經敲定透過 WebAPI 應該是比較好的一個合作方式,無奈在跟負責主機管理的人提出環境確認時,不幸得到的消息是,無法安裝新的.NET Framework,因此無法使用 WebAPI 。所幸小喵找到了一個好朋友 Donma 分享的文章,提供了解決的方法~
緣起
小喵最近有個需求,系統必須提供給舊系統呼叫小喵的 COM+ 元件,本來與其他系統負責人溝通後,最好能夠傳回 JSON 內容,並已經敲定透過 WebAPI 應該是比較好的一個合作方式,無奈在跟負責主機管理的人提出環境確認時,不幸得到的消息是,無法安裝新的.NET Framework,因此無法使用 WebAPI 。所幸小喵找到了一個好朋友 Donma 分享的文章,提供了解決的方法~
範例物件
這邊簡單用個UserInfo類別來當作範例物件,相關的內容如下:
Public Class UserInfo
    Public Property UserName As String = ""
    Public Property Age As Integer = 0
End Class
WebService
接著撰寫 WebService 的部分。首先是因為要傳回JSON的格式,先 Imports System.Web.Script.Service
Imports System.Web.Script.Services
接著,小喵用了兩個練習:
- 透過GET來取得多筆的資料,傳回物件集合,轉JSON格式
 - 透過POST送資料過來,最後傳回物件,轉JSON格式
 
透過 ScriptMothod的宣告,GetUsers 這個不需要傳入資料的部分,宣告可以使用 GET 來呼叫,而傳回的內容指定為JSON (Client端還是要配合指定傳回格式)
相關的程式碼如下:
Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.Web.Script.Services
' 若要允許使用 ASP.NET AJAX 從指令碼呼叫此 Web 服務,請取消註解下列一行。
<System.Web.Script.Services.ScriptService()> _
<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class WSUser
    Inherits System.Web.Services.WebService
    <WebMethod()> _
    <ScriptMethod(UseHttpGet:=True, ResponseFormat:=ResponseFormat.Json)> _
    Public Function GetUsers() As List(Of UserInfo)
        Try
            Dim y As Integer
            Dim oUsers As New List(Of UserInfo)
            Dim tUser As UserInfo
            
            '迴圈產生傳回的資料
            For y = 1 To 10
                tUser = New UserInfo
                tUser.UserName = "User" & y.ToString("00")
                tUser.Age = 20 + y
                oUsers.Add(tUser)
            Next
            Return oUsers
        Catch ex As Exception
            Throw
        End Try
    End Function
    <WebMethod> _
    <ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
    Public Function GetOneUser(ByVal UserName As String, ByVal Age As Integer) As UserInfo
        Try
            Dim rtnUser As New UserInfo
            rtnUser.UserName = UserName
            rtnUser.Age = Age
            Return rtnUser
        Catch ex As Exception
            Throw
        End Try
    End Function
End Class
ScriptMethod中宣告傳回的格式是Json,不過使用端還是要配合設定,不然傳回的預設還是xml。傳回xml或json在Server端這邊程式不必特別為Client端分開寫,有WebAPI 類似的方便。
因為其中 GetUsers 想透過 GET來呼叫,所以在 Web.Config 中特別設定一下,在System.Web的段落中,加入以下的內容
    <webServices>
      <protocols>
        <add name="HttpSoap"/>
        <add name="HttpPost"/>
        <add name="HttpGet"/>
      </protocols>
    </webServices>
這樣測試一下GetUsers,跑出來如下的內容
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<ArrayOfUserInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
  <UserInfo>
    <UserName>User01</UserName>
    <Age>21</Age>
  </UserInfo>
  <UserInfo>
    <UserName>User02</UserName>
    <Age>22</Age>
  </UserInfo>
  <UserInfo>
    <UserName>User03</UserName>
    <Age>23</Age>
  </UserInfo>
  <UserInfo>
    <UserName>User04</UserName>
    <Age>24</Age>
  </UserInfo>
  <UserInfo>
    <UserName>User05</UserName>
    <Age>25</Age>
  </UserInfo>
  <UserInfo>
    <UserName>User06</UserName>
    <Age>26</Age>
  </UserInfo>
  <UserInfo>
    <UserName>User07</UserName>
    <Age>27</Age>
  </UserInfo>
  <UserInfo>
    <UserName>User08</UserName>
    <Age>28</Age>
  </UserInfo>
  <UserInfo>
    <UserName>User09</UserName>
    <Age>29</Age>
  </UserInfo>
  <UserInfo>
    <UserName>User10</UserName>
    <Age>30</Age>
  </UserInfo>
</ArrayOfUserInfo>
不是指定要丟回JSON嗎,怎麼還是跑出xml ?
其實不必擔心,只要Client端呼叫的時候,指定Content-Type, dataType即可
jQuery呼叫範例:
WebService準備好了,接下來就寫呼叫引用的JavaScript,首先準備測試的畫面:
        <input type="button" id="btnGet" value="取得Users" />
        <br />
        UserName:<input type="text" id="txtUserName" value="" /><br />
        Age:<input type="number" id="numAge" value="0" /><br />
        <input type="button" id="btnGetOneUser" value="設定並取得User" />
        <hr />
        <textarea id="ta1" cols="60" rows="20"></textarea>
相關 jQuery Ajax的範例如下:
    <script>
        var strURL1 = 'http://localhost:48314/WSUser.asmx/GetUsers';
        var strURL2 = 'http://localhost:48314/WSUser.asmx/GetOneUser';
        $(document).ready(function () {
            $('#btnGet').click(getUsers);
            $('#btnGetOneUser').click(SetAndGetOneUser);
        });
        function SetAndGetOneUser() {
            var UserName = $('#txtUserName').val();
            var Age = $('#numAge').val();
            $.ajax({
                type: "POST",
                url: strURL2,
                contentType: "application/json; charset=utf-8",
                data:'{UserName:"' + UserName + '",Age:' + Age + '}',
                dataType: "json",
                success: function (data) {
                    if (data.hasOwnProperty("d")) {
                        $('#ta1').text(JSON.stringify(data.d));
                    }
                    else {
                        $('#ta1').text(JSON.stringify(data));
                    }
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    alert(xhr.status);
                    alert(thrownError);
                }
            });
        }
        function getUsers() {
            $.ajax({
                type: "GET",
                url: strURL1,
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (data) {
                    if (data.hasOwnProperty("d")) {
                        $('#ta1').text(JSON.stringify(data.d));
                    }
                    else {
                        $('#ta1').text(JSON.stringify(data));
                    }
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    alert(xhr.status);
                    alert(thrownError);
                }
            });
        }
    </script>
這樣產出的JSON,會有個怪怪的 d 如下:
所以會透過 data.hasOwnProperty 的方式判斷是否有那個 d 如果有,就取 d 以下的內容
以上好了後,在同一個專案中,沒有問題,不過跨了專案或者Domain之後,又會發生 jQuery 跨 Domain的問題,之前小喵有一篇【[WebAPI][CORS]使用 xdomain.js 實現 WebAPI 多組(Multiple) 跨 Domain】,有個透過 XDomain 的方式可以處理,因此借用這個方式,就可以輕鬆解決跨網域的問題,繼續提供另一個專案跨網域使用jQuery的 AJAX 來呼叫,相關的設定請參考那篇文章的說明。
末記
在環境上的不允許的狀況下,不得以用Web Service來處理,再次感恩好朋友 Donma 大大的文章,非常有幫助,這樣WebService也可以依據Client端的需求,做到傳回物件,就自動依據Client端需求傳回 XML 或 JSON 的格式。小喵這篇大致上與 Donma那篇幾乎相同,小喵改寫為 VB.NET 的方式撰寫,另外配合XDomain的方式來幾決 jQuery 的 Ajax 會有 Cross Domain 被拒絕的問題,相關資訊小喵做個筆記,以利未來有需要時的參考,也提供網路上的朋友們參考。
^_^
參考資料:
特別感恩當麻大的文章:
以下是簽名:
- 歡迎轉貼本站的文章,不過請在貼文主旨上加上【轉貼】,並在文章中附上本篇的超連結與站名【topcat姍舞之間的極度凝聚】,感恩大家的配合。
 - 小喵大部分的文章會以小喵熟悉的語言VB.NET撰寫,如果您需要C#的Code,也許您可以試著用線上的工具進行轉換,這裡提供幾個參考
 
| Microsoft MVP Visual Studio and Development Technologies (2005~2019/6)  | topcat Blog:http://www.dotblogs.com.tw/topcat  |