XAML in Xamarin.Forms 基礎篇 電子書

XAML in Xamarin.Forms 基礎篇 電子書
XAML in Xamarin.Forms 基礎篇 電子書

Xamarin.Forms 快速入門 電子書

Xamarin.Forms 快速入門 電子書
Xamarin.Forms 快速入門 電子書

2017/04/17

Xamarin.Forms 與 Azure Mobile App Lab 6

在 Xamarin.Forms 專案,修正使用 Azure 行動應用的線上資料表

在這裡,我們將要把我們寫好的 Xamarin.Forms 專案,加入使用 Azure 行動應用服務功能。

第一次準備工作

在您原先做好的 Xamarin.Forms 專案中,需要加入相關 NuGet 套件與建立一個 MobileServiceClient 物件

加入 NuGet 套件

  • 使用 Visual Studio 2015 打開 XFDoggy.sln 專案
  • 滑鼠右擊 方案XFDoggy,選擇 管理方案的 NuGet套件
  • 在 瀏覽 標籤頁次的搜尋文字輸入盒內,填入 Microsoft.Azure.Mobile.Client 搜尋這個套件
  • 點選所有專案都要安裝這個套件,並點選 安裝 按鈕

加入 MobileServiceClient 物件

  • 滑鼠右擊核心PCL專案的 XFDoggy,點選 加入 > 新增資料夾
  • 輸入 Helpers
  • 滑鼠右擊核心PCL專案的 核心PCL專案 資料夾,點選 加入 > 類別
  • 在對話窗中,點選 Visual C# > 類別
  • 在名稱欄位輸入 MainHelper,最後點選 新增 按鈕
  • 將 MainHelper 類別修改成底下的程式碼
    請修正相關命名空間錯誤
    public class MainHelper
    {
        /// <summary>
        /// 指向 Azure Mobile App 服務的主要網址
        /// </summary>
        public static string MainURL = "https://xamarinazureday.azurewebsites.net";
        /// <summary>
        /// Azure Mobile App 線上版本的用戶端
        /// </summary>
        public static MobileServiceClient client = new MobileServiceClient(MainURL);
    }
關於建立 MobileServiceClient 物件的時候,需要傳遞的 URL 參數 ( 行動應用的主要 URL ),您可以從 Azure 儀表板中,找到 XamarinAzureDay 行動應用程式,在這個 XamarinAuzreDay App Service 刀鋒視窗中,預設會開啟 概觀 標籤頁次,您可以從右方看到 URL 欄位,這裡就是這個行動應用的主要 URL。
請使用 Https 的通訊協定

修改 Xamarin.Forms 專案

在這裡,我們將要修正 差旅費用 申請作業的相關功能;在這裡,我們需要修正兩個頁面的 ViewModel,分別是,顯示清單與紀錄新增或修改頁面。原則上,我們在這裡並不會修正原有這個頁面中 Xamarin.Forms 的程式處理邏輯。

建立資料表會用到的資料模型

  • 滑鼠右擊核心PCL專案的 Models 資料夾,點選 加入 > 類別
  • 在對話窗中,點選 Visual C# > 類別
  • 在名稱欄位輸入 BusinessTripExpense,最後點選 新增 按鈕
  • 將 BusinessTripExpense 類別修改成底下的程式碼
    public class BusinessTripExpense
    {
        public string Id { get; set; }
        public DateTime 出差日期 { get; set; }
        public string 類型 { get; set; }
        public string 項目名稱 { get; set; }
        public string 地點 { get; set; }
        public double 費用 { get; set; }
        public string 備註 { get; set; }
        public bool 國內外 { get; set; }
        public bool 是否有單據 { get; set; }
    }

在 ViewMolde 加入這個資料表的 CRUD 行動應用服務功能。

  • 在核心PCL專案內,找到資料夾 ViewModels 內的 差旅費用申請HomePageViewModel.cs
  • 滑鼠雙擊這個檔案,打開它

宣告 Azure 行動應用服務資料物件

  • 我們需要加入 Azure 行動應用服務的資料表宣告,這樣,我們才能夠針對遠端 SQL Server 資料庫內的資料表,進行 CRUD 處理。
    請解析要加入的適當命名空間
        IMobileServiceTable<BusinessTripExpense> 差旅費用Table = MainHelper.client.GetTable<BusinessTripExpense>();

查詢/排序/過濾紀錄

  • 要從遠端SQL資料庫內查詢資料表內的所有資料,可以使用底下程式碼。
    您可以針對 差旅費用Table 物件,使用 LINQ 方法,進行所要查詢資料的條件、排序行為等等工作,Azure 行動應用服務物件會將您的需求透過 OData 要求轉譯成 SQL 查詢。
            #region 呼叫 Azure 行動應用後台,取得最新後台資料表的清單
            var fooList = await 差旅費用Table.OrderByDescending(x => x.出差日期).ToListAsync();
            foreach (var item in fooList)
            {
                foo差旅費用項目 = new 差旅費用項目ViewModel
                {
                    ID = item.Id,
                    出差日期 = item.出差日期,
                    項目名稱 = item.項目名稱,
                    地點 = item.地點,
                    類型 = item.類型,
                    是否有單據 = item.是否有單據,
                    國內外 = item.國內外,
                    費用 = item.費用,
                    備註 = item.備註,
                };
                差旅費用項目清單.Add(foo差旅費用項目);
            }
            #endregion

新增紀錄

  • 要新增一筆資料到遠端SQL資料庫內,可以使用底下程式碼
    產生一個新的資料表紀錄物件,呼叫 差旅費用Table.InsertAsync,便可新增一筆紀錄到遠端SQL資料庫內
    在這裡,請不要指定 Id 屬性有任何值,就樣才能夠讓 Azure 行動應用用戶端幫我們新增一筆記錄到資料表中
                        #region Azure 行動應用服務的新增
                        foo差旅費用 = new BusinessTripExpense
                        {
                            備註 = x.差旅費用項目.備註,
                            出差日期 = x.差旅費用項目.出差日期,
                            國內外 = x.差旅費用項目.國內外,
                            地點 = x.差旅費用項目.地點,
                            是否有單據 = x.差旅費用項目.是否有單據,
                            費用 = x.差旅費用項目.費用,
                            項目名稱 = x.差旅費用項目.項目名稱,
                            類型 = x.差旅費用項目.類型,
                        };
                        await 差旅費用Table.InsertAsync(foo差旅費用);
                        await Init();
                        #endregion

修改紀錄

  • 要修改一筆資料到遠端SQL資料庫內,可以使用底下程式碼
    差旅費用Table.UpdateAsync,便可修改遠端SQL資料庫的紀錄
                        #region Azure 行動應用服務的新增
                        foo差旅費用 = await 差旅費用Table.LookupAsync(x.差旅費用項目.ID);
                        foo差旅費用.備註 = x.差旅費用項目.備註;
                        foo差旅費用.出差日期 = x.差旅費用項目.出差日期;
                        foo差旅費用.國內外 = x.差旅費用項目.國內外;
                        foo差旅費用.地點 = x.差旅費用項目.地點;
                        foo差旅費用.是否有單據 = x.差旅費用項目.是否有單據;
                        foo差旅費用.費用 = x.差旅費用項目.費用;
                        foo差旅費用.項目名稱 = x.差旅費用項目.項目名稱;
                        foo差旅費用.類型 = x.差旅費用項目.類型;

                        await 差旅費用Table.UpdateAsync(foo差旅費用);
                        #endregion

刪除紀錄

  • 要刪除一筆資料到遠端SQL資料庫內,可以使用底下程式碼
    差旅費用Table.DeleteAsync,便可刪除遠端SQL資料庫的紀錄
                        #region Azure 行動應用服務的新增
                        foo差旅費用 = await 差旅費用Table.LookupAsync(x.差旅費用項目.ID);
                        await 差旅費用Table.DeleteAsync(foo差旅費用);
                        #endregion

完整的 差旅費用申請HomePage View / ViewModels

差旅費用申請HomePage.xaml

這裡修正了一些物件名稱
<?xml version="1.0" encoding="utf-8" ?>
<!--NavigationPage.BackButtonTitle="上一頁" 這個設定,主要是針對 iOS 平台來使用到的-->
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             xmlns:localControls="clr-namespace:XFDoggy.CustomControls"
             xmlns:behaviors="clr-namespace:XFDoggy.Behaviors"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="XFDoggy.Views.差旅費用申請HomePage"
             Title="差旅費用申請"
             x:Name="ThisPage"
             NavigationPage.BackButtonTitle="上一頁">

    <!--這個頁面的版面配置-->
    <!--Data Binding 資料繫結請參考:https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/-->
    <Grid
        RowSpacing="0" ColumnSpacing="0"
        BackgroundColor="{StaticResource 頁面背景Color}"
        >
        <!--該頁面的主要背景顏色設定-->
        <Grid
            RowSpacing="0" ColumnSpacing="0"
            Margin="10"
            BackgroundColor="{StaticResource 頁面內容本文背景Color}"
            >
            <Grid.RowDefinitions>
                <!--這個部分為頁面標題與文字的空間規劃-->
                <RowDefinition Height="40"/>
                <!--這個部分是其他內容區域-->
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>

            <!--頁面標題與文字-->
            <Grid
                RowSpacing="0" ColumnSpacing="0"
                BackgroundColor="{StaticResource 頁面內容標題背景Color}"
                >
                <Grid.RowDefinitions>
                    <RowDefinition Height="40"/>
                </Grid.RowDefinitions>
                <Label
                    Text="差旅費用申請清單"                    
                    Style="{StaticResource 頁面內文標題文字Style}"
                    />
            </Grid>

            <!--清單資料-->
            <!--ListView 請參考:https://developer.xamarin.com/api/type/Xamarin.Forms.ListView/-->
            <ListView
                HorizontalOptions="Fill" VerticalOptions="Fill"
                Grid.Row="1"
                ItemsSource="{Binding 差旅費用項目清單}"
                SelectedItem="{Binding 點選差旅費用項目, Mode=TwoWay}"
                SeparatorVisibility="None"
                HasUnevenRows="True"
                >
                <!--這個部分為要使用 MVVM 綁定命令方式,將要透過 XAML Behavior來做到-->
                <!--Xamarin.Forms Behavior 請參考:https://developer.xamarin.com/guides/xamarin-forms/behaviors/-->
                <ListView.Behaviors>
                    <behaviors:EventHandlerBehavior EventName="ItemTapped">
                        <behaviors:InvokeCommandAction Command="{Binding 點選差旅費用項目Command}"  />
                    </behaviors:EventHandlerBehavior>
                </ListView.Behaviors>
                <ListView.ItemTemplate>
                    <!--定義每筆紀錄要出現的樣貌-->
                    <DataTemplate>
                        <!--ViewCell 請參考:https://developer.xamarin.com/api/type/Xamarin.Forms.ViewCell/-->
                        <ViewCell>
                            <Grid
                                RowSpacing="0" ColumnSpacing="0"
                                >
                                <StackLayout
                                    Orientation="Vertical"
                                    >
                                    <Label
                                        Margin="10,0"
                                        Text="{Binding 出差日期, StringFormat='{0:yyyy-MM-dd}'}}"
                                        TextColor="Black"
                                        FontSize="24"
                                        HorizontalOptions="Start" VerticalOptions="Start"
                                        LineBreakMode="WordWrap">
                                    </Label>
                                    <StackLayout
                                        Orientation="Horizontal"
                                        Margin="0,5">
                                        <Label
                                            Margin="10,0,0,0"
                                            Text="{Binding 類型}"
                                            TextColor="Black"
                                            FontSize="14"
                                            HorizontalOptions="Start" VerticalOptions="Start"
                                            LineBreakMode="TailTruncation"
                                            WidthRequest="150">
                                        </Label>
                                        <Label
                                            Margin="10,0,10,0"
                                            Text="{Binding 費用, StringFormat='{0} 元'}"
                                            TextColor="Black"
                                            FontSize="14"
                                            HorizontalOptions="End" VerticalOptions="Start"
                                            LineBreakMode="TailTruncation">
                                        </Label>
                                    </StackLayout>
                                </StackLayout>

                                <!--分隔線-->
                                <BoxView 
                                    HorizontalOptions="Fill" VerticalOptions="End"
                                    HeightRequest="2"
                                    Color="#8c8c8c" />
                            </Grid>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

        </Grid>
        <!--新增按鈕-->
        <!--這裡採用浮動式的按鈕設計-->
        <Grid
            RowSpacing="0" ColumnSpacing="0"
            HorizontalOptions="End" VerticalOptions="End"
            Margin="0,0,30,30"
            >
            <BoxView Color="Black" WidthRequest="50" HeightRequest="50"/>
            <localControls:FontAwesomeLabel 
                Text="&#xf067;"
                Font="36"
                TextColor="White"
                HorizontalOptions="Center" VerticalOptions="Center"
                >
                <localControls:FontAwesomeLabel.GestureRecognizers>
                    <TapGestureRecognizer Command="{Binding 新增按鈕Command}" />
                </localControls:FontAwesomeLabel.GestureRecognizers>
            </localControls:FontAwesomeLabel>
        </Grid>
    </Grid>

</ContentPage>

差旅費用申請HomePageViewModel.cs

這裡修正了一些物件名稱
    public class 差旅費用申請HomePageViewModel : BindableBase, INavigationAware
    {
        #region Repositories (遠端或本地資料存取)
        // 取得 Azure Mobile App 中的 差旅費用 資料表物件
        IMobileServiceTable<BusinessTripExpense> 差旅費用Table = MainHelper.client.GetTable<BusinessTripExpense>();
        #endregion

        #region ViewModel Property (用於在 View 中作為綁定之用)
        #region 差旅費用項目清單
        private ObservableCollection<差旅費用項目ViewModel> _差旅費用項目清單 = new ObservableCollection<差旅費用項目ViewModel>();
        /// <summary>
        /// 工作日報表項目清單
        /// </summary>
        public ObservableCollection<差旅費用項目ViewModel> 差旅費用項目清單
        {
            get { return _差旅費用項目清單; }
            set { SetProperty(ref _差旅費用項目清單, value); }
        }
        #endregion

        #region 點選差旅費用項目
        private 差旅費用項目ViewModel _點選差旅費用項目;
        /// <summary>
        /// PropertyDescription
        /// </summary>
        public 差旅費用項目ViewModel 點選差旅費用項目
        {
            get { return this._點選差旅費用項目; }
            set { this.SetProperty(ref this._點選差旅費用項目, value); }
        }
        #endregion

        #endregion

        #region Field 欄位
        BusinessTripExpense foo差旅費用;

        public DelegateCommand 點選差旅費用項目Command { get; set; }
        public DelegateCommand 新增按鈕Command { get; set; }

        private readonly INavigationService _navigationService;
        private readonly IEventAggregator _eventAggregator;
        #endregion

        #region Constructor 建構式
        public 差旅費用申請HomePageViewModel(INavigationService navigationService, IEventAggregator eventAggregator)
        {

            #region 相依性服務注入的物件

            _eventAggregator = eventAggregator;
            _navigationService = navigationService;
            #endregion

            #region 頁面中綁定的命令
            點選差旅費用項目Command = new DelegateCommand(async () =>
            {
                #region 建立要傳遞到下個頁面的參數
                var fooNavigationParameters = new NavigationParameters();
                fooNavigationParameters.Add("點選工作日報表項目", 點選差旅費用項目);
                fooNavigationParameters.Add("新增或修改", 新增或修改Enum.修改);
                #endregion

                //點選工作日報表項目 = null;

                await _navigationService.NavigateAsync("差旅費用申請紀錄修改Page", fooNavigationParameters);
            });

            新增按鈕Command = new DelegateCommand(async () =>
            {
                #region 建立要傳遞到下個頁面的參數
                var fooNavigationParameters = new NavigationParameters();
                fooNavigationParameters.Add("點選工作日報表項目", new 差旅費用項目ViewModel());
                fooNavigationParameters.Add("新增或修改", 新增或修改Enum.新增);
                #endregion

                await _navigationService.NavigateAsync("差旅費用申請紀錄修改Page", fooNavigationParameters);
            });
            #endregion

            #region 事件聚合器訂閱
            _eventAggregator.GetEvent<差旅費用紀錄維護動作Event>().Subscribe(async x =>
            {
                switch (x.新增或修改Enum)
                {
                    case 新增或修改Enum.新增:
                        #region Azure 行動應用服務的新增
                        foo差旅費用 = new BusinessTripExpense
                        {
                            備註 = x.差旅費用項目.備註,
                            出差日期 = x.差旅費用項目.出差日期,
                            國內外 = x.差旅費用項目.國內外,
                            地點 = x.差旅費用項目.地點,
                            是否有單據 = x.差旅費用項目.是否有單據,
                            費用 = x.差旅費用項目.費用,
                            項目名稱 = x.差旅費用項目.項目名稱,
                            類型 = x.差旅費用項目.類型,
                        };
                        await 差旅費用Table.InsertAsync(foo差旅費用);
                        await Init();
                        #endregion
                        break;
                    case 新增或修改Enum.修改:
                        #region 更新欄位資料
                        var fooObj = 差旅費用項目清單.FirstOrDefault(z => z.ID == x.差旅費用項目.ID);
                        if (fooObj != null)
                        {
                            var fooIdx = 差旅費用項目清單.IndexOf(fooObj);
                            差旅費用項目清單[fooIdx] = x.差旅費用項目;
                        }

                        #region Azure 行動應用服務的新增
                        foo差旅費用 = await 差旅費用Table.LookupAsync(x.差旅費用項目.ID);
                        foo差旅費用.備註 = x.差旅費用項目.備註;
                        foo差旅費用.出差日期 = x.差旅費用項目.出差日期;
                        foo差旅費用.國內外 = x.差旅費用項目.國內外;
                        foo差旅費用.地點 = x.差旅費用項目.地點;
                        foo差旅費用.是否有單據 = x.差旅費用項目.是否有單據;
                        foo差旅費用.費用 = x.差旅費用項目.費用;
                        foo差旅費用.項目名稱 = x.差旅費用項目.項目名稱;
                        foo差旅費用.類型 = x.差旅費用項目.類型;

                        await 差旅費用Table.UpdateAsync(foo差旅費用);
                        #endregion
                        #endregion
                        break;
                    case 新增或修改Enum.刪除:
                        var fooObjDel = 差旅費用項目清單.FirstOrDefault(z => z.ID == x.差旅費用項目.ID);
                        if (fooObjDel != null)
                        {
                            差旅費用項目清單.Remove(fooObjDel);
                        }

                        #region Azure 行動應用服務的新增
                        foo差旅費用 = await 差旅費用Table.LookupAsync(x.差旅費用項目.ID);
                        await 差旅費用Table.DeleteAsync(foo差旅費用);
                        #endregion
                        break;
                    default:
                        break;
                }
            });
            #endregion
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {
        }

        public async void OnNavigatedTo(NavigationParameters parameters)
        {
            if (parameters.ContainsKey("差旅費用紀錄維護動作內容") == false)
            {
                await Init();
            }
        }
        #endregion

        #region Navigation Events (頁面導航事件)
        #endregion

        #region 設計時期或者執行時期的ViewModel初始化
        #endregion

        #region 相關事件
        #endregion

        #region 相關的Command定義
        #endregion

        #region 其他方法
        /// <summary>
        /// 進行要顯示資料的初始化
        /// </summary>
        private async Task Init()
        {
            差旅費用項目ViewModel foo差旅費用項目;

            差旅費用項目清單.Clear();

            #region 呼叫 Azure 行動應用後台,取得最新後台資料表的清單
            var fooList = await 差旅費用Table.OrderByDescending(x => x.出差日期).ToListAsync();
            foreach (var item in fooList)
            {
                foo差旅費用項目 = new 差旅費用項目ViewModel
                {
                    ID = item.Id,
                    出差日期 = item.出差日期,
                    項目名稱 = item.項目名稱,
                    地點 = item.地點,
                    類型 = item.類型,
                    是否有單據 = item.是否有單據,
                    國內外 = item.國內外,
                    費用 = item.費用,
                    備註 = item.備註,
                };
                差旅費用項目清單.Add(foo差旅費用項目);
            }
            #endregion
        }
        #endregion

    }

iOS 原生專案修正

  • 打開 iOS 原生專案中 AppDelegate.cs 檔案
  • 在類別 AppDelegate 的 FinishedLaunching 方法內的呼叫 FinishedLaunching 方法前,加入底下程式碼
            Microsoft.WindowsAzure.MobileServices.CurrentPlatform.Init();

實際執行結果

在這裡,我們使用 Android 平台做為測試標的
我們在這裡可以新增任意數量紀錄,也可以隨意修改與刪除

檢測後端資料庫儲存結果

您可以使用 PostMan 來取得後端SQL資料庫內的 差旅費用 資料表,實際儲存的紀錄內容。
在這裡,我們將會使用底下 URL 來查詢(記得要加入適當的 Header)
底下是實際查詢結果內容
[
  {
    "deleted": false,
    "updatedAt": "2017-02-12T07:36:18.204Z",
    "createdAt": "2017-02-12T07:31:55.314Z",
    "version": "AAAAAAAACAE=",
    "id": "6de91a3368964410b514d50e22a3f1a6",
    "是否有單據": false,
    "國內外": true,
    "備註": null,
    "費用": 5200,
    "地點": "Taipei",
    "項目名稱": "Accommondation cost",
    "類型": "Hotel",
    "出差日期": "2017-02-11T16:00:00Z"
  },
  {
    "deleted": false,
    "updatedAt": "2017-02-12T07:30:20.064Z",
    "createdAt": "2017-02-12T07:30:20.064Z",
    "version": "AAAAAAAAB/w=",
    "id": "dbdf03a4240b4a84b9e0ac9d42510182",
    "是否有單據": false,
    "國內外": true,
    "備註": "By Uber",
    "費用": 310,
    "地點": "Taipei",
    "項目名稱": "Airport to Hotel",
    "類型": "Traffic Taxi",
    "出差日期": "2017-02-10T16:00:00Z"
  }
]

Xamarin.Forms 與 Azure Mobile App Lab 5

在 Azure 行動應用後端專案,新增差旅費用頁面需要用的資料表

為了要進行這個部分練習,需要建立一個新的SQL Database資料表,因此,我們需要啟用 Code First Migration 功能,來幫助我們依據專案內的資料模型,進行自動調整遠端資料庫內的綱要 (Schema) 內容。
  • 開啟您從 Azure Moible App 項目中下載的 XamarinAzureService 內的 XamarinAzureDay.sln Visual Studio 專案
    下圍呈現了這個 Visual Studio 方案/專案的結構
  • 按下 F5 ,在本地端執行這個專案
    您可以使用 PostMan 來檢查本地端執行與運作結果是否正常
  • 中斷除錯執行
  • 點選功能表 工具 > NuGet封裝管理員 > 套件管理員主控台
  • 在 套件管理員主控台 中輸入底下指令
Enable-Migrations
完成後,會出現底下訊息
Checking if the context targets an existing database...
Detected database created with a database initializer. Scaffolded migration '201702111723152_InitialCreate' corresponding to existing database. To use an automatic migration instead, delete the Migrations folder and re-run Enable-Migrations specifying the -EnableAutomaticMigrations parameter.
Code First Migrations enabled for project XamarinAzureDayService.
  • 接著,執行底下指令
Add-Migration Initial
完成後,會出現底下訊息
Scaffolding migration 'Initial'.
The Designer Code for this migration file includes a snapshot of your current Code First model. This snapshot is used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include in this migration, then you can re-scaffold it by running 'Add-Migration Initial' again.
  • 打開資料夾 App_Start 底下的 Startup.MobileApp.cs 檔案
  • 在這個檔案最上方加入底下 using
using System.Data.Entity.Migrations;
using XamarinAzureDayService.Migrations;
  • 將這行程式碼註解起來 Database.SetInitializer(new XamarinAzureDayInitializer());
  • 在剛剛註解的程式碼後,加入底下程式碼
            var migrator = new DbMigrator(new Migrations.Configuration());
            migrator.Update();
  • 按下 F5 ,在本地端執行這個專案
    您可以使用 PostMan 來檢查本地端執行與運作結果是否正常
  • 中斷除錯執行

建立資料傳輸物件 (DTO) 類別

接下來,我們需要修改這個後端 API 專案,讓這個專案可以提供更多的功能。
  • 為了要開始產生一個我們自訂的資料表,我們需要定義資料表控制器, 設定資料表控制器需要三個步驟︰
這裡,我們需要定義一個差旅費用的申請紀錄表單,用來定義 SQL Database 內的資料表。
  • 請滑鼠右擊 DataObjects 資料夾,選擇 加入 > 類別
  • 在對話窗下方的 名稱 輸入 BusinessTripExpense
  • 點選 新增 按鈕
  • 請將剛剛產生的類別 BusinessTripExpense,修改成為如下程式碼:
    public class BusinessTripExpense : EntityData
    {
        public DateTime 出差日期 { get; set; }
        public string 類型 { get; set; }
        public string 項目名稱 { get; set; }
        public string 地點 { get; set; }
        public double 費用 { get; set; }
        public string 備註 { get; set; }
        public bool 國內外 { get; set; }
        public bool 是否有單據 { get; set; }
    }
若有找不到的類別或者命名空間,請點選燈泡來修正

EntityData 類別

每個要新增的資料表類別,需要繼承 EntityData 這個類別,這個類別的定義如下。
    public bool Deleted { get; set; }
您可以看到我們並不需要額外定義 Id 作為每筆紀錄的唯一紀錄欄位,因為在 EntityData 內已經幫我們加入進來了 (要實作出 ITableData 這個介面);而其他的欄位 CreatedAt / Deleted / UpdatedAt / Version 將會用於方便 Azure Mobile 服務進行使用 Entity Framework 工作處理之用。
    //
    // 摘要:
    //     An abstract implementation of the Microsoft.Azure.Mobile.Server.Tables.ITableData
    //     interface indicating how the system properties for a given table data model are
    //     to be serialized when communicating with clients when using Entity Framework
    //     for accessing the backend store. The uniform serialization of system properties
    //     ensures that the clients can process the system properties uniformly across platforms.
    //     Concrete entity framework models can derive from this base class in order to
    //     support the system properties.
    public abstract class EntityData : ITableData
    {
        protected EntityData();

        [System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedAttribute]
        [Index(IsClustered = true)]
        [TableColumn(TableColumnType.CreatedAt)]
        public DateTimeOffset? CreatedAt { get; set; }
        [TableColumn(TableColumnType.Deleted)]
        public bool Deleted { get; set; }
        [System.ComponentModel.DataAnnotations.KeyAttribute]
        [TableColumn(TableColumnType.Id)]
        public string Id { get; set; }
        [System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedAttribute]
        [TableColumn(TableColumnType.UpdatedAt)]
        public DateTimeOffset? UpdatedAt { get; set; }
        [TableColumn(TableColumnType.Version)]
        [System.ComponentModel.DataAnnotations.TimestampAttribute]
        public byte[] Version { get; set; }
    }

建立資料表控制器。

如果已安裝 Azure SDK,您現在可以建立範本資料表控制器,請進行底下操作

使用 Azure 行動應用程式資料表控制器

  • 滑鼠右擊 Controller 資料夾,選擇 加入 > 控制器
  • 在對話窗中,選擇 Azure 行動應用程式資料表控制器
  • 點選新增按鈕
  • 在出現 新增控制器 對話窗,請輸入或者選擇如下圖結果
    模型類別:您剛剛定義的 SQL 資料表型別,可用下拉選單來選擇
    資料內容類別:,也就是這個專案內繼承 DbContext 的類別,可用下拉選單來選擇
    控制器名稱:可以使用自動產生的名稱,注意,最後面一定要有 Controller
  • 點選 新增 按鈕,完成這個資料表控制器產生動作。
  • 底下為產生後的 BusinessTripExpenseController 資料控制器程式碼
    您可以看到,對於差旅費用資料表的基本 CRUD API 程式碼,都已經幫您自動產生好了
    這裡請特別注意,在使用 Azure Mobile App 的資料表控制項類別中,必須要繼承 TableController 這個類別,而不是要使用 ApiController 類別
    public class BusinessTripExpenseController : TableController<BusinessTripExpense>
    {
        protected override void Initialize(HttpControllerContext controllerContext)
        {
            base.Initialize(controllerContext);
            XamarinAzureDayContext context = new XamarinAzureDayContext();
            DomainManager = new EntityDomainManager<BusinessTripExpense>(context, Request);
        }

        // GET tables/BusinessTripExpense
        public IQueryable<BusinessTripExpense> GetAllBusinessTripExpense()
        {
            return Query(); 
        }

        // GET tables/BusinessTripExpense/48D68C86-6EA6-4C25-AA33-223FC9A27959
        public SingleResult<BusinessTripExpense> GetBusinessTripExpense(string id)
        {
            return Lookup(id);
        }

        // PATCH tables/BusinessTripExpense/48D68C86-6EA6-4C25-AA33-223FC9A27959
        public Task<BusinessTripExpense> PatchBusinessTripExpense(string id, Delta<BusinessTripExpense> patch)
        {
             return UpdateAsync(id, patch);
        }

        // POST tables/BusinessTripExpense
        public async Task<IHttpActionResult> PostBusinessTripExpense(BusinessTripExpense item)
        {
            BusinessTripExpense current = await InsertAsync(item);
            return CreatedAtRoute("Tables", new { id = current.Id }, current);
        }

        // DELETE tables/BusinessTripExpense/48D68C86-6EA6-4C25-AA33-223FC9A27959
        public Task DeleteBusinessTripExpense(string id)
        {
             return DeleteAsync(id);
        }
    }

加入 Migration

  • 點選功能表 工具 > NuGet封裝管理員 > 套件管理員主控台
  • 在 套件管理員主控台 中輸入底下指令
Add-Migration BusinessTripExpense
  • 按下 F5 ,在本地端執行這個專案
    您可以使用 PostMan 來檢查本地端執行與運作結果是否正常
  • 中斷除錯執行

發佈到 Azure 雲端上

PostMan 測試資料

本地端

Azure

Header 資訊

Key : ZUMO-API-VERSION
Value : 2.0.0

這個練習範例專案,請參考

XamarinAzureService_Custom