Web 服務存取
在這個範例專案中,將會實作 RESTful Web API 與 WCF 這兩種 Web 服務的呼叫方式。
在這裡,網路上提供了兩個Web 服務的網址:
- WCF
- RESTful Web API
這兩個 Web 服務都會把傳入的兩個整數相加,並且把相加的結果,回傳回來。
建立標籤式的樣板式頁面方案
- 首先,開啟您的 Visual Studio 2015
- 接著透過 Visual Studio 2015 功能表,選擇這些項目
檔案
>新增
>專案
準備新增一個專案。 - 接著,Visual Studio 2015 會顯示
新增專案
對話窗,請在這個對話窗上,進行選擇Visual C#
>Cross-Platform
>Blank Xaml App (Xamarin.Forms Portable)
- 接著,在最下方的
名稱
文字輸入盒處,輸入XFWebSrv
這個名稱,最後使用滑鼠右擊右下方的確定
按鈕。 - 當專案建立到一半,若您的開發環境還沒有建置與設定完成 Mac 電腦與 Xamarin Studio for Mac 系統,此時會看到
Xamarin Mac Agent Instructions
對話窗出現,這個對話窗是要提醒您進行與 Mac 電腦連線設定,這是因為,您無法在 Windows 作業系統進行 iOS 相關應用程式的建立與設計工作,而是需要透過 Mac 電腦安裝的 XCode 來協助您完成這些 iOS 應用程式的建立工作。不過,這不影響您繼續開發 Xamarin.Forms 的應用程式,只不過此時,您無法編譯與執行 iOS 的應用程式。 - 接著會看到
新的通用Windows專案
對話視窗,此時,您只需要按下確定
按鈕即可,此時,專案精靈會繼續完成相關平台的專案建立工作。 - 最後,整個新的 Xamarin.Forms 專案就建立完成了。
WCF 的事前準備
了解 PCL profile
在 Xamarin.Forms 內,想要呼叫 WCF Web 服務,需要先建立出 WCF 代理 (Proxy),之後就可以透過 WCF 代理還呼叫 WCF 服務提供的各項方法。因此,加入 WCF 的方法是在專案內的
參考
節點上,使用滑鼠右擊,透過 加入服務參考
選項,把 WCF 位址輸入到 加入服務參考
對話窗內。
可是,當您在 核心PCL 專案內的
參考
節點上,使用滑鼠右擊,卻沒有看到 加入服務參考
選項可以選擇。
這是因為 核心PCL 是
可移植類別庫
(Portable Class Library),也就是說,為了要讓這個類別庫可以支援更多的平台專案可以使用,因此,在 PCL 專案內,把許多無法跨平台的 API 或者功能,將無法使用。而在 PCL 內,有個欄位 TargetFrameworkProfile
定義了 PCL 的設定檔(Profile)資訊(您可以開啟 XFWebSrv.csproj 檔案茶看到),如下圖所示。
現在(Visual Studio 2015 with Update 2),若是透過 Visual Studio 專案樣版建立的 Xamarin.Forms 跨平台專案,其產生的核心PCL專案,使用的是
Profile111
設定檔;而這個 Profile111
PCL 設定檔內,是不提供 WCF Proxy 支援的。
更多關於 PCL 不同設定檔案資訊,可以參考底下連結
解決方案1 利用原生專案
- 雖然 核心PCL 專案內無法產生與建立 WCF 代理,不過,原生 Android 與 iOS 專案內,卻可以支援
- 因此,您可以在原生專案內的
參考
節點上,使用滑鼠右擊,就會看到加入 Web 參考
這個選項,透過這項功能,就可以產生 WCF 代理。
解決方案2 建立新 類別庫(可攜式)
- 在方案 XFWebSrv 節點上滑鼠右擊,選擇
加入
>新的專案
>Visual C#
>類別庫(可攜式)
,接著在下方名稱欄位旁的文字輸入盒,輸入XFWCFPCL
千萬注意,不可以選擇類別庫 (可移植到 iOS、Android、Windows)
這個類別庫 - 當出現 加入可攜式類別庫 對話窗,點選
確定
按鈕 - 在 XFWCFPCL 專案內,滑鼠右擊
參考
節點,選擇加入服務參考
選項 - 當
加入服務參考
對話窗出現的時候,在位置欄位,輸入http://wcfservice120160626121524.azurewebsites.net/Service1.svc
,接著點選移至
按鈕,確認所要定義的命名空間,最後按下確定
按鈕,產生 WCF Proxy Class - 滑鼠右擊 XFWCFPCL 專案節點,選擇
加入
>類別
選項,在名稱欄位文字輸入盒中填入WCFServiceBase
,接著按下確定
按鈕 - 將底下程式碼複製到這個檔案內。
WCFServiceBase
這個類別將會透過相依性服務注入的方式,讓核心PCL專案可以使用這個 WCF 功能。
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
namespace XFWCFPCL
{
public class WCFServiceBase
{
public Task<int> Sum(int v1, int v2)
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
var binding = new BasicHttpBinding()
{
Name = "basicHttpBinding",
MaxReceivedMessageSize = 67108864,
};
var timeout = new TimeSpan(0, 1, 0);
binding.SendTimeout = timeout;
binding.OpenTimeout = timeout;
binding.ReceiveTimeout = timeout;
var client = new ServiceReference1.Service1Client(binding, new EndpointAddress("http://wcfservice120160626121524.azurewebsites.net/Service1.svc"));
client.GetSumDataCompleted += (s,e) =>
{
};
client.GetSumDataAsync(v1, v2);
return tcs.Task;
}
}
}
MainPage
- 當上述準備工作已經就緒,接下來就可以開始在核心PCL專案內寫相關商業邏輯程式碼了。
- 打開核心PCL 的 MainPage.xaml 檔案,將底下的 XAML 宣告定義複製到這個檔案內。
- 這個頁面宣告內容相當簡單,使用版面配置
StackLayout
將其包含的控制項,以垂直的方式排列 - 共有兩個按鈕,一個是呼叫 RESTful Web API,另外一個是呼叫 WCF,他們皆會先從
Entry
控制項中取得使用者所輸入的整數值,經會 Web 服務計算過後,將計算後的值,顯示在Label
控制項內 Entry
控制項內,使用了Keyboard
屬性,定義使用者只能夠輸入數字。
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XFWebSrv"
x:Class="XFWebSrv.MainPage">
<ContentPage.Padding>30</ContentPage.Padding>
<StackLayout
Orientation="Vertical"
>
<Entry x:Name="entryValue1" Keyboard="Numeric" Text="168" />
<Entry x:Name="entryValue2" Keyboard="Numeric" Text="99" />
<Label x:Name="labelRESTful" />
<Button x:Name="buttonRESTful" Text="呼叫 RESTful" Clicked="OnRESTfulClicked" />
<Label x:Name="labelWCF" />
<Button x:Name="buttonWCF" Text="呼叫 WCF" Clicked="OnWCFClicked" />
</StackLayout>
</ContentPage>
- 請將下列 C# 程式碼複製到 MainPage.xaml.cs內。
- 在建構式內,使用了
MessagingCenter
訂閱了一個訊息事件,也就是當使用者有選擇某個日期之後,其相對應的 callback 就會執行,在這裡,將會取出透過訊息中心所傳遞過來的日期參數,並且將其顯示在指定Label
上。 - 在 掃描QRCode 按鈕事件內, 使用了相依性注入服務
DependencyService
取得當時行動平台實作的 QRCode 掃描物件,並且呼叫ScanAsync
這個方法,取得QRCode掃描結果,並且顯示到指定的Label
。 - 在 選擇日期 按鈕事件內,則是透過
Navigation.PushModalAsync
方法,開啟一個對話窗頁面,該頁面為CalendarPage
MainPage.xaml.cs
- OnRESTfulClicked這個按鈕事件,展示了如何呼叫 RESTful Web API 的方式,透過
HttpClient
物件的 GetStringAsync 的非同步方法。 - OnWCFClicked這個按鈕事件,展示了如何呼叫 WCF 的方式,透過
DependencyService.Get
靜態方法,取得在該行動裝置平台下實作的物件,並且呼叫實作的 Sum() 方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace XFWebSrv
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
async void OnRESTfulClicked(object sender, EventArgs e)
{
var fooURL = $"http://doggyrestfulapi.azurewebsites.net/api/SumData?value1={entryValue1.Text}&value2={entryValue2.Text}";
var fooClient = new HttpClient();
var fooResult = await fooClient.GetStringAsync(fooURL);
labelRESTful.Text = $"透過 RESTful API 計算出的結果 : {fooResult}";
}
async void OnWCFClicked(object sender, EventArgs e)
{
int v1 = int.Parse(entryValue1.Text);
int v2 = int.Parse(entryValue2.Text);
int v3 = await DependencyService.Get<IWCFService>().Sum(v1, v2);
labelWCF.Text = $"透過 WCF 計算出的結果 : {v3}"; ;
}
}
}
相依性服務定義
核心PCL
- 請在 XFWebSrv 核心PCL 專案節點使用滑鼠右擊該節點,選擇
加入
>類別
,當加入新項目 - XFWebSrv
對話窗出現後,點選Visual C#
>類別
,最後在下方名稱欄位的文字輸入盒內,輸入IWCFService
。 - 請將底下 C# 程式碼複製到這個檔案內。
IWCFService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XFWebSrv
{
public interface IWCFService
{
Task<int> Sum(int v1, int v2);
}
}
Android 專案
- 請在 XFWebSrv.Droid 專案下的
參考
節點,使用滑鼠右擊該節點,選擇加入參考
,當參考管理員 - XFWebSrv.Droid
對話窗出現後,點選專案
>方案
,最後勾選XFWCFPCL
- 請在 XFWebSrv.Droid 專案節點使用滑鼠右擊該節點,選擇
加入
>類別
,當加入新項目 - XFWebSrv.Droid
對話窗出現後,點選Visual C#
>Class
,最後在下方名稱欄位的文字輸入盒內,輸入WCFService
。 - 請將底下 C# 程式碼複製到這個檔案內。
WCFService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using XFWCFPCL;
using XFWebSrv.Droid;
[assembly: Xamarin.Forms.Dependency(typeof(WCFService))]
namespace XFWebSrv.Droid
{
public class WCFService : WCFServiceBase, IWCFService
{
}
}
iOS 專案
- 請在 XFWebSrv.iOS 專案下的
參考
節點,使用滑鼠右擊該節點,選擇加入參考
,當參考管理員 - XFWebSrv.Droid
對話窗出現後,點選專案
>方案
,最後勾選XFWCFPCL
- 請在 XFWebSrv.iOS 專案節點使用滑鼠右擊該節點,選擇
加入
>類別
,當加入新項目 - XFWebSrv.iOSDroid
對話窗出現後,點選Apple
>類別
,最後在下方名稱欄位的文字輸入盒內,輸入WCFService
。 - 請將底下 C# 程式碼複製到這個檔案內。
WCFService.cs
using System;
using System.Collections.Generic;
using System.Text;
using XFWCFPCL;
using XFWebSrv.iOS;
[assembly: Xamarin.Forms.Dependency(typeof(WCFService))]
namespace XFWebSrv.iOS
{
public class WCFService : WCFServiceBase, IWCFService
{
}
}
實際執行畫面
Android 執行結果
請在方案總管內,滑鼠右擊
XFWebSrv.Droid
專案,選擇 設定為起始專案
,接著按下 F5
開始執行。
佈署注意事項
iOS 執行結果
請在方案總管內,滑鼠右擊
XFWebSrv.iOS
專案,選擇 設定為起始專案
,接著按下 F5
開始執行。