2017-02-18 108 views
1

我找不到概述了使用OneDrive來存儲和保持在C#中跨設備syncrhonised應用程序文件的正確方式的任何文件正確的使用方法OneDrive API來同步文件

我在OneDrive Dev Center閱讀文檔,但我不明白的http代碼。 (僅自學C#)。

我知道我使用delta方法從OneDrive中獲取已更改的文件,然後在本地保存,但我無法弄清楚如何,所以通過使用GetAsync<>手動檢查本地vs OneDrive方法。 我的當前實現(以下僅供參考)在我看來相當笨拙,而API可能處理得更好。

此外,它似乎沒有反向'delta'功能?也就是說,我在本地嚮應用程序寫入文件的位置,然後告訴OneDrive同步更改。那是因爲我需要使用PutAsync<>方法實際上傳它嗎? (目前我在做什麼)

public async Task<T> ReadFromXML<T>(string gamename, string filename) 
    { 
     string filepath = _appFolder + @"\" + gamename + @"\" + filename + ".xml"; 
     T objectFromXML = default(T); 
     var srializer = new XmlSerializer(typeof(T)); 
     Item oneDItem = null; 
     int casenum = 0; 
     //_userDrive is the IOneDriveClient 
     if (_userDrive != null && _userDrive.IsAuthenticated) 
     { 
      try 
      { 
       oneDItem = await _userDrive.Drive.Special.AppRoot.ItemWithPath(filepath).Request().GetAsync(); 
       if (oneDItem != null) casenum += 1; 
      } 
      catch (OneDriveException) 
      { } 
     } 
     StorageFile localfile = null; 
     try 
     { 
      localfile = await ApplicationData.Current.LocalFolder.GetFileAsync(filepath); 
      if (localfile != null) casenum += 2; 
     } 
     catch (FileNotFoundException) 
     { } 
     switch (casenum) 
     { 
      case 0: 
       //neither exist. Throws exception to tbe caught by the calling method, which should then instantiate a new object of type <T> 
       throw new FileNotFoundException(); 
      case 1: 
       //OneDrive only - should copy the stream to a new local file then return the object 
       StorageFile writefile = await ApplicationData.Current.LocalFolder.CreateFileAsync(filepath, CreationCollisionOption.ReplaceExisting); 
       using (var newlocalstream = await writefile.OpenStreamForWriteAsync()) 
       { 
        using (var oneDStream = await _userDrive.Drive.Special.AppRoot.ItemWithPath(filepath).Content.Request().GetAsync()) 
        { 
         oneDStream.CopyTo(newlocalstream); 
        } 
       } 
       using (var newreadstream = await writefile.OpenStreamForReadAsync()) 
       { objectFromXML = (T)srializer.Deserialize(newreadstream); } 
       break; 
      case 2: 
       //Local only - returns the object 
       using (var existinglocalstream = await localfile.OpenStreamForReadAsync()) 
       { objectFromXML = (T)srializer.Deserialize(existinglocalstream); } 
       break; 
      case 3: 
       //Both - compares last modified. If OneDrive, replaces local data then returns the object 
       var localinfo = await localfile.GetBasicPropertiesAsync(); 
       var localtime = localinfo.DateModified; 
       var oneDtime = (DateTimeOffset)oneDItem.FileSystemInfo.LastModifiedDateTime; 
       switch (oneDtime > localtime) 
       { 
        case true: 
         using (var newlocalstream = await localfile.OpenStreamForWriteAsync()) 
         { 
          using (var oneDStream = await _userDrive.Drive.Special.AppRoot.ItemWithPath(filepath).Content.Request().GetAsync()) 
          { oneDStream.CopyTo(newlocalstream); } 
         } 
         using (var newreadstream = await localfile.OpenStreamForReadAsync()) 
         { objectFromXML = (T)srializer.Deserialize(newreadstream); } 
         break; 
        case false: 
         using (var existinglocalstream = await localfile.OpenStreamForReadAsync()) 
         { objectFromXML = (T)srializer.Deserialize(existinglocalstream); } 
         break; 
       } 
       break; 
     } 
     return objectFromXML; 
    } 
+0

不確定您要做什麼。 Windows 10有一個驅動器文件夾,您可以將其設置爲在本地同步文件。 –

+0

據我所知,該文件夾不可用在電話設備上,只有桌面(可能還有平板電腦,但我沒有一個可以驗證)。儘管如此,我們的目標是將數據保存到本地設備,將文件同步到OneDrive,以便其他設備可以保持最新狀態(並執行相同的操作)。數據文件太大而無法使用「RoamingData」。 – Lindsay

+2

如果您願意,可以使用c#sdk。 https://github.com/onedrive/onedrive-sdk-csharp要記住的一件事是一個驅動器可以存儲該文件的最新版本。如果您需要進行任何同步(即結合來自本地驅動器和一個驅動器版本的數據),則必須在您的代碼中完成同步。 –

回答

2

同步需要幾個不同的步驟,其中一些OneDrive API將幫助您,其中一些你必須做你自己。

變化檢測
第一階段顯然是檢測是否有任何變化。該OneDrive API提供了兩種機制,以檢測服務的變化:

  1. 可以使用具有If-None-Match標準要求進行檢測單個文件的更改:

    await this.userDrive.Drive.Special.AppRoot.ItemWithPath(remotePath).Content.Request(new Option[] { new HeaderOption("If-None-Match", "etag") }).GetAsync(); 
    

    如果該文件不存在在所有你會得到一個404 Not Found。 否則,如果文件沒有改變,你會得到一個304 Not Modified
    否則你會得到文件的當前狀態。

  2. 的層次結構的變化可以使用delta API進行檢測:

    await this.userDrive.Drive.Special.AppRoot.Delta(previousDeltaToken).Request().GetAsync(); 
    

    這將返回當前狀態以來的delta上一次調用已更改的所有項目。如果這是第一次調用,則previousDeltaToken將爲空,API將返回AppRoot內所有項目的當前狀態。對於響應中的每個文件,您需要再次往返服務以獲取內容。

在本地端,您需要枚舉所有感興趣的文件,並比較時間戳來確定,如果事情發生了變化。

很明顯,前面的步驟需要了解「最後看到」狀態,因此您的應用程序需要以某種形式的數據庫/數據結構來跟蹤這些情況。我建議跟蹤以下內容:

+------------------+---------------------------------------------------------------------------+ 
|  Property  |         Why?         | 
+------------------+---------------------------------------------------------------------------+ 
| Local Path  | You'll need this so that you can map a local file to its service identity | 
| Remote Path  | You'll need this if you plan to address the remote file by path    | 
| Remote Id  | You'll need this if you plan to address the remote file by unique id   | 
| Hash    | The hash representing the current state of the file      | 
| Local Timestamp | Needed to detect local changes           | 
| Remote Timestamp | Needed for conflict resolution           | 
| Remote ETag  | Needed to detect remote changes           | 
+------------------+---------------------------------------------------------------------------+ 

此外,如果使用delta方法,你需要將token值從delta響應存儲。這與項目無關,因此需要存儲在某個全局字段中。

衝突解決
如果雙方你的應用程序將需要經過一個解決衝突的過程中被檢測到的變化。對同步文件缺乏瞭解的應用程序需要提示用戶手動解決衝突,或者執行諸如分叉文件等操作,以便現在有兩個副本。但是,處理自定義文件格式的應用程序應該有足夠的知識來有效地合併文件,而無需任何形式的用戶交互。這意味着完全依賴於正在同步的文件。

應用更改
的最後一步是推合併狀態到任何需要(例如,如果變化本地然後推遠程,如果改變被遠程然後推本地,否則如果變化在兩種地方推兩地)。確保執行此步驟非常重要,以避免在「更改檢測」步驟發生後替換寫入的內容。在本地你可能通過在這個過程中鎖定文件來完成這個任務,但是你不能用這個遠程文件來完成。相反,您需要使用etag值來確保該服務只接受請求,如果狀態仍然是您所期望的:

await this.userDrive.Drive.Special.AppRoot.ItemWithPath(remotePath).Content.Request(new Option[] { new HeaderOption("If-Match", "etag") }).PutAsync(newContentStream); 
+0

感謝您的詳細回覆,它看起來正是我需要處理的信息。我會在本週晚些時候出發,如果能夠實現這個目標,我會給出答案。爲了澄清'PreviousDeltaToken'的問題,應用程序需要在初始調用之後在本地存儲哪些內容,以便在調用之間進行比較?如果是這樣,那麼你提到的DeltaLink值有什麼不同? – Lindsay

+1

感謝您指出我對「deltaLink」的引用 - 它在您處理C#SDK時不適用,因此我已將該提及更新爲'token'。它應該是來自「delta」調用的響應中的一個屬性。你需要存儲它,因爲它是系統知道你最後一次呼叫的方式,以便它可以只返回那些已經改變的事情。 – Brad

相關問題