<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 云連接移動應用 - 借助身份驗證和離線支持構建 Xamarin 應用 作者:[Kraig Brockschmidt](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Kraig+Brockschmidt)、[Erik Reitan](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Erik+Reitan)、[Mike Wasson](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Mike+Wasson)、[Rick Anderson](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Rick+Anderson)、[Tom Dykstra](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Tom+Dykstra)?| September 2015 |?[獲取代碼](http://aka.ms/altostratusproject) 如八月期刊第一部分(系列共兩部分)“使用 Azure Web 應用和 WebJobs 創建 Web 服務” ([msdn.microsoft.com/magazine/mt185572](https://msdn.microsoft.com/magazine/mt185572))中所述,現在很多移動應用都可以連接到提供有價值且有趣的數據的一個或多個 Web 服務。對這些服務直接發起 REST API 調用并在客戶端中處理響應,盡管這非常簡單,但此類方法過于消耗電池電量,而且很多服務強制執行了帶寬和各類限制。此外,低端硬件的性能也可能會下降。將任務卸載到自定義后端是可行的,如我們在“Altostratus”項目中的演示(我們將在本文中繼續討論)。 第一部分中討論的 Altostratus 后端定義會定期從 StackOverflow 和 Twitter(只是為了使用兩種不同的數據源)中收集和規范化“對話”,并將它們存儲到 Microsoft Azure 數據庫中。這意味著,客戶端所需的確切數據可直接由后端提供,同時可允許我們調整 Azure 中的后端范圍,以便為任意數量的客戶端提供空間,而不會達到原始提供程序設置的限制。除規范化后端數據以匹配客戶端需求外,我們還使用 Web API 優化數據交換,以節約移動設備的稀缺資源。 在本文中,我們將討論客戶端應用的詳細信息(請參閱圖 1)。首先,我們從應用的體系結構入手,設置整體上下文,然后轉入 Xamarin 和 Xamarin.Forms 的使用、使用后端進行身份驗證、構建脫機緩存并在 Team Foundation Server (TFS) 和 Visual Studio Online 上使用 Xamarin 進行構建。 ![](https://box.kancloud.cn/2016-01-08_568f81ea8453e.png)? 圖 1 運行在 Android 平板電腦(左側)、Windows Phone(中間)和 iPhone(右側)上的 Xamarin 移動應用 ## 客戶端應用體系結構 客戶端應用包含三個主要頁面或視圖: 配置、主頁和項,它們的類將共享這些名稱(請參閱圖 2)。輔助登錄頁沒有 UI,只是作為 OAuth 提供程序網頁的宿主。借助基本的模型-視圖-視圖模型 (MVVM) 結構,每個主頁(“登錄”頁除外)都具有關聯的視圖模型類來處理表示項、類別和配置設置(包括身份驗證提供程序的列表)的視圖和數據模型類之間的綁定關系。 ![](https://box.kancloud.cn/2016-01-08_568f81eaacf2d.png)? 圖 2 Altostratus 客戶端應用的體系結構,顯示涉及的主要類的名稱(除非有指定,否則項目中的文件將匹配這些類名稱) (注意: 通常,開發人員傾向于將 XAML 視圖分離到可移植類庫 [PCL](與視圖模型和其他類分離),讓設計人員可以使用 Blend 等工具對這些視圖單獨執行操作。我們沒有進行分離:一來是使項目保留簡單的結構;二來是因為 Blend 目前無法與 Xamarin.Forms 中的控件一起使用)。 數據模型始終會填充本地 SQLite 數據庫中的這些項目,它們在應用首次運行時已進行了預填充。數據模型中與后端同步的過程非常簡單:檢索新數據(盡可能少,從而將網絡流量減至最低)、使用該數據更新數據庫、清除所有舊數據并指示數據模型刷新其對象。這將觸發 UI 的更新,這要歸功于數據與視圖模型進行了綁定。 我們稍后會探討,多個不同事件將觸發同步:UI 中的刷新按鈕、更改配置、對后端進行身份驗證(將檢索以前保存的配置)以及在至少 30 分鐘后恢復應用等。當然,同步是通過后端的 Web API 與后端的主要通信,但是后端還提供 API 以用于注冊用戶,檢索經過身份驗證的用戶設置,并在經過身份驗證的用戶更改配置之后更新這些設置。 ## 適用于跨平臺客戶端的 Xamarin.Forms 您可能已經在 MSDN 雜志中了解到,可以通過 Xamarin 使用 C# 和 Microsoft .NET Framework 通過在各個平臺共享的大量代碼構建適用于 Android、iOS 和 Windows 的應用。(有關我們的開發配置的概述,請參閱后面的部分“針對 TFS 和 VSO 使用 Xamarin 進行構建”。)通過為 XAML/C# 提供常見的 UI 解決方案,Xamarin.Forms 框架對此做出了進一步的貢獻。借助 Xamarin.Forms,Altostratus 項目在單個 PCL 中共享了該項目的 95% 以上的代碼。事實上,該項目中僅特定于平臺的代碼是啟動位,其有以下幾個來源:項目模板、處理 Web 瀏覽器控件的登錄頁的呈現器,以及用于將預填充的 SQLite 數據庫復制到本地存儲中的相應讀寫位置的幾行代碼。 請注意,還可以對 Xamarin 項目進行配置以使用共享項目,而非 PCL。但是,Xamarin 建議使用 PCL,而且使用 Altostratus 的主要優點在于,我們可以在 Win32 控制臺應用程序中使用同一 PCL 來創建預填充數據庫。這意味著,我們無需為此復制任何數據庫代碼,初始值設定項程序將始終與應用的其余部分保持同步。 請注意,共享代碼并沒有明顯減少在每個目標平臺上完全測試應用的工作量;如果您以本機方式編寫每個應用,則流程的該部分將花費同樣長的時間。此外,由于 Xamarin.Forms 是新事物,您可能會發現特定于平臺的 bug 或您需要在代碼中處理的其他行為。有關我們在編寫 Altostratus 時發現的一些行為的詳細信息,請訪問?[bit.ly/1g5EF4j](http://bit.ly/1g5EF4j)?查看文章。 如果您遇到奇怪的問題,應首先前往 Xamarin bug 數據庫 ([bugzilla.xamarin.com](http://bugzilla.xamarin.com/))。如果在其中找不到關于問題的討論,可以將問題發布到 Xamarin 論壇 ([forums.xamarin.com](http://forums.xamarin.com/)),您會發現 Xamarin 員工很樂意回復您的問題。 也就是說,與詳細了解每個單獨平臺的 UI 層相比,處理此類個別問題的工作量相當少。而且,由于 Xamarin.Forms 相對來說屬于新事物,發現此類問題有助于使框架越來越強大。 ## 特定于平臺的調整 在 Xamarin.Forms 中,有時很有必要對一個平臺或其他平臺進行調整,如微調布局。(有關示例,請參閱 Charles Petzold 的優秀書籍《Programming Mobile Apps with Xamarin.Forms》[[bit.ly/1H8b2q6](http://bit.ly/1H8b2q6)])。 您可能還需要處理一些不一致行為,如 webview 元素觸發它的第一個導航事件(同樣,有關我們遇到的一些不一致行為,請訪問?[bit.ly/1g5EF4j](http://bit.ly/1g5EF4j)?查看我們的文章)。 為此,Xamarin.Forms 包含 API Device.OnPlatform(iOS_valueAndroid_value, Windows_value) 和匹配的 XAML 元素。可以推測出,OnPlatform 根據當前運行時返回不同的值。例如,以下 XAML 代碼隱藏了 Windows Phone 上配置頁面的登錄控件,因為 Xamarin.Auth 組件尚且不支持該平臺,因此我們始終運行未經身份驗證的 (configuration.xaml): ~~~ <StackLayout Orientation="Vertical"> ? <StackLayout.IsVisible> ??? <OnPlatform x:TypeArguments="x:Boolean" Android="true" iOS="true" ????? WinPhone="false" /> ? </StackLayout.IsVisible> ? <Label Text="{ Binding AuthenticationMessage }" FontSize="Medium" /> ? <Picker x:Name="providerPicker" Title="{ Binding ProviderListLabel }" ??? IsVisible="{ Binding ProviderListVisible }" /> ? <Button Text="{ Binding LoginButtonLabel}" Clicked="LoginTapped" /> </StackLayout> ~~~ 談到組件,Xamarin 本身主要是由提取本機平臺常見功能的組件構建而成,其中很多組件先于 UI 的 Xamarin.Forms。其中某些組件內置于 Xamarin 中,而包括社區貢獻在內的其他組件需要從[components.xamarin.com](http://components.xamarin.com/)?獲取。除 Xamarin.Auth 外,Altostratus 還使用連接性插件 ([tinyurl.com/xconplugin](http://tinyurl.com/xconplugin)) 顯示指示器,并在設備離線時禁用刷新按鈕。 我們發現在設備上更改連接(反映在插件的 IsConnected 屬性中)與插件觸發其事件之間始終存在一些延遲。這意味著,在設備離線與刷新按鈕更改為禁用狀態之間有幾秒鐘時間。為了處理此問題,我們使用刷新命令事件來查看插件的 IsConnected 狀態。如果為離線,則立刻禁用按鈕,但會設置一個標志來指示 ConnectivityChanged 處理程序在恢復連接時自動啟動同步。 Altostratus 還使用 Xamarin.Auth ([tinyurl.com/xamauth](http://tinyurl.com/xamauth)) 來通過 OAuth 處理身份驗證的詳細信息,我們即將討論此內容。這里需要注意的是,該組件目前只支持 iOS 和 Android,不支持 Windows Phone,而且也不在我們修復特定缺陷的項目范圍內。幸運的是,該客戶端應用在未經身份驗證的情況下仍可以正常運行,這表明用戶的設置沒有保留在云中,而且與后端的數據交換沒有完全優化。組件獲取更新可以支持 Windows 之后,我們只需刪除之前所示的 XAML 中的 OnPlatform 標記,將登錄控件設置為可見。 ## 后端身份驗證 從整體角度來說,在 Altostratus 應用程序中,我們想要演示在后端存儲一些特定于用戶的首選項所涉及的機制,以便在處理 HTTP 請求時后端可以自動應用這些首選項。當然,對于此特定的應用程序,我們本可以使用 URI 參數和請求獲得相同的結果,但此類示例不能作為更加復雜的方案的基礎。在服務器上存儲首選項還可以讓它們在用戶的所有設備之間漫游。 使用任何類型的特定于用戶的數據意味著對該唯一的用戶進行身份驗證。請注意,這與授權不同。身份驗證是識別用戶并對用戶身份進行驗證的一種方法。另一方面,授權與任何特定用戶(例如,管理員、普通用戶、來賓)具備的權限有關。 對于身份驗證,我們通過 Google 和 Facebook 等第三方使用社交登錄名,而非實現自己的憑據系統(而且后端包含 API,可由客戶端應用用于檢索配置頁面 UI 的提供程序列表)。社交登錄名的主要優點在于,我們不必處理憑據或其隨附的安全和隱私問題;后端將只會存儲電子郵件地址作為用戶名,而且客戶端只在運行時管理訪問令牌。否則,提供程序需要執行所有這些繁重的任務,包括電子郵件驗證、密碼檢索等。 當然,并非所有人都有社交登錄名提供程序的帳戶,出于隱私的原因,某些用戶不想使用社交媒體帳戶。同樣,社交登錄名可能不適用于業務線應用;對于這類情況,我們建議使用 Azure Active Directory。不過,對我們來說,這是一個邏輯選擇,因為我們只需要通過某些方式來對單個用戶進行身份驗證。 通過身份驗證之后,用戶有權在后端保存首選項。如果我們想要實現其他級別的授權(如修改其他用戶的首選項),后端可以根據權限數據庫檢查用戶名。 在 ASP.NET Web API 中為社交登錄名使用 OAuth2?OAuth2 ([bit.ly/1SxC1AM](http://bit.ly/1SxC1AM)) 是一個授權框架,允許用戶在沒有共享其憑據的情況下授予對資源的訪問權限。它定義了多個“憑據流”,用于指定憑據在各實體之間的傳遞方式。ASP.NET Web API 使用所謂的“隱式授予流”,移動應用在其中既不收集憑據,也不存儲任何密碼信息。該工作由 OAuth2 提供程序和 ASP.NET 標識庫 ([asp.net/identity](http://asp.net/identity)) 分別來完成。 若要啟用社交登錄名,您必須通過應用開發人員門戶將您的應用程序注冊到每個登錄提供程序。(此上下文中的“應用程序”表示所有客戶端體驗,包括移動和 Web,且不局限于移動應用)。注冊后,提供程序將為您提供一個唯一的客戶端 ID 和密碼。有關示例,請參閱?[bit.ly/1BniZ89](http://bit.ly/1BniZ89)。 我們使用這些值來初始化 ASP.NET 標識中間件,如圖 3?中所示。 圖 3 初始化 ASP.NET 標識中間件 ~~~ var fbOpts = new FacebookAuthenticationOptions { ? AppId = ConfigurationManager.AppSettings["FB_AppId"], ? AppSecret = ConfigurationManager.AppSettings["FB_AppSecret"] }; fbOpts.Scope.Add("email"); app.UseFacebookAuthentication(fbOpts); var googleOptions = new GoogleOAuth2AuthenticationOptions() { ? ClientId = ConfigurationManager.AppSettings["GoogleClientID"], ? ClientSecret = ConfigurationManager.AppSettings["GoogleClientSecret"] }; app.UseGoogleAuthentication(googleOptions); ~~~ 類似于“FB_AppID”的字符串是有關 Web 應用的環境和配置設置的密鑰,其中存儲了實際 ID 和密碼。您可以進行更新,而無需重新構建和重新部署應用。 使用 Xamarin.Auth 處理憑據流總體而言,社交身份驗證過程涉及應用、后端和提供程序之間的各種握手。幸運的是,Xamarin.Auth 組件(可從 Xamarin 組件存儲中獲取)為應用處理了大部分任務。這包括使用瀏覽器控件并提供回調掛鉤,以便應用可在授權完成后作出回應。 在初始狀態下,Xamarin.Auth 可讓客戶端應用執行部分授權事宜,這意味著該應用會存儲客戶端 ID 和密碼。雖然這與 ASP.NET 流稍有不同,但 Xamarin.Auth 包含構造良好的類層次結構。Xamarin.Auth.O-Auth2Authenticator 類派生自 WebRedirectAuthenticator,為我們提供了所需的基本功能,僅需編寫少量的其他代碼,可從 Android 和 iOS 項目(Xamarin.Auth 尚不支持 Windows)中的 LoginPageRenderer.cs 文件中找到。有關我們此處執行的操作的更多詳細信息,請訪問[tinyurl.com/kboathalto](http://tinyurl.com/kboathalto)?查看我們的博客文章。 然后,客戶端應用具有派生自 Xamarin.Forms 的基本 ContentPage 的 LoginPage 類,允許我們導航到該位置。此類公開兩種方法:CompleteLoginAsync 和 CancelAsync,這兩種方法根據用戶在提供程序的 Web 界面中執行的操作從 LoginPageRenderer 代碼中調用。 發送經過身份驗證的請求?成功登錄之后,客戶端應用會擁有一個訪問令牌。若要發出經過身份驗證的請求,則請求僅包含如下 Authorization 標頭中的該令牌: ~~~ GET http://hostname/api/UserPreferences HTTP/1.1 Authorization: Bearer I6zW8Dk... Accept: */* X-Requested-With: XMLHttpRequest User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko ~~~ 此處,“Bearer”指示使用持有者令牌的授權,其后是較長的不透明的令牌字符串。 我們為包含自定義消息處理程序的所有 REST 請求使用 System.Net.Http.HttpClient 庫,以將身份驗證標頭添加到每個請求中。消息處理程序是插件組件,允許您檢查并修改 HTTP 請求和響應消息。若要了解更多信息,請參閱?[bit.ly/1MyMMB8](http://bit.ly/1MyMMB8)。 消息處理程序在類 Authentication-MessageHandler (webapi.cs) 中實現,并在創建 HttpClient 實例時安裝: ~~~ _httpClient = HttpClientFactory.Create( ? handler, new AuthenticationMessageHandler(provider)); ~~~ ITokenProvider 接口只是處理程序從應用中獲取訪問令牌的一種方法(這在 model.cs 中的 UserPreferences 類中實現)。針對每個 HTTP 請求調用 SendAsync 方法;如圖 4?所示,如果令牌提供程序包含一個可使用的標頭,則它將添加 Authorization 標頭。 圖 4 添加 Authorization 標頭 ~~~ public interface ITokenProvider { ? string AccessToken { get; } } class AuthenticationMessageHandler : DelegatingHandler { ? ITokenProvider _provider; ? public AuthenticationMessageHandler(ITokenProvider provider) ? { ???? _provider = provider; ? } ? protected override Task<HttpResponseMessage> ??? SendAsync(HttpRequestMessage request, ??? System.Threading.CancellationToken cancellationToken) ? { ??? var token = _provider.AccessToken; ??? if (!String.IsNullOrEmpty(token)) ??? { ????? request.Headers.Authorization = ??????? new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); ??? } ??? return base.SendAsync(request, cancellationToken); ? } } ~~~ 如本文第一部分中所述,如果在后端收到令牌和請求,則該令牌可用于檢索該用戶的首選項,并自動將它們應用到請求的其余部分。例如,如果用戶將會話限制設置為 25(而非默認的 100),則最多和請求一起返回 25 個項,從而節省網絡帶寬。 ## 為后端數據構建脫機緩存 與移動 Web 相比,移動應用的一大優勢是能夠靈活支持脫機使用情況。根據定義,移動應用始終呈現在用戶的設備上,并且可以使用各種數據存儲選項(如 SQLite)來保留脫機數據緩存,而不是依賴基于瀏覽器的機制。 事實上,Altostratus 移動客戶端的 UI 只使用在本地 SQLite 數據庫中保留的數據,這就使應用在不連接的情況下完全正常運行。當存在連接時,后臺進程會從后端檢索當前數據以更新數據庫。這會更新位于數據庫之上的數據模型對象,這反過來會通過數據綁定觸發 UI 更新(可以返回圖 2?查看相關內容)。這樣一來,它就非常類似于第一部分中討論的后端體系結構,其中正在運行的 webjobs 收集、規范化并在 SQL Server 數據庫中存儲數據,以便 Web API 可以直接從該數據庫中提供請求。 Altostratus 的脫機支持涉及三個不同的任務: * 將預填充的數據庫文件直接置于應用程序包中,以便在首次運行時即可提供工作數據,而無需連接。 * 為在 UI 中出現的數據模型的各個部分實現單向同步過程:會話(項)、類別、身份驗證提供程序和用戶首選項。 * 將同步掛接到除 UI 中的刷新按鈕之外的相應觸發器。 讓我們逐個進行了解。 創建預填充的數據庫?用戶可以從在線商店中安裝應用,但在設備脫機后,需要一段時間后才能運行。問題是,您是希望應用告知:“抱歉,只有在聯機狀態下才能執行有用的操作”? 還是希望應用可以智能地處理此類情況? 為了演示后一種方法,Altostratus 客戶端直接在每個平臺上的應用程序包中加入了一個預填充的 SQLite 數據庫(位于每個平臺項目的資源/原始文件夾)。在首次運行時,客戶端會將此數據庫文件復制到設備上的讀寫位置,然后以獨占的方式在該位置中使用它。因為每個平臺對應唯一的文件復制過程,我們在運行時使用 Xamarin.Forms.DependencyService 功能來解析定義為 ISQLite 的接口的具體實現。DataAccessLayer 構造函數 (DataAccess.cs) 中將發生這種情況,然后調用 ISQLite.GetDatabasePath 來檢索復制后的讀寫數據庫文件的特定于平臺的位置(如圖 5?中所示)。 圖 5 檢索數據庫文件的特定于平臺的位置 ~~~ public DataAccessLayer(SQLiteAsyncConnection db = null) { ? if (db == null) ? { ??? String path = DependencyService.Get<ISQLite>().GetDatabasePath(); ??? db = new SQLiteAsyncConnection(path);??????????????? ??? // Alternate use to use the synchronous SQLite API: ??? // database = SQLiteConnection(path);??????????????? ? } ? database = db; ? _current = this; } ~~~ 為創建初始數據庫,Altostratus 解決方案包含較小的 Win32 控制臺應用程序,稱為 DBInitialize。它使用相同的共享 PCL 作為應用來使用數據庫,因此絕不會出現第二個不匹配的基本代碼的問題。但是,DBInitialize 無需使用 DependencyService: 它可以直接創建文件并打開連接: ~~~ string path = "Altostratus.db3"; SQLiteAsyncConnection conn = new SQLiteAsyncConnection(path); var dbInit = new DataAccessLayer(conn); ~~~ 此處,DBInitialize 調用 DataAccessLayer.InitAsync 來創建表(應用從未對預填充的數據庫執行此類操作)并使用其他 DataAccessLayer 方法從后端獲取數據。請注意,借助異步調用,DBInitialize 只使用 .Wait,因為它是一個控制臺應用程序,無需擔心響應式 UI: ~~~ DataModel model = new DataModel(dbInit); model.InitAsync().Wait(); model.SyncCategories().Wait(); model.SyncAuthProviders().Wait(); model.SyncItems().Wait(); ~~~ 為提供用戶可查看的內容,它使用計時器每隔半秒在屏幕上放置一個點。 請注意,您始終要使用 DB Browser for SQLite ([bit.ly/1OCkm8Y](http://bit.ly/1OCkm8Y)) 等工具來查看預填充的數據庫,然后將其導入項目中。一個或多個 Web 請求可能會失敗,在這些情況下,數據庫將無效。您可以將此邏輯構建到 DBInitialize 中,以便它刪除數據庫并顯示錯誤。在本例中,我們只是監視錯誤消息并根據需要再次運行程序。 您可能會問:“預填充數據庫的內容是否不會相對較快地過時? 我不希望我的應用用戶在首次運行時看到陳舊的數據!” 當然,如果您不定期更新應用,確實會出現以上情況。因此,您要提交應用的定期更新,其中包括數據庫以及相對較新的數據(這取決于您的數據的性質)。 如果用戶已安裝該應用,則更新不會產生任何影響,因為復制打包的數據庫文件的代碼會查看讀寫副本是否已存在,然后直接使用該副本。但是,如果只是檢查文件是否存在,則一段時間內未運行應用的用戶可以停止啟動包含舊數據(而不是更近時間內更新的程序包中的數據)的應用。您可以查看緩存數據庫的時間戳是否比程序包內的時間戳更早,并使用較新的副本覆蓋該緩存。雖然這并非在 Altostratus 中實現的內容,但我們也需要保留現有數據庫中的用戶首選項信息。 將脫機緩存與后端同步?如前面提到的,Altostratus 客戶端會始終針對它的緩存數據庫來運行。發送到后端的所有 Web 請求(上載新的用戶首選項除外)在同步緩存的上下文中發起。其適用機制作為 DataModel 類的一部分來實現,尤其是通過 sync.cs 中的四種方法實現: SyncSettings(委托給 model.cs 中的 Configuration.ApplyBack endConfiguration)、SyncCategories、SyncAuthProviders 和 SyncItems。很顯然,這四種方法中的主力是 SyncItems,我們將在下一部分中探討是什么觸發了這四種方法。 請注意,Altostratus 只朝一個方向同步數據,從后端到本地緩存。此外,我們知道我們感興趣的數據不會更新得太快(考慮到后端 webjobs 的計劃),因此我們只會關心與后端數據存儲的最終一致性,而不是按照分鐘或秒的順序進行更新。 從本質上來說,每個同步過程都是相同的: 從后端檢索當前數據,使用新值更新本地數據庫,從數據庫中刪除所有舊值,然后重新填充數據模型對象以觸發 UI 更新。 對于項,還需要執行一些操作,因為可從 UI 中調用 SyncItems,并且我們想防止過于激動的用戶重復按下按鈕。專用 DataModel.syncTask 屬性指示是否存在活動項同步;如果 syncTask 為非 null,則 SyncItems 會忽略重復請求。此外,由于項請求可能需要一段時間并且涉及較大的數據集,因此,我們想在設備處于脫機狀態的情況下取消項同步。為此,我們保存任務的 System.Threading.CancellationToken。 如圖 6?中所示,專用 SyncItemsCore 方法是此過程的核心。它從數據庫中檢索上次同步的時間戳,并隨 Web 請求加入此時間戳。 圖 6 專用 SyncItemsCore 方法 ~~~ private async Task<SyncResult> SyncItemsCore() { ? SyncResult result = SyncResult.Success; ? HttpResponseMessage response; ? Timestamp t = await DataAccessLayer.Current.GetTimestampAsync(); ? String newRequestTimestamp = ??? DateTime.UtcNow.ToString(WebAPIConstants.ItemsFeedTimestampFormat); ? response = await WebAPI.GetItems(t, syncToken); ? if (!response.IsSuccessStatusCode) ? { ??? return SyncResult.Failed; ? } ? t = new Timestamp() { Stamp = newRequestTimestamp }; ? await DataAccessLayer.Current.SetTimestampAsync(t); ? if (response.StatusCode == System.Net.HttpStatusCode.NoContent) ? { ??? return SyncResult.NoContent; ? } ? var items = await response.Content.ReadAsAsync<IEnumerable<FeedItem>>(); ? await ProcessItems(items); ? // Sync is done, refresh the ListView data source. ? await PopulateGroupedItemsFromDB(); ? return result; } ~~~ 通過執行此操作,后端僅返回給定時間之后的新項或更新項。因此,客戶端只獲取它真正需要的數據,這就節省了用戶可能有限的數據計劃。這也意味著,客戶端在處理每個請求中的數據時工作量較少,這也節省了電池能量并可將網絡流量降至最低。盡管聽起來不是很多,但處理每個類別的 5 個會話(而不是每個請求的 50 個)減少了 90% 的工作量。如果每天進行 20 到 30 次同步,那么一個應用一個月時間內可輕松累積到數百兆字節。簡言之,您的客戶肯定會感激您在優化流量方面做出的努力! 請求返回之后,ProcessItems 方法將所有這些項添加到數據庫,對標題進行一些清理工作(如刪除智能引號),并提取有關說明正文的前 100 個字符以在主列表中顯示。我們可以讓后端執行標題清理操作,這可以節省客戶端上的一些處理時間。我們選擇將其留在客戶端上是因為其他方案需要執行特定于平臺的調整。我們還可以讓后端創建 100 個字符的說明,這意味著可節省客戶端的一些處理時間,但會增加網絡流量。對于我們在此處使用的數據,這可能是一種折中方案,由于 UI 最終是客戶端的職責,因此讓客戶端來執行此步驟似乎是更好的做法。(有關此內容和其他 UI 注意事項的更多詳細信息,請訪問[tinyurl.com/kboathaltoxtra](http://tinyurl.com/kboathaltoxtra)?參閱我們的博客文章)。 將項添加到數據庫之后,會通過 PopulateGroupedItemsFromDB 刷新數據模型組。這里,數據庫包含的項可能多于用戶當前會話限制設置所需的項,了解這一點非常重要。通過將該限制直接應用于數據庫查詢,PopulateGroupedItemsFromDB 證明了這一點。 不過,隨著時間的推移,我們不希望數據庫通過保留大量永遠不再顯示的項來不斷擴展。為此,SyncItems 調用 DataAccessLayer.ApplyConversationLimit 方法來選擇數據中的舊項,直到項的數量滿足指定限制。因為 Altostratus 數據集內的所有單個項的大小都相對較小,因此我們使用最大會話限制 100,無需考慮用戶的當前設置。這樣一來,如果用戶提高該限制,我們就無需再次從后端中請求數據。但是,如果我們的數據項較大,則最好主動選擇數據庫并根據需要重新請求項。 同步觸發器?很顯然,UI 中的刷新按鈕是項同步發生的主要方式,但是其他同步進程何時會發生? 項同步是否有其他觸發器? 就代碼來說,回答這些問題需要一些技巧,因為對 Sync* 方法的調用都發生在同一位置,即 HomeViewModel.Sync 方法。但是,此方法和輔助入口點 HomeViewModel.CheckTimeAndSync 都是從其他不同位置調用的。以下是通過 SyncExtent 枚舉中的值對同步調用進行參數化的時間、位置和方式的摘要: * 啟動之后,HomeViewModel 構造函數使用一勞永逸的模式調用 Sync(SyncExtent.All),因此同步完全是在后臺發生的。該模式只表示將異步方法中的返回值保存到本地變量中,以禁止有關未使用 await 的編譯器警告。 * 在 Connectivity 插件的 ConnectivityChanged 事件的處理程序的內部,當執行之前的調用(使用與當時請求時相同的盤區)時,我們會在設備處于脫機狀態時調用 Sync。 * 如果用戶訪問配置頁面并更改活動類別或會話限制,或登錄后端并應用后端設置,則 DataModel.Configuration.HasChanged 標志會記住這一事實。當用戶返回到主頁時, HomePage.OnAppearing 處理程序會調用 HomeViewModel.CheckRefresh,其會檢查 HasChanged 并根據需要調用 Sync(SyncExtent.Items)。 * App.OnResume event (app.cs) 調用 CheckTimeAndSync,其會應用某些邏輯,根據應用掛起時間來確定同步內容。很明顯,這些條件高度依賴您的數據和后端操作的性質。 * 最后,刷新按鈕調用帶有標志的 CheckTimeAndSync,以始終至少執行一個項同步。刷新按鈕使用 CheckTimeAndSync,因為用戶可能(盡管可能性很小)使應用程序在前臺運行半小時以上,甚至一天,在這種情況下,刷新按鈕還應執行我們在恢復時執行的其他同步。 將所有內容整合到 HomeViewModel.Sync 中的一個好處是它可以在適當的時間設置公共 HomeViewModel.IsSyncing 屬性。此屬性是數據綁定到 Home.xaml 中的 Xamarin.Forms.ActivityIndicator 的 IsVisible 和 IsRunning 屬性。設置此標志的簡單行為可控制該指示器的可見性。 ## 在 TFS 和 Visual Studio Online 上使用 Xamarin 進行構建 對于 Altostratus 項目,我們使用了在某種程度上跨平臺工作的通用開發環境:安裝仿真器的 Windows PC、Android 和 Windows Phone 的受限設備以及安裝 iOS 仿真器和受限 iOS 設備的本地 Mac OS X 計算機(請參閱圖 7)。通過此類設置,您可以使用 Mac OS X 計算機進行遠程 iOS 構建和調試,從而直接在 PC 上的 Visual Studio 中執行所有開發和調試工作。此外,還可以從 Mac 中提交存儲就緒的 iOS 應用。 ![](https://box.kancloud.cn/2016-01-08_568f81eabf8b7.png)? 圖 7 Xamarin 項目的通用跨平臺開發環境以及使用 Visual Studio Tools for Apache Cordova 等其他技術的開發環境 我們為進行團隊協作和源控制部署了 Visual Studio Online,并對其進行配置,為后端和 Xamarin 客戶端執行連續集成生成。如果我們立即啟動此項目,將能夠使用最新的 Visual Studio Online 生成系統來直接在托管生成控制器中構建 Xamarin 應用。有關更多信息,請訪問?[tinyurl.com/kboauthxamvso](http://tinyurl.com/kboauthxamvso)?查看我們的博客文章。不過,2015 年早些時候,托管生成控制器尚且不具備此項支持。幸運的是,將運行 TFS 的本地計算機用作 Visual Studio Online 的生成控制器確實是一件非常簡單的事情。在該服務器上,我們安裝了 Xamarin 隨附的免費 TFS Express 版本以及必要的 Android 和 Windows 平臺 SDK,并確保將 Android SDK 存放到 c:\android-sdk 等生成帳戶可以訪問的位置。(默認情況下,它的安裝程序將 SDK 存放到當前用戶的存儲中,生成帳戶沒有權限訪問)。?[bit.ly/1OhQPSW](http://bit.ly/1OhQPSW)?中的 Xamarin 文檔“配置 Team Foundation Server for Xamarin”有關于這一點的討論。 完全配置了生成服務器之后,通過以下步驟連接到 Visual Studio Online(請參閱?[bit.ly/1RJS4QL](http://bit.ly/1RJS4QL)?中的“部署和配置生成服務器”): 1. 打開 TFS 管理控制臺。 2. 在左側導航窗格中,展開服務器名稱,然后選擇“生成配置”。 3. 在生成服務下,單擊“屬性”,打開“生成服務屬性”對話框。 4. 單擊對話框頂部的“停止服務”。 5. 在“通信”下,在“為項目集合提供生成服務”下的框中輸入您的 Visual Studio Online 集合的 URL,例如,https://.visualstudio.com/defaultcollection。 6. 單擊對話框底部的“啟動”按鈕重啟服務。 這就完成了所有操作! 當您在 Visual Studio 團隊資源管理器 中創建生成定義時,連接到 Visual Studio Online 的 TFS 計算機將顯示在可用的生成控制器的列表中。選擇該選項后,您從 Visual Studio 中排隊或在簽入后排隊的生成將被路由到 TFS 計算機。 ## 總結 我們希望您會喜歡我們對于 Altostratus 項目的探討,并且您會發現這些代碼適用于您自己的移動云連接應用。同樣,我們對于此項目的目標是為跨平臺移動應用的清晰示例提供一個自定義后端,該后端可以代表客戶端執行重要的工作以優化需要客戶端直接執行的工作。通過讓始終運行的后端代表所有客戶端收集數據,我們極大地減少了客戶端生成的網絡流量(及其對數據計劃的后續影響)。通過規范化來自不同源的數據,我們盡可能減少客戶端上的必要的數據處理,這節省了日益重要的電池電量。通過使用后端進行身份驗證,我們演示了一些可用方法,在后端存儲用戶首選項并自動將它們應用到客戶端與后端的互動中,這同樣優化了網絡流量和處理要求。我們知道,對于我們的特定要求,有更加簡便的方法可以達到相同的效果,但我們想創建一個可擴展到更加復雜的方案的示例。 我們樂于聽取您對于此項目的意見和建議。請向我們提供反饋! ### Azure 脫機同步 實現自己的脫機緩存的一個替代方法是表的 Azure 脫機同步,這是 Azure 移動服務的一部分。這將完全沒有必要編寫任何同步代碼,并且無需執行將客戶端中的更改推送到服務器的操作。但是,因為它使用表存儲,因此不像 SQLite 一樣提供相關的數據模型。 * * * Kraig Brockschmidt?*擔任 Microsoft 高級內容開發人員,側重于跨平臺移動應用。他是 Microsoft Press 出版的《Programming Windows Store Apps with HTML, CSS and JavaScript》(兩個版本)和?[kraigbrockschmidt.com](http://kraigbrockschmidt.com/)?上的博客的作者。* Mike Wasson?*是 Microsoft 的內容開發人員。多年來,他一直負責撰寫 Win32 多媒體 API 的文檔。目前,他正在撰寫 Microsoft Azure 和 ASP.NET。* Rick Anderson?*擔任 Microsoft 的高級編程人員,側重于 ASP.NET MVC、Microsoft Azure 和實體框架。您可以通過 Twitter 關注他:[twitter.com/RickAndMSFT](http://twitter.com/RickAndMSFT)。* Erik Reitan?*是 Microsoft 的高級內容開發人員。他側重于 Microsoft Azure 和 ASP.NET。通過 Twitter 關注他:[twitter.com/ReitanErik](http://twitter.com/ReitanErik)。* Tom Dykstra?*是 Microsoft 的高級內容開發人員,側重于 Microsoft Azure and ASP.NET。*
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看