Search code examples
c#uwpwin-universal-apponedrive

UWP OneDrive storage space


I have a c# UWP App, that makes use of the OneDrive API to store files in the approot (special folder for my App only). I know, that I can get the total space of OneDrive this way, but it doesn't tell me, how much space my App takes.

Is there a fast way to tell, how much space my App takes to store these files there (instead of iterating through all items)?


Solution

  • As Brad said, approot like any other OneDrive item has a metadata. And in item's metadata has a size property which represents size of the item in bytes. So we can use this property to get the total space your app takes.

    As App Folder described, we can use GET /drive/special/approot to get your app folder's metadata and when using OneDrive .NET SDK, the code will like:

    var item = await oneDriveClient.Drive.Special.AppRoot.Request().GetAsync();
    System.Diagnostics.Debug.WriteLine($"{item.Name}'s size is {item.Size}");
    

    However as I tested, when we use this code in UWP, we will encounter a cache issue. Even your app folder's size has changed, this API will return the same value as the first time you run it.

    This is because while Get metadata for a OneDrive item, it has an optional request headers if-none-match and if this request header is included and the eTag (or cTag) provided matches the current tag on the file, an HTTP 304 Not Modified response is returned.

    And in UWP, using HttpClient will automatically add this header in request, if the eTag is not changed, HttpClient will not get the newest info, it will return the data it cached. According to Item resource type:

    Note: The eTag and cTag properties work differently on containers (folders). The cTag value is modified when content or metadata of any descendant of the folder is changed. The eTag value is only modified when the folder's properties are changed, except for properties that are derived from descendants (like childCount or lastModifiedDateTime).

    So in most case, app folder's eTag won't change and when we use OneDrive .NET SDK or default HttpClient in UWP to get app folder's metadata, we will get the cached data. To see this clearly, we can use to trace the network, and we will find in the request headers, If-None-Match is added and the real response from OneDrive is HTTP 304 Not Modified. enter image description here

    To solve this issue, we can use Windows.Web.Http.HttpClient class with HttpBaseProtocolFilter class and HttpCacheControl class to disable the cache like following:

    var oneDriveClient = await OneDriveClientExtensions.GetAuthenticatedUniversalClient(new[] { "wl.signin", "onedrive.readwrite" });
    
    var filter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
    filter.CacheControl.ReadBehavior = Windows.Web.Http.Filters.HttpCacheReadBehavior.MostRecent;
    filter.CacheControl.WriteBehavior = Windows.Web.Http.Filters.HttpCacheWriteBehavior.NoCache;
    
    var httpClient = new HttpClient(filter);
    
    var request = new HttpRequestMessage(HttpMethod.Get, new Uri("https://api.onedrive.com/v1.0/drive/special/approot"));
    request.Headers.Authorization = new Windows.Web.Http.Headers.HttpCredentialsHeaderValue("Bearer", oneDriveClient.AuthenticationProvider.CurrentAccountSession.AccessToken);
    
    var response = await httpClient.SendRequestAsync(request);
    
    var item = oneDriveClient.HttpProvider.Serializer.DeserializeObject<Item>(await response.Content.ReadAsStringAsync());
    System.Diagnostics.Debug.WriteLine($"{item.Name}'s size is {item.Size}");
    

    PS: To make this method work, we need make sure there is no local HTTP cache. So we'd better uninstall the app first and do not use await oneDriveClient.Drive.Special.AppRoot.Request().GetAsync() in the app.