Skip to content

Commit

Permalink
Merge pull request #18 from windows-toolkit/michael-hawker/graph-pres…
Browse files Browse the repository at this point in the history
…enter

Initial GraphPresenter prototype for #17
  • Loading branch information
azchohfi authored Aug 11, 2020
2 parents d5c0517 + c2dd9ea commit 25be48a
Show file tree
Hide file tree
Showing 11 changed files with 453 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.Graph;
using Microsoft.Toolkit.Uwp.Helpers;
using Newtonsoft.Json.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Microsoft.Toolkit.Graph.Controls
{
/// <summary>
/// Specialized <see cref="ContentPresenter"/> to fetch and display data from the Microsoft Graph.
/// </summary>
public class GraphPresenter : ContentPresenter
{
/// <summary>
/// Gets or sets a <see cref="IBaseRequestBuilder"/> to be used to make a request to the graph. The results will be automatically populated to the <see cref="ContentPresenter.Content"/> property. Use a <see cref="ContentPresenter.ContentTemplate"/> to change the presentation of the data.
/// </summary>
public IBaseRequestBuilder RequestBuilder
{
get { return (IBaseRequestBuilder)GetValue(RequestBuilderProperty); }
set { SetValue(RequestBuilderProperty, value); }
}

/// <summary>
/// Identifies the <see cref="RequestBuilder"/> dependency property.
/// </summary>
/// <returns>
/// The identifier for the <see cref="RequestBuilder"/> dependency property.
/// </returns>
public static readonly DependencyProperty RequestBuilderProperty =
DependencyProperty.Register(nameof(RequestBuilder), typeof(IBaseRequestBuilder), typeof(GraphPresenter), new PropertyMetadata(null));

/// <summary>
/// Gets or sets the <see cref="Type"/> of item returned by the <see cref="RequestBuilder"/>.
/// Set to the base item type and use the <see cref="IsCollection"/> property to indicate if a collection is expected back.
/// </summary>
public Type ResponseType { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the returned data from the <see cref="RequestBuilder"/> is a collection.
/// </summary>
public bool IsCollection { get; set; }

/// <summary>
/// Gets or sets list of <see cref="QueryOption"/> representing <see cref="Microsoft.Graph.QueryOption"/> values to pass into the request built by <see cref="RequestBuilder"/>.
/// </summary>
public List<QueryOption> QueryOptions { get; set; } = new List<QueryOption>();

/// <summary>
/// Gets or sets a string to indicate a sorting order for the <see cref="RequestBuilder"/>. This is a helper to add this specific request option to the <see cref="QueryOptions"/>.
/// </summary>
public string OrderBy { get; set; }

/// <summary>
/// Initializes a new instance of the <see cref="GraphPresenter"/> class.
/// </summary>
public GraphPresenter()
{
Loaded += GraphPresenter_Loaded;
}

private async void GraphPresenter_Loaded(object sender, RoutedEventArgs e)
{
// Note: some interfaces from the Graph SDK don't implement IBaseRequestBuilder properly, see https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/722
if (RequestBuilder != null)
{
var request = new BaseRequest(
RequestBuilder.RequestUrl,
RequestBuilder.Client); // TODO: Do we need separate Options here?
request.Method = "GET";
request.QueryOptions = QueryOptions?.Select(option => (Microsoft.Graph.QueryOption)option)?.ToList() ?? new List<Microsoft.Graph.QueryOption>();

// Handle Special QueryOptions
if (!string.IsNullOrWhiteSpace(OrderBy))
{
request.QueryOptions.Add(new Microsoft.Graph.QueryOption("$orderby", OrderBy));
}

try
{
var response = await request.SendAsync<object>(null, CancellationToken.None).ConfigureAwait(false) as JObject;

//// TODO: Deal with paging?

var values = response["value"];
object data = null;

if (IsCollection)
{
data = values.ToObject(Array.CreateInstance(ResponseType, 0).GetType());
}
else
{
data = values.ToObject(ResponseType);
}

_ = DispatcherHelper.ExecuteOnUIThreadAsync(() => Content = data);
}
catch
{
// TODO: We should figure out what we want to do for Loading/Error states here.
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;

namespace Microsoft.Toolkit.Graph.Controls
{
/// <summary>
/// XAML Proxy for <see cref="Microsoft.Graph.QueryOption"/>.
/// </summary>
public sealed class QueryOption
{
/// <inheritdoc cref="Microsoft.Graph.Option.Name"/>
public string Name { get; set; }

/// <inheritdoc cref="Microsoft.Graph.Option.Value"/>
public string Value { get; set; }

/// <summary>
/// Implicit conversion for <see cref="QueryOption"/> to <see cref="Microsoft.Graph.QueryOption"/>.
/// </summary>
/// <param name="option">query option to convert.</param>
public static implicit operator Microsoft.Graph.QueryOption(QueryOption option)
{
return new Microsoft.Graph.QueryOption(option.Name, option.Value);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<PackageTags>UWP Toolkit Windows Controls MSAL Microsoft Graph AadLogin ProfileCard Person PeoplePicker Login</PackageTags>
<SignAssembly>false</SignAssembly>
<GenerateLibraryLayout>true</GenerateLibraryLayout>
<LangVersion>8.0</LangVersion>
<Configurations>Debug;Release;CI</Configurations>
<Platforms>AnyCPU;ARM;ARM64;x64;x86</Platforms>
</PropertyGroup>
Expand All @@ -34,8 +35,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Graph.Beta" Version="0.18.0-preview" />
<PackageReference Include="Microsoft.Graph.Auth" Version="1.0.0-preview.4" />
<PackageReference Include="Microsoft.Graph.Beta" Version="0.19.0-preview" />
<PackageReference Include="Microsoft.Graph.Auth" Version="1.0.0-preview.5" />
</ItemGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions Microsoft.Toolkit.Graph/Extensions/GraphExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Graph;
Expand Down
4 changes: 2 additions & 2 deletions Microsoft.Toolkit.Graph/Microsoft.Toolkit.Graph.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Graph.Beta" Version="0.18.0-preview" />
<PackageReference Include="Microsoft.Graph.Auth" Version="1.0.0-preview.4" />
<PackageReference Include="Microsoft.Graph.Beta" Version="0.19.0-preview" />
<PackageReference Include="Microsoft.Graph.Auth" Version="1.0.0-preview.5" />
<PackageReference Include="Microsoft.Toolkit" Version="6.1.0" />
</ItemGroup>
</Project>
27 changes: 11 additions & 16 deletions Microsoft.Toolkit.Graph/Providers/MockProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ namespace Microsoft.Toolkit.Graph.Providers
/// </summary>
public class MockProvider : IProvider
{
private const string GRAPH_PROXY_URL = "https://proxy.apisandbox.msdn.microsoft.com/svc?url=";

private ProviderState _state = ProviderState.Loading;

/// <inheritdoc/>
Expand All @@ -42,22 +44,15 @@ private set

/// <inheritdoc/>
public GraphServiceClient Graph => new GraphServiceClient(
"https://proxy.apisandbox.msdn.microsoft.com/svc?url=" + HttpUtility.HtmlEncode("https://graph.microsoft.com/beta/"),
new DelegateAuthenticationProvider((requestMessage) =>
{
//// Temporary Workaround for https://github.com/microsoftgraph/msgraph-sdk-dotnet-core/issues/59
//// ------------------------
var requestUri = requestMessage.RequestUri.ToString();
var index = requestUri.IndexOf("&");
if (index >= 0)
{
requestMessage.RequestUri = new Uri(requestUri.Remove(index, 1).Insert(index, "?"));
}

//// End Workaround

return this.AuthenticateRequestAsync(requestMessage);
}));
new DelegateAuthenticationProvider((requestMessage) =>
{
var requestUri = requestMessage.RequestUri.ToString();

// Prepend Proxy Service URI to our request
requestMessage.RequestUri = new Uri(GRAPH_PROXY_URL + Uri.EscapeDataString(requestUri));

return this.AuthenticateRequestAsync(requestMessage);
}));

/// <inheritdoc/>
public event EventHandler<StateChangedEventArgs> StateChanged;
Expand Down
11 changes: 10 additions & 1 deletion Microsoft.Toolkit.Graph/Providers/ProviderManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
// See the LICENSE file in the project root for more information.

using System;
using System.ComponentModel;
using Microsoft.Graph;
using Microsoft.Identity.Client;
using Microsoft.Toolkit.Helpers;

namespace Microsoft.Toolkit.Graph.Providers
{
Expand All @@ -14,7 +18,7 @@ namespace Microsoft.Toolkit.Graph.Providers
/// ProviderManager.Instance.GlobalProvider = await MsalProvider.CreateAsync(...);
/// </code>
/// </example>
public class ProviderManager
public class ProviderManager : INotifyPropertyChanged
{
/// <summary>
/// Gets the name of the toolkit client to identify self in Graph calls.
Expand All @@ -31,6 +35,9 @@ public class ProviderManager
/// </summary>
public event EventHandler<ProviderUpdatedEventArgs> ProviderUpdated;

/// <inheritdoc/>
public event PropertyChangedEventHandler PropertyChanged;

private IProvider _provider;

/// <summary>
Expand Down Expand Up @@ -58,6 +65,8 @@ public IProvider GlobalProvider
}

ProviderUpdated?.Invoke(this, new ProviderUpdatedEventArgs(ProviderManagerChangedState.ProviderChanged));

PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(GlobalProvider)));
}
}

Expand Down
Binary file added SampleTest/Assets/FileIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 25be48a

Please sign in to comment.