<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>App Consult Team</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/appconsult/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/appconsult/feed.xml</link>
    <description>The Windows App Consult team blog for the latest updates on events and technical articles, success stories and team public updates.</description>
    <lastBuildDate>Thu, 28 Feb 2019 15:57:23 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>The Windows AppConsult blog has moved!</title>
      <link>https://docs.microsoft.com/archive/blogs/appconsult/the-windows-appconsult-blog-has-moved</link>
      <pubDate>Wed, 27 Feb 2019 08:44:58 GMT</pubDate>
      <dc:creator><![CDATA[Matteo Pagani]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/appconsult/?p=24425</guid>
      <description><![CDATA[Since a while Microsoft has launched a new platform called Tech Community, where different groups in...]]></description>
      <content:encoded><![CDATA[Since a while Microsoft has launched a new platform called <a href="https://techcommunity.microsoft.com/">Tech Community</a>, where different groups in Microsoft can publish news, articles and stay in touch in a better way with communities and developers.
As AppConsult, we immediately saw the opportunity to move to a more modern platform, which can help us to reach and share our knowledge with developers all around the world.

I'm happy to share that, thanks to the efforts of my team mate <a href="https://twitter.com/sbovo">Sebastien</a>, we are now officialy part of the Windows 10 community on the Tech Community website!

<img src="https://msdnshared.blob.core.windows.net/media/2019/02/The-Windows-AppConsult-blog-has-movedappconsult.png" alt="" />

This is the official link where you can find us: <a href="https://techcommunity.microsoft.com/t5/Windows-Dev-AppConsult/bg-p/WindowsDevAppConsult">https://techcommunity.microsoft.com/t5/Windows-Dev-AppConsult/bg-p/WindowsDevAppConsult</a>. Also the short link <a href="https://aka.ms/appconsultblog">https://aka.ms/appconsultblog</a> has been updated to redirect to the new website.

It's our new home! You will find the same articles you can find here but, most importantly, it's the place where we're going to publish all our new articles. So, if you have bookmarked this blog, remember to update it to the new URL! And in case you have subscribed to our RSS feed, this is the URL of the new one: <a href="https://techcommunity.microsoft.com/gxcuf89792/rss/board?board.id=WindowsDevAppConsult">https://techcommunity.microsoft.com/gxcuf89792/rss/board?board.id=WindowsDevAppConsult</a>.

Take some time to read the official announcement <a href="https://techcommunity.microsoft.com/t5/Windows-Dev-AppConsult/Welcome-to-the-Windows-Dev-AppConsult-blog/ba-p/329684">here</a> and... see you on the other side!]]></content:encoded>
    </item>
    <item>
      <title>Add AI feature to Xamarin.Forms app</title>
      <link>https://docs.microsoft.com/archive/blogs/appconsult/add-ai-feature-on-xamarin-forms-app</link>
      <pubDate>Tue, 18 Dec 2018 01:33:09 GMT</pubDate>
      <dc:creator><![CDATA[KazukiOta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/appconsult/?p=24305</guid>
      <description><![CDATA[Now, AI is one of important technologies.
Almost all platforms have API sets of AI. Following list...]]></description>
      <content:encoded><![CDATA[Now, AI is one of important technologies.
Almost all platforms have API sets of AI. Following list is technology names per platform.

<ul>
  <li>Windows 10: Windows ML</li>
  <li>Android: TensorFlow</li>
  <li>iOS: CoreML</li>
</ul>

Xamarin can call native API sets using C#. It means you can implement AI feature on your app using Xamarin. This article will be introducing how to use AI APIs with Xamarin.Forms.

<h2>Create a project</h2>

Open Visual Studio 2017, then create a new project that is Mobile App (Xamarin.Form) of Cross-Platform category. And then select Blank, select Android, iOS, Windows(UWP) and .NET Standard.

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/1.createproject.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/1.createproject-1024x561.jpg" alt="" width="1024" height="561" class="alignnone size-large wp-image-24315" /></a>
<figcaption style="text-align:center">Create a Xamarin.Forms project</figcaption>
</figure>

Add base feature that exclude AI to here. I'll use a take photo feature in this app. So, add Xam.Plugin.Media NuGet package to all projects, then setup projects in accordance with the readme file shown. And then edit MainPage.xaml like below:

<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;ContentPage
    x:Class=&quot;AIApp.MainPage&quot;
    xmlns=&quot;https://xamarin.com/schemas/2014/forms&quot;
    xmlns:x=&quot;https://schemas.microsoft.com/winfx/2009/xaml&quot;
    xmlns:ios=&quot;clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core&quot;
    xmlns:local=&quot;clr-namespace:AIApp&quot;
    Title=&quot;Safe Area&quot;
    ios:Page.UseSafeArea=&quot;True&quot;&gt;

    &lt;StackLayout&gt;
        &lt;Image
            x:Name=&quot;picture&quot;
            Aspect=&quot;AspectFill&quot;
            VerticalOptions=&quot;FillAndExpand&quot; /&gt;
        &lt;Label x:Name=&quot;output&quot; HorizontalOptions=&quot;CenterAndExpand&quot; /&gt;
        &lt;StackLayout Orientation=&quot;Horizontal&quot;&gt;
            &lt;Button
                Clicked=&quot;PickPhotoButton_Clicked&quot;
                HorizontalOptions=&quot;FillAndExpand&quot;
                Text=&quot;Pick a picture&quot; /&gt;
            &lt;Button
                Clicked=&quot;TakePhotoButton_Clicked&quot;
                HorizontalOptions=&quot;FillAndExpand&quot;
                Text=&quot;Take a picture&quot; /&gt;
        &lt;/StackLayout&gt;
    &lt;/StackLayout&gt;

&lt;/ContentPage&gt;</code></pre>

At next, edit the code behind like below:

<pre><code>using Plugin.Media;
using Plugin.Media.Abstractions;
using System;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace AIApp
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private async void TakePhotoButton_Clicked(object sender, EventArgs e)
        {
            await ProcessPhotoAsync(true);
        }

        private async void PickPhotoButton_Clicked(object sender, EventArgs e)
        {
            await ProcessPhotoAsync(false);
        }

        private async Task ProcessPhotoAsync(bool useCamera)
        {
            await CrossMedia.Current.Initialize();
            if (useCamera ? !CrossMedia.Current.IsTakePhotoSupported : !CrossMedia.Current.IsPickPhotoSupported)
            {
                await DisplayAlert(&quot;Info&quot;, &quot;Your phone doesn&#039;t support photo feature.&quot;, &quot;OK&quot;);
                return;
            }

            var photo = useCamera ? 
                await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions()) : 
                await CrossMedia.Current.PickPhotoAsync();
            if (photo == null)
            {
                picture.Source = null;
                return;
            }

            picture.Source = ImageSource.FromFile(photo.Path);

            var service = DependencyService.Get&lt;IPhotoDetector&gt;();
            if (service == null)
            {
                await DisplayAlert(&quot;Info&quot;, &quot;Not implemented the feature on your device.&quot;, &quot;OK&quot;);
                return;
            }

            using (var s = photo.GetStream())
            {
                var result = await service.DetectAsync(s);
                output.Text = $&quot;It looks like a {result}&quot;;
            }
        }
    }
}
</code></pre>

In this code, using IPhotoDetector interface to detect a photo. The interface is just a method that is DetectAsync.

<pre><code>using System.IO;
using System.Threading.Tasks;

namespace AIApp
{
    public interface IPhotoDetector
    {
        Task&lt;FriesOrNotFriesTag&gt; DetectAsync(Stream photo);
    }

    public enum FriesOrNotFriesTag
    {
        None,
        Fries,
        NotFries,
    }
}
</code></pre>

<h2>Create ML models</h2>

I use Microsoft Cognitive Services Custom Vision(https://customvision.ai) to create ML models. Create Fries and NotFries tags on the project of Custom Vision. 
Custom Vision service has a feature that generate CoreML, TensorFlow and ONNX files. Please read the following document to know more information.

<a href="https://docs.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/export-your-model">Export your model for use with mobile devices | Microsoft Docs</a>

The point  is that select General (compact) of Domains category when creating project.

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/2.createcustomvisionproject.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/2.createcustomvisionproject.jpg" alt="" width="603" height="828" class="alignnone size-full wp-image-24325" /></a>
<figcaption style="text-align:center">Create new project</figcaption>
</figure>

After training the model, you can export the ML models from Export button at Performance tab.

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/3.export.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/3.export.jpg" alt="" width="961" height="190" class="alignnone size-full wp-image-24335" /></a>
<figcaption style="text-align:center">Export models</figcaption>
</figure>

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/4.chooseplatforms.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/4.chooseplatforms.jpg" alt="" width="600" height="962" class="alignnone size-full wp-image-24345" /></a>
<figcaption style="text-align:center">Choose your platform</figcaption>
</figure>

<h2>Add Windows 10 implementation</h2>

Windows 10 has Windows ML feature.

<a href="https://docs.microsoft.com/en-us/windows/ai/">Windows Machine Learning | Microsoft Docs</a>

Add the onnx file to Assets folder on the UWP project, then generated a C# file for use the onnx file.

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/5.addonnx.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/5.addonnx.jpg" alt="" width="443" height="337" class="alignnone size-full wp-image-24355" /></a>
<figcaption style="text-align:center">Add an ONNX model</figcaption>
</figure>

Add PhotoDetector.cs file to UWP project, and then edit the file like below:

<pre><code>using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Windows.AI.MachineLearning;
using Windows.Graphics.Imaging;
using Windows.Media;
using Windows.Storage;
using Xamarin.Forms;

[assembly: Dependency(typeof(AIApp.UWP.PhotoDetector))]
namespace AIApp.UWP
{
    public class PhotoDetector : IPhotoDetector
    {
        private FriesOrNotFriesModel _model;
        public async Task DetectAsync(Stream photo)
        {
            await InitializeModelAsync();
            var bitmapDecoder = await BitmapDecoder.CreateAsync(photo.AsRandomAccessStream());
            var output = await _model.EvaluateAsync(new FriesOrNotFriesInput
            {
                data = ImageFeatureValue.CreateFromVideoFrame(VideoFrame.CreateWithSoftwareBitmap(await bitmapDecoder.GetSoftwareBitmapAsync())),
            });
            var label = output.classLabel.GetAsVectorView().FirstOrDefault();
            return Enum.Parse(label);
        }

        private async Task InitializeModelAsync()
        {
            if (_model != null)
            {
                return;
            }

            var onnx = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/FriesOrNotFries.onnx"));
            _model = await FriesOrNotFriesModel.CreateFromStreamAsync(onnx);
        }
    }
}</code></pre>

<h2>Add Android implementation</h2>

On Android platform, TensorFlow is popular library. In Java or Kotlin, there is tensorflow-android library.

<a href="https://mvnrepository.com/artifact/org.tensorflow/tensorflow-android">TensorFlow AAR For Android Inference Library and Java API | Maven Repository</a>

On Xamarin, there is wrapper library.

<a href="https://www.nuget.org/packages/Xam.Android.Tensorflow/">Xam.Android.Tensorflow | NuGet</a>

The library was introduced following article of Xamarin Blog.

<a href="https://blog.xamarin.com/android-apps-tensorflow/">Using TensorFlow and Azure to Add Image Classification to Your Android Apps | Xamarin Blog</a>

Add a model file and label file to Android project.

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/6.addtensorflow.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/6.addtensorflow.jpg" alt="" width="522" height="331" class="alignnone size-full wp-image-24365" /></a>
<figcaption style="text-align:center">Add TensorFlow model</figcaption>
</figure>

At next, I add the library to Android project, then create PhotoDetector.cs file to the project. At next, edit the file like below:

<pre><code>using Android.Graphics;
using Org.Tensorflow.Contrib.Android;
using Plugin.CurrentActivity;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;

[assembly: Dependency(typeof(AIApp.Droid.PhotoDetector))]
namespace AIApp.Droid
{
    public class PhotoDetector : IPhotoDetector
    {
        private static readonly string ModelFile = "model.pb";
        private static readonly string LabelFile = "labels.txt";
        private static readonly string InputName = "Placeholder";
        private static readonly string OutputName = "loss";
        private static readonly int InputSize = 227;
        private readonly TensorFlowInferenceInterface _inferenceInterface;
        private readonly string[] _labels;

        public PhotoDetector()
        {
            _inferenceInterface = new TensorFlowInferenceInterface(CrossCurrentActivity.Current.Activity.Assets, ModelFile);
            using (var sr = new StreamReader(CrossCurrentActivity.Current.Activity.Assets.Open(LabelFile)))
            {
                _labels = sr.ReadToEnd().Split('\n').Select(x =&gt; x.Trim()).Where(x =&gt; !string.IsNullOrEmpty(x)).ToArray();
            }
        }

        public async Task DetectAsync(Stream photo)
        {
            var bitmap = await BitmapFactory.DecodeStreamAsync(photo);
            var floatValues = GetBitmapPixels(bitmap);
            var outputs = new float[_labels.Length];
            _inferenceInterface.Feed(InputName, floatValues, 1, InputSize, InputSize, 3);
            _inferenceInterface.Run(new[] { OutputName });
            _inferenceInterface.Fetch(OutputName, outputs);
            var index = Array.IndexOf(outputs, outputs.Max());
            return (FriesOrNotFriesTag)Enum.Parse(typeof(FriesOrNotFriesTag), _labels[index]);
        }

        private async Task LoadByteArrayFromAssetsAsync(string name)
        {
            using (var s = CrossCurrentActivity.Current.Activity.Assets.Open(name))
            using (var ms = new MemoryStream())
            {
                await s.CopyToAsync(ms);
                ms.Seek(0, SeekOrigin.Begin);
                return ms.ToArray();
            }
        }

        private static float[] GetBitmapPixels(Bitmap bitmap)
        {
            var floatValues = new float[InputSize * InputSize * 3];
            using (var scaledBitmap = Bitmap.CreateScaledBitmap(bitmap, InputSize, InputSize, false))
            {
                using (var resizedBitmap = scaledBitmap.Copy(Bitmap.Config.Argb8888, false))
                {
                    var intValues = new int[InputSize * InputSize];
                    resizedBitmap.GetPixels(intValues, 0, resizedBitmap.Width, 0, 0, resizedBitmap.Width, resizedBitmap.Height);
                    for (int i = 0; i &gt; 8) &amp; 0xFF) - 117);
                        floatValues[i * 3 + 2] = (((val &gt;&gt; 16) &amp; 0xFF) - 123);
                    }
                    resizedBitmap.Recycle();
                }
                scaledBitmap.Recycle();
            }

            return floatValues;
        }
    }
}</code></pre>


<h2>Add iOS implementation</h2>

The last platform is iOS. iOS has CoreML feature.

<a href="https://developer.apple.com/documentation/coreml">Core ML | Apple Developer Documentation</a>

In Xamarin platform, you can use CoreML APIs. The documentation is below:

<a href="https://docs.microsoft.com/en-us/xamarin/ios/platform/introduction-to-ios11/coreml">Introduction to CoreML in Xamarin.iOS | Microsoft Docs</a>

Add the CoreML file to Resources folder of iOS project, and set CoreMLModel to Build Action.

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/addcoreml.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/addcoreml.jpg" alt="" width="564" height="569" class="alignnone size-full wp-image-24375" /></a>
<figcaption style="text-align:center">Add CoreML file</figcaption>
</figure>

At next, add PhotoDetector.cs to iOS project, then edit the file like below:

<pre><code>using CoreFoundation;
using CoreImage;
using CoreML;
using Foundation;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Vision;
using Xamarin.Forms;

[assembly: Dependency(typeof(AIApp.iOS.PhotoDetector))]
namespace AIApp.iOS
{
    public class PhotoDetector : IPhotoDetector
    {
        private readonly MLModel _mlModel;
        private readonly VNCoreMLModel _model;

        public PhotoDetector()
        {
            var assetPath = NSBundle.MainBundle.GetUrlForResource("FriesOrNotFries", "mlmodelc");
            _mlModel = MLModel.Create(assetPath, out var _);
            _model = VNCoreMLModel.FromMLModel(_mlModel, out var __);
        }

        public Task DetectAsync(Stream photo)
        {
            var taskCompletionSource = new TaskCompletionSource();
            void handleClassification(VNRequest request, NSError error)
            {
                var observations = request.GetResults();
                if (observations == null)
                {
                    taskCompletionSource.SetException(new Exception("Unexpected result type from VNCoreMLRequest"));
                    return;
                }

                if (!observations.Any())
                {
                    taskCompletionSource.SetResult(FriesOrNotFriesTag.None);
                    return;
                }

                var best = observations.First();
                taskCompletionSource.SetResult((FriesOrNotFriesTag)Enum.Parse(typeof(FriesOrNotFriesTag), best.Identifier));
            }

            using (var data = NSData.FromStream(photo))
            {
                var ciImage = new CIImage(data);
                var handler = new VNImageRequestHandler(ciImage, new VNImageOptions());
                DispatchQueue.DefaultGlobalQueue.DispatchAsync(() =&gt;
                {
                    handler.Perform(new VNRequest[] { new VNCoreMLRequest(_model, handleClassification) }, out var _);
                });
            }

            return taskCompletionSource.Task;
        }
    }
}</code></pre>

<h2>How does it run?</h2>

This is results run on Windows 10.

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/runinuwp.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/runinuwp-1024x496.jpg" alt="" width="1024" height="496" class="alignnone size-large wp-image-24385" /></a>
<figcaption style="text-align:center">Chirashi sushi is not fries, French fries is fries.</figcaption>
</figure>

On Android:

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/onandroid.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/onandroid.jpg" alt="" width="1015" height="920" class="alignnone size-full wp-image-24395" /></a>
<figcaption style="text-align:center">French fries is fries, Fried egg is not fries.</figcaption>
</figure>

On iOS:

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/onios.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/onios.jpg" alt="" width="819" height="916" class="alignnone size-full wp-image-24405" /></a>
<figcaption style="text-align:center">French fries is fries, Soup is not fries.</figcaption>
</figure>

<h2>Conclusion</h2>

AI is very important technology. You can use it your apps on all platforms.
If you created apps using Xamarin, then you could add the AI feature by steps of this article.

Have a good programing.]]></content:encoded>
    </item>
    <item>
      <title>How to convert class library that is targeted WPF to .NET Core 3.0 from .NET Framework</title>
      <link>https://docs.microsoft.com/archive/blogs/appconsult/how-to-convert-class-library-that-is-targeted-wpf-to-net-core-3-0-from-net-framework</link>
      <pubDate>Wed, 12 Dec 2018 00:56:40 GMT</pubDate>
      <dc:creator><![CDATA[KazukiOta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/appconsult/?p=23865</guid>
      <description><![CDATA[At Connect(); 2018, .NET Core 3.0 Preview 1 was released and to support WPF/WinForms...]]></description>
      <content:encoded><![CDATA[At Connect(); 2018, .NET Core 3.0 Preview 1 was released and to support WPF/WinForms announced.
I’ve been owned two libraries that are ReactiveProperty and Livet. ReactiveProperty is targeted .NET Standard 2.0. .NET Standard 2.0 is available for .NET Core. However, Livet is targeted .NET Framework 4.5.2 or later. So, I have to convert it when I’ll use it on .NET Core 3.0. This article is working logs that I did.

Create a .NET Core 3.0 class library project that name is Livet.NetCore.

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/core1.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/core1-1024x310.jpg" alt="" width="1024" height="310" class="alignnone size-large wp-image-23875" /></a>
<figcaption style="text-align:center">Create a .NET Core class library project</figcaption>
</figure>

The project file that is generated is as below:

<pre>
<code>&lt;Project Sdk="Microsoft.NET.Sdk"&gt;
  &lt;PropertyGroup&gt;
    &lt;TargetFramework&gt;netcoreapp3.0&lt;/TargetFramework&gt;
  &lt;/PropertyGroup&gt;
&lt;/Project&gt;</code>
</pre>

I changed the project file in order to support WPF. Changed the “Sdk” attribute at Project tag to Microsoft.NET.Sdk.WindowsDesktop, and then added “&lt;UseWPF&gt;true&lt;/UseWPF&gt;” to under the PropertyGroup tag.

<pre>
<code>&lt;Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"&gt;
  &lt;PropertyGroup&gt;
    &lt;TargetFramework&gt;netcoreapp3.0&lt;/TargetFramework&gt;
    &lt;UseWPF&gt;true&lt;/UseWPF&gt;
  &lt;/PropertyGroup&gt;
&lt;/Project&gt;</code>
</pre>

After that, under the dependencies node of the project would change like below:

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/core1-2.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/core1-2.jpg" alt="" width="737" height="217" class="alignnone size-full wp-image-23885" /></a>
<figcaption style="text-align:center">Added some dependencies in order to support WindowsDesktop</figcaption>
</figure>

At Livet project, all of codes are in Shared project. So, I added reference to it on the Livet.NetCore project. If in your product there is no shared project, then at first you create a shared project, and then copy all code to there.

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/core2.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/core2.jpg" alt="" width="582" height="127" class="alignnone size-full wp-image-23895" /></a>
<figcaption style="text-align:center">Select "Add Reference..."</figcaption>
</figure>

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/core3.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/core3-1024x444.jpg" alt="" width="1024" height="444" class="alignnone size-large wp-image-23905" /></a>
<figcaption style="text-align:center">Select the shared projects</figcaption>
</figure>

After that, a lot of errors occurred.

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/core4.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/core4.jpg" alt="" width="579" height="202" class="alignnone size-full wp-image-23915" /></a>
<figcaption style="text-align:center">Over 7,000 errors!?</figcaption>
</figure>

The errors were by to depend the behavior feature. I had to add a reference that is “System.Windows.Interactivity.WPF” manually, using NuGet package manager.

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/core5.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/core5-1024x370.jpg" alt="" width="1024" height="370" class="alignnone size-large wp-image-23925" /></a>
<figcaption style="text-align:center">Added the System.Windows.Interactivity.WPF package</figcaption>
</figure>

All compile errors was fixed! However, the package is targeted .NET Framework 4.6.1. Below warning occurred.

<figure>
<a href="https://msdnshared.blob.core.windows.net/media/2018/12/core6.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/core6-1024x68.jpg" alt="" width="1024" height="68" class="alignnone size-large wp-image-23935" /></a>
<figcaption style="text-align:center">New warning message</figcaption>
</figure>

At “C:\Users\User name\.nuget\packages\system.windows.interactivity.wpf\2.0.20525\lib\net40”, I checked compatibility using Microsoft API Portability Analyzer with below command:

<pre>
<code>path to apiport.exe folder\ApiPort.exe analyze -f .</code>
</pre>

The detail of ApiPort.exe is written on <a href="https://blogs.msdn.microsoft.com/appconsult/2018/12/12/desktop-development-features-of-net-core-3-0-preview-1/">previous article</a>.

On the report that is result of the command, there is green at .NET Core column.

<a href="https://msdnshared.blob.core.windows.net/media/2018/12/core7.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/core7-1024x237.jpg" alt="" width="1024" height="237" class="alignnone size-large wp-image-23945" /></a>

I decided ignoring the warning. I added “NU1701” to NoWarn item of Properties window of System.Windows.Interactivity.WPF in order to ignore the warning.

<a href="https://msdnshared.blob.core.windows.net/media/2018/12/core8.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/core8.jpg" alt="" width="884" height="673" class="alignnone size-full wp-image-23955" /></a>

<h2>Publish to NuGet</h2>

Final step is that publish to NuGet. It is very easy. Fill information to Package tab of project properties.

<a href="https://msdnshared.blob.core.windows.net/media/2018/12/core9.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/core9-1024x837.jpg" alt="" width="1024" height="837" class="alignnone size-large wp-image-23965" /></a>

And then, select publish menu of project’s context menu.

<a href="https://msdnshared.blob.core.windows.net/media/2018/12/core10.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/core10.jpg" alt="" width="681" height="262" class="alignnone size-full wp-image-23975" /></a>

After completed the wizard, would be generated a nupkg file. then upload to nuget.org.

<a href="https://msdnshared.blob.core.windows.net/media/2018/12/core11.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/core11.jpg" alt="" width="916" height="854" class="alignnone size-full wp-image-23985" /></a>


<h2>Conclusion</h2>

I converted the class library that is targeted .NET Framework to .NET Core 3.0. In this class library, it was very easy, however if your product depends Windows specific features(ex: XBAP, Windows service, COM, etc…), then I think you will have to need additional steps.]]></content:encoded>
    </item>
    <item>
      <title>Desktop development features of .NET Core 3.0 Preview 1</title>
      <link>https://docs.microsoft.com/archive/blogs/appconsult/desktop-development-features-of-net-core-3-0-preview-1</link>
      <pubDate>Wed, 12 Dec 2018 00:24:35 GMT</pubDate>
      <dc:creator><![CDATA[KazukiOta]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/appconsult/?p=23795</guid>
      <description><![CDATA[At Connect(); 2018, Announced releasing .NET Core 3.0 Preview 1. In this release, it has very...]]></description>
      <content:encoded><![CDATA[At Connect(); 2018, Announced releasing .NET Core 3.0 Preview 1. In this release, it has very interesting features for Windows Desktop app developers.
<h2>WPF and Windows Forms support</h2>
In .NET Core 3.0 Preview 1, We can use WPF and Windows Forms. It is very easy. You just type below commands.

<code>dotnet new wpf</code> 

or 

<code>dotnet new winforms</code>

The commands generate the project files. The below screenshots are opening the projects on Visual Studio 2019 Preview.

<a href="https://msdnshared.blob.core.windows.net/media/2018/12/app1.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/app1-1024x625.jpg" alt="" width="1024" height="625" class="alignnone size-large wp-image-23805" /></a>

<a href="https://msdnshared.blob.core.windows.net/media/2018/12/app2.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/app2-1024x843.jpg" alt="" width="1024" height="843" class="alignnone size-large wp-image-23815" /></a>

Designer feature isn’t yet. However, you can launch the apps and debug on VS 2019 Preview.

<a href="https://msdnshared.blob.core.windows.net/media/2018/12/app3.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/app3-1024x589.jpg" alt="" width="1024" height="589" class="alignnone size-large wp-image-23825" /></a>

<h2>Can use .NET Framework libraries?</h2>

.NET Core 3.0 supports .NET Standard libraries. However, almost all WPF/WinForms apps depends libraries that are targeted .NET Framework, for example: Prism.

We can add the packages using NuGet package manager, however the below warning is occurred.

<a href="https://msdnshared.blob.core.windows.net/media/2018/12/app4.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/app4-1024x136.jpg" alt="" width="1024" height="136" class="alignnone size-large wp-image-23835" /></a>

In this case, you can check the compatibility using .NET Portability Analyzer.

<a href="https://docs.microsoft.com/en-us/dotnet/standard/analyzers/portability-analyzer">The .NET Portability Analyzer</a>

The previous link describes Visual Studio plugin. However VS2019 doesn’t support the extension yet. You can download the CLI tools from below link:

<a href="https://github.com/Microsoft/dotnet-apiport/releases?id=42678">Microsoft/dotnet-apiport releases page</a>

And you can analyze compatibility by below command.

<code>"path to ApiPort.exe directory"\ApiPort.exe analyze -f .</code>

After that, the report is generated:

<a href="https://msdnshared.blob.core.windows.net/media/2018/12/app5.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/app5-1024x188.jpg" alt="" width="1024" height="188" class="alignnone size-large wp-image-23845" /></a>

You can check compatibility, and then you can ignore the warnings on the properties window of Visual Studio 2019 as your discretion.

<a href="https://msdnshared.blob.core.windows.net/media/2018/12/app6.jpg"><img src="https://msdnshared.blob.core.windows.net/media/2018/12/app6.jpg" alt="" width="354" height="235" class="alignnone size-full wp-image-23855" /></a>

<h2>Conclusion</h2>

.NET Core 3.0 is preview status yet. However, you can try it now. You can evaluate your WPF/WinForms apps on .NET Core 3.0.

.NET Core 3.0 is high performance than .NET Framework. And you can use self-contained deployment feature that is include runtime to your deployment package.(It means that .NET Core 3.0 doesn’t need on deployment target machine.)

<a href="https://docs.microsoft.com/en-us/dotnet/core/deploying/">.NET Core application deployment</a>

Have a fun programming.]]></content:encoded>
    </item>
    <item>
      <title>Integrate the Microsoft Graph in your HoloLens and Mixed Reality apps</title>
      <link>https://docs.microsoft.com/archive/blogs/appconsult/23775</link>
      <pubDate>Thu, 06 Dec 2018 00:27:31 GMT</pubDate>
      <dc:creator><![CDATA[Sebastien Bovo]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/appconsult/?p=23775</guid>
      <description><![CDATA[Microsoft Graph is all about you! About the data of the user: Azure Active Directory, Office 365...]]></description>
      <content:encoded><![CDATA[Microsoft Graph is all about you! About the data of the user: Azure Active Directory, Office 365 data, Enterprise Mobility and Security services, Education tenant data and Windows Services.

As a developer, the beauty resides in the unified way to authenticate, access and query the data. It can simply be by using a <strong>HTTPS Rest service</strong> or <strong>the SDK for your platform</strong>.

I could continue describing the Microsoft Graph for pages and pages but there is better way to discover it with the nice <a target="_blank" href="https://developer.microsoft.com/en-us/graph/blogs/announcing-30-days-of-microsoft-graph-blog-series/" rel="noopener">30 Days of Microsoft Graph blog series</a>.

Microsoft Graph in Mixed Reality? I start with a little bit of context before detailing all steps.
<h2 id="using-the-microsoft-graph-in-hololens-and-mixed-reality">Using the Microsoft Graph in HoloLens and Mixed Reality</h2>
Let me tell you my journey, I started using this useful and comprehensive tutorial <a target="_blank" href="https://docs.microsoft.com/en-us/graph/training/uwp-tutorial" rel="noopener">https://docs.microsoft.com/en-us/graph/training/uwp-tutorial</a>; It allows you to create an UWP app that uses the Microsoft Graph in 30min!

It works really great for a 2D UWP app because it uses all the goodness of
<ul>
 	<li>The <a target="_blank" href="https://github.com/Microsoft/WindowsCommunityToolkit" rel="noopener">Windows Community toolkit</a> controls for Graph</li>
 	<li>The High level classes from the <a target="_blank" href="https://github.com/microsoftgraph/msgraph-sdk-dotnet" rel="noopener">.NET SDK for Graph</a></li>
 	<li>Under the hood, the <a target="_blank" href="https://github.com/AzureAD/microsoft-authentication-library-for-dotnet" rel="noopener">Microsoft Authentication Library (MSAL)</a> is used to authenticate to the Azure Active Directory for using Microsoft Graph</li>
</ul>
For HoloLens and Mixed Reality, it is different because our project is in Unity. We cannot reference and manage NuGet packages as we do in Visual Studio projects.

Do I give up? No! Here is what I have done:
<ol>
 	<li>I went through the tutorial - <a target="_blank" href="https://docs.microsoft.com/en-us/graph/training/uwp-tutorial" rel="noopener">https://docs.microsoft.com/en-us/graph/training/uwp-tutorial</a>. I had the full working project and looked at the dependencies.</li>
</ol>
<img alt="Visual Studio project depedencies" src="https://msdnshared.blob.core.windows.net/media/2018/12/UseGraphInMixedRealityVisualStudioProjectDependencies.png" />

These dependencies are the following NuGet packages.

<img alt="Nuget packages for the project" src="https://msdnshared.blob.core.windows.net/media/2018/12/UseGraphInMixedRealityNugetpackagesForTheProject.png" />
<ol start="2">
 	<li>Looking deeper at the XAML and the code, I first wanted to remove the Windows Community Toolkit dependencies because I cannot use them in a Unity 3D project.</li>
</ol>
To do so, I will have to perform the Microsoft Graph Authentication alone (and not simply use the graph login control from the Toolkit). I have done some researches and I have read carefully the <a target="_blank" href="https://blogs.msdn.microsoft.com/appconsult/2018/04/12/microsoft-graph-and-hololens-authentication/" rel="noopener">blog post</a> of my colleague <a target="_blank" href="https://twitter.com/mplogas" rel="noopener">Marc Plogas</a>. I had 2 options: (1) Do it really alone. Humm?! or (2) Use the <a target="_blank" href="https://github.com/AzureAD/microsoft-authentication-library-for-dotnet" rel="noopener">MSAL</a> UWP dll: I went for the option 2.
<strong>➡ Explanations and code in Step 3 below ⬅</strong>
<ol start="3">
 	<li>Lastly, the code of the tutorial uses the <a target="_blank" href="https://github.com/microsoftgraph/msgraph-sdk-dotnet" rel="noopener">.NET SDK for Graph</a>. Because all the SDK for the Microsoft are wrappers on the HTTP Rest API, I decided to not take an extra dll in the Unity project but just do HTTP calls using the UWP HttpClient.
<strong>➡ Explanations and code in Step 4 below ⬅</strong></li>
</ol>
So, we are good to go 😃: We will keep only one dll which will be the MSAL one.
<h3 id="here-are-now-the-real-steps-for-using-microsoft-graph-in-your-hololens-or-mixed-reality-apps">Here are now the real steps for using Microsoft Graph in your HoloLens or Mixed Reality apps.</h3>
--
<h2 id="step-1-register-an-entry--for-your-app-in-the-azure-active-directory">Step 1. Register an entry 🆔 for your app in the Azure Active Directory</h2>
This is the easy (but mandatory) part: <strong>In order to be able to query the Microsoft Graph, our app has to be known and registered in the Azure Active Directory</strong>.

I would make no sense to rewrite here how to do it because it is well explained in the tutorial we mentioned earlier. Just follow: <a target="_blank" href="https://docs.microsoft.com/en-us/graph/training/uwp-tutorial?tutorial-step=2" rel="noopener">Register the app in the portal</a>.

🆗 You have now the App Id which is like <code>0664402e-24c2-456d-8157-e8e110c45348</code>. Save it for later.
<h2 id="step-2-create-the-unity--app">Step 2. Create the Unity 🎮 App</h2>
<h3 id="project-setup-">Project setup 📏</h3>
Please note that for today, I used the <strong>Unity 2018 version</strong>. Here are all the tools:
<ul>
 	<li>Windows version 1809 for the PC and HoloLens</li>
 	<li>Visual Studio 2017 version 15.9.0</li>
 	<li>Windows SDK version 10.0.17763.0</li>
 	<li>Unity 2018.2.18f1</li>
</ul>
<blockquote><strong>Note:</strong> If you are familiar with Unity and Mixed Reality, please refer to <a target="_blank" href="https://blogs.msdn.microsoft.com/appconsult/2018/06/14/create-a-windows-mixed-reality-app-from-0-the-unity-project/" rel="noopener">Create a Windows Mixed Reality App from 0 – The Unity project</a>.</blockquote>
Configure the Unity project for Windows Mixed Reality:
<ul>
 	<li><strong>File</strong> menu / <strong>Build Settings</strong> ➡ <strong>Universal Windows Platform</strong> selected as the Build platform</li>
 	<li><strong>Edit</strong> menu / <strong>Project Settings</strong> / <strong>Player</strong> ➡ <strong>Virtual Reality Supported</strong> checked</li>
 	<li><strong>Edit</strong> menu / <strong>Project Settings</strong> / <strong>Player</strong> ➡ <strong>Other Settings</strong> / <strong>.NET</strong> as Scripting Backend. Please also use the <strong>Experimental (.NET 4.6 Equivalent)</strong> for the Scripting Runtime Version.</li>
 	<li>Put the camera <strong>at the origin</strong> (0,0,0) and use <strong>Solid Color</strong> = <strong>Black</strong>.
<img alt="Camera at the origin" src="https://msdnshared.blob.core.windows.net/media/2018/12/UseGraphInMixedRealityCameraAthTheOrigin.png" /></li>
 	<li>Add an empty game object named <code>ScriptManager</code> with a script <code>Startup</code> where we will place all the source code for simplicity.</li>
</ul>
<h3 id="field-of-view-feedback">Field of view feedback</h3>
(Not action here)

As explained in a <a target="_blank" href="https://blogs.msdn.microsoft.com/appconsult/2018/10/05/call-remote-assist-from-your-hololens-app/" rel="noopener">previous post</a>, I use some "technical piping" in order to display some text in front of the user from any code within the app. You will see it in action when you will run the sample. The only point that you have to remember is: Call <code>FOVFeedback.instance.ModifyText("Some text");</code> when you want in any class in your Unity project!

If you write the app from scratch and not use the sample code on GitHub, just <code>Debug.Log("Some text");</code> for example.
<h3 id="plugins">Plugins</h3>
We use the MSAL dll for the authentication. Because there no NuGet packaging system in Unity we are going to get this dll from the disk and add it to the <em>Assets</em> folder.
Again <a target="_blank" href="https://twitter.com/mplogas" rel="noopener">Marc Plogas</a> explained this in a <a target="_blank" href="https://blogs.msdn.microsoft.com/appconsult/2018/04/12/microsoft-graph-and-hololens-authentication/" rel="noopener">previous blog post</a>.

So, the dll to use is the one located in <code>C:\Users\&lt;&lt;YOUR_USER&gt;&gt;\.nuget\packages\microsoft.identity.client\2.5.0-preview\lib\uap10.0</code>.
<blockquote><strong>Note:</strong> This folder exists and would be populated if you have used this component at least one time for one project (This will be the case if you go through the Graph tutorial that I mentioned)</blockquote>
<img alt="Microsoft.identity.client dll" src="https://msdnshared.blob.core.windows.net/media/2018/12/UseGraphInMixedRealityMicrosoft.identity.client.png" />

Drag &amp; drop this dll in the Unity <strong>Project Window</strong> inside the <strong>Assets</strong> folder. Create a <strong>Plugins\WSA</strong> folder for this purpose.

<img alt="Unity project window" src="https://msdnshared.blob.core.windows.net/media/2018/12/UseGraphInMixedRealityUnityProjectWindow.png" />
<blockquote><strong>Note:</strong> Using the <strong>Plugins\WSA</strong> automatically flag the dll to be used only for Windows:
<img alt="" src="https://msdnshared.blob.core.windows.net/media/2018/12/UseGraphInMixedRealityWSAPlayer.png" /></blockquote>
🆗 With the MSAL dll in the <code>Assets\Plugins\WSA</code> folder, we can now use the Microsoft.Identity.Client namespace classes in our code.
<h2 id="step-3--authenticate-against-the-azure-active-directory">Step 3. ✅ Authenticate against the Azure Active Directory</h2>
To authenticate against the Azure Active Directory we use <a target="_blank" href="https://github.com/AzureAD/microsoft-authentication-library-for-dotnet" rel="noopener">Microsoft Authentication Library (MSAL)</a>. This library takes care of displaying the well-known "login browser popup". As a developer we do not have to worry about two-factor authentication, pin, etc. At the end, we get a token to use for all subsequent calls to Microsoft Graph.

Let's create a <strong>GoGraph</strong> method in the <strong>Startup</strong> class as follows:
<pre><code class="language-csharp">private async Task GoGraph()
{
    #if UNITY_WSA &amp;&amp; !UNITY_EDITOR
    // Get the authentication token using Microsoft.Identity.Client
    bool authenticated = false;
    PublicClientApplication client = new PublicClientApplication("&lt;&lt;YOUR_APP_ID&gt;&gt;"); // (1)
    AuthenticationResult authResult = null;
    IEnumerable&lt;string&gt; Scopes = new List&lt;string&gt; { "User.Read", "User.ReadBasic.All" }; // (2)
    try
    {
        authResult = await client.AcquireTokenAsync(Scopes);
        // Display some text like ($"UniqueId={authResult.UniqueId}, AccessToken={authResult.AccessToken}");
        authenticated = true;
    }
    catch (MsalException msaEx)
    {
        // Display some text like ($"Failed to acquire token: {msaEx.Message}");
    }
    catch (Exception ex)
    {
        // Display some text like ($"Failed to acquire token: {ex.Message}");
    }
    // To be continued...
}
#endif
</code></pre>
(1) <code>&lt;&lt;YOUR_APP_ID&gt;&gt;</code> has to be replaced by the App Id you got from the <strong>Step 1</strong>.

(2) <code>{ "User.Read", "User.ReadBasic.All" }</code> are the required permissions you will need to perform the Microsoft Graph calls. You will find theses permissions in the <a target="_blank" href="https://docs.microsoft.com/en-us/graph/api/overview?view=graph-rest-1.0" rel="noopener">Graph APIs reference</a> for each method. Here is an example for the <strong>List users</strong> method.

<img alt="Screenshot displaying permissions for a Graph method" src="https://msdnshared.blob.core.windows.net/media/2018/12/UseGraphInMixedRealityPermissionsExample.png" />

Let's use this <strong>GoGraph</strong> method In the <strong>Start</strong> method of the <strong>Startup</strong> class:
<pre><code class="language-csharp">public class Startup : MonoBehaviour
{
    // Use this for initialization
    async void Start()
    {
        await GoGraph();
    }
</code></pre>
<blockquote><strong>Note:</strong> I will give you the needed <code>using</code> statements later in this article.</blockquote>
<h2 id="step-4--query-microsoft-graph">Step 4. 🔍 Query Microsoft Graph</h2>
Once authenticated, we just have to provide the token for each call to the Microsoft Graph. This is done by using: <code>httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", authResult.AccessToken);</code>.

The call I want to do here is the one missing from the a previous article - <a href="https://blogs.msdn.microsoft.com/appconsult/2018/10/05/call-remote-assist-from-your-hololens-app/">https://blogs.msdn.microsoft.com/appconsult/2018/10/05/call-remote-assist-from-your-hololens-app/</a>. That is to say: Search a person in the Azure Active Directory and get its <strong>Object ID</strong> in order to call him with Remote Assist from HoloLens. Please use the following code just after <code>// To be continued...</code>
<pre><code class="language-csharp">if (authenticated)
{
    // Query MS Graph using a HTTP GET
    string GraphUriAndQuery = @"https://graph.microsoft.com/v1.0/users?$filter=startswith(Displayname,'Marty')&amp;$select=id";
    var uri = new System.Uri(GraphUriAndQuery);
    using (HttpClient httpClient = new HttpClient())
    {
        try
        {
            httpClient.DefaultRequestHeaders.Authorization =
                new AuthenticationHeaderValue("bearer", authResult.AccessToken); // &lt;-- Authentication token got from the MSAL code
            string result = await httpClient.GetStringAsync(uri);

            Rootobject root = new Rootobject(); // JSON pasted as a class :-). See below
            MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
            DataContractJsonSerializer ser = new DataContractJsonSerializer(root.GetType());
            root = ser.ReadObject(ms) as Rootobject;
            // Display some text like ($"id={root.value[0].id}"); // root.value[0].id is the Object ID of the first person found
        }
        catch (Exception ex)
        {
            // Display some text like ($"Failed to query MS Graph: {ex.Message}");
        }
    }
}
</code></pre>
You noticed that this code uses a class named <code>Rootobject</code>. It represents the object(s) we will received from the Graph call. This class can be easely created by using the nice Visual Studio Feature called <strong>Paste JSON as Classes</strong>. You just have to test the Graph API in the <a target="_blank" href="https://developer.microsoft.com/en-us/graph/graph-explorer" rel="noopener">Graph Explorer</a>, copy (to the clipboard) the resulting JSON and go back to Visual Studio: <strong>Edit</strong> menu / <strong>Paste Special</strong> / <strong>Paste JSON As Classes</strong>. Here is a demo:

<img alt="Paste JSON as Classes video" src="https://msdnshared.blob.core.windows.net/media/2018/12/UseGraphInMixedRealityPasteJSON.gif" />

For the Graph call done today, the classes are the following. You can add them in the <strong>Startup.cs</strong> file just after the <strong>Startup</strong> class:
<pre><code class="language-csharp">public class Rootobject
{
    public string odatacontext { get; set; }
    public Value[] value { get; set; }
}

public class Value
{
    public string id { get; set; }
}
</code></pre>
Finally, as promised, the <code>using</code> statements required are:
<pre><code class="language-csharp">using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using System;
#if UNITY_WSA &amp;&amp; !UNITY_EDITOR
using System.Net.Http;
using System.Net.Http.Headers;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
using Microsoft.Identity.Client;
#endif
</code></pre>
<h2 id="the-sample-code-">The sample code 📜</h2>
As usual, you will find the sample code on GitHub - <a href="https://github.com/Microsoft/Windows-AppConsult-Samples-MixedReality/tree/master/MixedReality-MSGraph">https://github.com/Microsoft/Windows-AppConsult-Samples-MixedReality/tree/master/MixedReality-MSGraph</a>.

Here is extracted the full code you will need for the <strong>Startup.cs</strong> script:
<pre><code class="language-csharp">using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using System;
#if UNITY_WSA &amp;&amp; !UNITY_EDITOR
using System.Net.Http;
using System.Net.Http.Headers;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
using Microsoft.Identity.Client;
#endif

public class Startup : MonoBehaviour
{
    // Use this for initialization
    async void Start()
    {
        await GoGraph();
    }

    private async Task GoGraph()
    {
#if UNITY_WSA &amp;&amp; !UNITY_EDITOR
        // Get the authentication token using Microsoft.Identity.Client
        bool authenticated = false;
        PublicClientApplication client = new PublicClientApplication("06644049-fd27-4366-9dfb-c9f1bd99d35a");
        AuthenticationResult authResult = null;
        IEnumerable&lt;string&gt; Scopes = new List&lt;string&gt; { "User.Read", "User.ReadBasic.All" };
        try
        {
            authResult = await client.AcquireTokenAsync(Scopes);
            // FOVFeedback.instance.ModifyText($"UniqueId={authResult.UniqueId}, AccessToken={authResult.AccessToken}");
            authenticated = true;
        }
        catch (MsalException msaEx)
        {
            FOVFeedback.instance.ModifyText($"Failed to acquire token: {msaEx.Message}");
        }
        catch (Exception ex)
        {
            FOVFeedback.instance.ModifyText($"Failed to acquire token: {ex.Message}");
        }


        if (authenticated)
        {
            // Query MS Graph using a HTTP GET
            string GraphUriAndQuery = @"https://graph.microsoft.com/v1.0/users?$filter=startswith(Displayname,'Marty')&amp;$select=id";
            var uri = new System.Uri(GraphUriAndQuery);
            using (HttpClient httpClient = new HttpClient())
            {
                try
                {
                    httpClient.DefaultRequestHeaders.Authorization =
                        new AuthenticationHeaderValue("bearer", authResult.AccessToken);
                    string result = await httpClient.GetStringAsync(uri);

                    Rootobject root = new Rootobject();
                    MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
                    DataContractJsonSerializer ser = new DataContractJsonSerializer(root.GetType());
                    root = ser.ReadObject(ms) as Rootobject;
                    FOVFeedback.instance.ModifyText($"id={root.value[0].id}");
                }
                catch (Exception ex)
                {
                    FOVFeedback.instance.ModifyText($"Failed to query MS Graph: {ex.Message}");
                }
            }
        }
#else
        FOVFeedback.instance.ModifyText(":-( The app does not work in the Editor");
#endif
    }
}


public class Rootobject
{
    public string odatacontext { get; set; }
    public Value[] value { get; set; }
}

public class Value
{
    public string id { get; set; }
}
</code></pre>
<blockquote><strong>Note:</strong> This code uses <strong>FOVFeedback.instance.ModifyText()</strong> which is in the repo. Do not hesitate to replace with <code>Debug.Log()</code> if you create the sample from scratch.</blockquote>
<iframe src='https://gfycat.com/ifr/IllegalThoroughBighornedsheep' frameborder='0' allowfullscreen width='640' height='360'></iframe><p> <a href="https://gfycat.com/IllegalThoroughBighornedsheep">via Gfycat</a></p>

<h2 id="conclusion">Conclusion</h2>
This is really a trivial sample querying for the Object ID of an user in the Azure Active Directory ; but you have now the base Unity/Visual Studio project to do everything you want 🎈🚀 with Microsoft Graph in HoloLens and Mixed Reality! Just use the <a target="_blank" href="https://developer.microsoft.com/en-us/graph/graph-explorer" rel="noopener">Graph Explorer</a> and update the HTTP call + the JSON classes.

Remember that, because the Microsoft Graph can be used by any code and any platform, you can get great insights and data in you Mixed Reality Apps! It is now your turn 😉

Bye,

<a target="_blank" href="https://twitter.com/sbovo" rel="noopener">@sbovo</a> for the 💻 🎮 Windows AppConsult team.

--
<h2 id="references">References</h2>
<ul>
 	<li>Source code on GitHub - <a href="https://github.com/Microsoft/Windows-AppConsult-Samples-MixedReality/tree/master/MixedReality-MSGraph">https://github.com/Microsoft/Windows-AppConsult-Samples-MixedReality/tree/master/MixedReality-MSGraph</a></li>
 	<li>30 Days of Microsoft Graph - <a href="https://developer.microsoft.com/en-us/graph/blogs/announcing-30-days-of-microsoft-graph-blog-series">https://developer.microsoft.com/en-us/graph/blogs/announcing-30-days-of-microsoft-graph-blog-series</a></li>
 	<li>Build UWP apps with Microsoft Graph - <a href="https://docs.microsoft.com/en-us/graph/training/uwp-tutorial">https://docs.microsoft.com/en-us/graph/training/uwp-tutorial</a></li>
 	<li>Graph Explorer - <a href="https://developer.microsoft.com/en-us/graph/graph-explorer">https://developer.microsoft.com/en-us/graph/graph-explorer</a></li>
 	<li>Microsoft Graph and HoloLens: Authentication - <a href="https://blogs.msdn.microsoft.com/appconsult/2018/04/12/microsoft-graph-and-hololens-authentication/">https://blogs.msdn.microsoft.com/appconsult/2018/04/12/microsoft-graph-and-hololens-authentication/</a></li>
 	<li>Graph APIs reference - <a href="https://docs.microsoft.com/en-us/graph/api/overview?view=graph-rest-1.0">https://docs.microsoft.com/en-us/graph/api/overview?view=graph-rest-1.0</a></li>
 	<li>How to: Serialize and Deserialize JSON Data <a href="https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-serialize-and-deserialize-json-data">https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-serialize-and-deserialize-json-data</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Alexa + Azure Functions + Microsoft Graph = a smarter assistant!</title>
      <link>https://docs.microsoft.com/archive/blogs/appconsult/alexa-azure-functions-microsoft-graph-a-smarter-assistant</link>
      <pubDate>Wed, 05 Dec 2018 08:17:23 GMT</pubDate>
      <dc:creator><![CDATA[Matteo Pagani]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/appconsult/?p=24145</guid>
      <description><![CDATA[On this blog we have recently learned how to build an Alexa Skill using Microsoft tools and...]]></description>
      <content:encoded><![CDATA[<p>On this blog <a href="https://blogs.msdn.microsoft.com/appconsult/2018/11/02/build-your-first-alexa-skill-with-alexa-net-and-azure-functions-the-basics/">we have recently learned</a> how to build an Alexa Skill using Microsoft tools and platforms, like C#, Visual Studio and Azure Functions. The skill we have built <a href="https://blogs.msdn.microsoft.com/appconsult/tag/alexa/">in the previous posts</a> was available to every user: it didn't need to know who the user is asking the questions in order to return a proper feedback. However, there are some scenarios where this approach isn't good enoguh. Think, for example, to a skill to order food that can be delivered at home. The skill must know who is placing the order, to charge your credit card with the total amount; or to pick your home location as delivery address.</p>
<p>For these scenarios, Alexa provides a feature called <strong>account linking</strong>. When the user enables the skill, he will be requested to authenticate to a 3rd party service using an OAuth 2.0 flow. Once the linking is successful, every request to the skill will be authenticated against the service and Alexa will send you, in the JSON request, the access token which is required to perform further operations.</p>
<p>You can identify skills which require account linking thanks to the message displayed under the <strong>Enable</strong> button in the Alexa Store.</p>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantlogin1.png" alt=""></p>
<p>In this blog post we're going to see how to implement this flow by adding support to Azure Active Directory authentication and the Microsoft Graph to a skill. We'll welcome the user by saying his name and we'll be able to provide information about his OneDrive storage.</p>
<p>Let's start!</p>
<h3 id="the-account-linking">The account linking</h3>
<p>To setup the account linking you need to select your skill on the <a href="https://developer.amazon.com/alexa/console">Alexa Developer Console</a> and choose <strong>Account linking</strong> from the menu on the left:</p>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantaccountlinking1.png" alt=""></p>
<p>In the first part of the page you'll be able to customize the configuration of the account linking. In order to enable it, you have to turn on the first option <strong>Do you allow users to create an account or link to an existing account with you?</strong>. This will enable the message you have seen in the previous image in the Alexa Store.
The second option can be used if your skill offers some features which can be leveraged also without linking an account. For example, the food delivery skill could offer a command to know the restaurants around you which can be freely invoked; however, as soon as you try to order some food, you'll be asked to link your account.
In our scenario, we leave this option turned off. Our skill needs to use the Microsoft Graph, so we aren't able to provide any feature if the user hasn't login with his Microsoft Account.</p>
<p>Then make sure to check <strong>Auth Code Grant</strong> as authorization grant type, since it's the safest one.</p>
<p>The rest of the page is dedicated to configure the OAuth 2.0 flow, which will be triggered when the user enables the skill and authenticates with the 3rd party service. Let's take a step back and take a look at how the OAuth 2.0 flow works:</p>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantoauth21.png" alt=""></p>
<p>The process involves three steps:</p>
<ol>
<li>First, the client application (in our case, the skill) sends an authorization request to the specific endpoint exposed by the service. The user will see a popup or he will be redirected to a different page (in case of a web application), where he will be asked to login with his credentials. This page belongs to the owner of the service. This means that the client application (in our case, neither Amazon nor our skill) will never get access to the credentials of the user.</li>
<li>If the authorization request is approved, the application can use the received grant to request an access token. The access token is a unique identifier of the user which, however, doesn't contain any information that can be used to identify his credentials.</li>
<li>Once we have the access token, we can now finally access to all the protected resources exposed by the service. The access token will be included as authorization header of every request and, if it's valid, we will receive the resource we have asked.</li>
</ol>
<p>If we take a look now at the section to configure the OAuth 2.0 flow, we will see how the various fields match the flow we have just highlighted:</p>
<ul>
<li><strong>Authorization URI</strong>: this is the endpoint exposed by the service to ask the permission to start using it. You send a request with all the details to identify your application and, if approved, you will receive back the authorization code.</li>
<li><strong>Access Token URI</strong>: this is the endpoint to use as next step. After we have been authorized to use the service, we can use the authorization code to send a request to this URI to get back the access token.</li>
<li><strong>Client ID</strong> is the unique identifier of our application.</li>
<li><strong>Client secret</strong> is a password which has been provided by the owner of the service to authenticate our application.</li>
<li><strong>Scope</strong> is a set of values which which identiy the features of the service we want to leverage.</li>
</ul>
<p>In our scenario, we need to authenticate to the Microsoft Graph using a Microsoft Account or an Office 365 account. Where can we find all the information we need to fill the Account Linking page in the Amazon portal?
In order to leverage authentication with a 3d party service, we need to register our application against it. For this reason, all the 3rd party services which provide authentication (Microsoft, Google, Twitter, GitHub, etc.) offer a developer portal that can be used to register an application and to obtain all the credentials we need to implement the authentication flow.</p>
<p>The one offered by Microsoft to register an application which needs to support Azure AD authentication is available in the Azure Portal. As such, the first step is to login to <strong><a href="https://portal.azure.com">https://portal.azure.com</a></strong> using the account which you want to use to register your application (Microsoft Account or Office 365).
Once you are logged into Azure, open the <strong>Azure Active Directory</strong> section and choose <strong>App registrations (Preview)</strong>:</p>
<p><a href="appregistration.png"></a></p>
<p>Let's start to register our application. Click on the <strong>New registration</strong> button.</p>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantregisterapplication1.png" alt=""></p>
<p>First give to your application a unique name. In my case, I chose <strong>MyAlexaSkill</strong>. Then you must specify which account types you want to support:</p>
<ul>
<li><strong>Accounts in the organizational directory only</strong>: if you're logged in with an Office 365 account, you will be able to create an application which is authorized to allow the login only for users from your organization. This approach is useful when you're building an internal app, which my be used only by people from your company.</li>
<li><strong>Accounts in any organizational directory</strong>: this option will enable any Office 365 user to login with their account, regardless of the tenant they belong to.</li>
<li><strong>Accounts in any organizational directory and personal Microsoft Account</strong>: this option will enable not only Office 365 users to login, but also users with a personal Microsoft Account.</li>
</ul>
<p>In our scenario, let's enable the third option. We want to enable every user to use the skill to know how much space they have left on OneDrive, regardless if it's the personal space or the business one.</p>
<p>Ignore, for the moment, the <strong>Redirect URI</strong> section. We're going to fill it later. Press <strong>Register</strong> at the end of the section.</p>
<p>Now we can start to fill the various field in the Alexa Developer Portal. Let's see where to retrieve the various parameters:</p>
<ul>
<li><strong>Authorization URI</strong> and <strong>Access Token URI</strong>: we can find this information by clicking on the <strong>Endpoints</strong> button.</li>
</ul>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantendpoints1.png" alt=""></p>
<p>From there, we need to copy the two URIs under <strong>OAuth 2.0 authorization endpoint (v2)</strong> and <strong>OAuth 2.0 token endpoint (v2)</strong>.</p>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantoauth2endpoints1.png" alt=""></p>
<ul>
<li><strong>Client Id</strong> can be retrieved in the main page under <strong>Application (client) ID</strong>:</li>
</ul>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantclientid1.png" alt=""></p>
<ul>
<li><strong>Client Secret</strong> must be generated from the Azure portal. Click on <strong>Certificates &amp; secrets</strong> in the left panel, then click on <strong>New client secret</strong>. Give it a description and choose an expiration date. In the context of a skill, you can safely choose <strong>Never</strong>. This way, you won't have to remember to update, from time to time, the client secret in the Alexa Developer Portal. Once the secret has been generated, copy it in the portal and store it also somewhere safe. The reason is that this is the only time you'll be able to see the client secret in clear. After that, it will be automatically masked and there won't be any way to see it again. You'll be forced to generate a new one, if you lose it.</li>
</ul>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantclientsecret1.png" alt=""></p>
<ul>
<li><strong>Client Authentication Scheme</strong>: keep <strong>HTTP Basic</strong>.</li>
<li><strong>Scope</strong> must match the various scopes that we have enabled in the Azure portal. You can see them by clicking on <strong>API permissions</strong> in the Azure app configuration. By default, the standard one is <strong>User.Read</strong>, which allows the application to read the basic information of the user profile, like his name or his mail address. If you want to add more scopes, you can click on <strong>Add a permission</strong> and explore all the other scopes that are offered by the Azure services or by your custom services. In this case, we're building a skill which integrates with the Microsoft Graph, so you'll find all the available permissions under <strong>Microsoft Graph</strong>:</li>
</ul>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantmicrosoftgraph1.png" alt=""></p>
<p>Scopes are categorized as <strong>Delegated permissions</strong> and <strong>Application permissions</strong>. In our case, we want the skill to access to the API as the signed user, so we can focus on the first category. From there, you'll be able to explore all the available scopes and enable the ones you need. Pay attention that, for some of them, you may see the value <strong>Yes</strong> in the <strong>Admin consent required</strong> column. If you're building an enterprise skill which authenticates with an Office 365 account, the administrator of the tenant may block the usage of some scopes for security reasons. In such cases, you will need to reach him to ask to enable the proper permissions.</p>
<p>Once you have defined the scopes you need, you will need to copy them inside the <strong>Scope</strong> field of the Alexa Developer Portal. If you have multiple scopes, you can click on the <strong>+</strong> button to add new fields.</p>
<p>The last step requires the opposite process compared to what we have done so far. We'll need to take some info from the Alexa Developer Portal and copy them to the Azure one. In the OAuth 2.0 flow, in fact, once the authentication process is completed the service will forward the response to a specific endpoint exposed by our application. In this case, since it's an Alexa skill, the endpoints are provided directly by Amazon. We can find them at the end of the Account Linking configuration page:</p>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantredirecturi1.png" alt=""></p>
<p>We need to copy them in the Azure Portal, in the <strong>Authentication</strong> section:</p>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantredirecturiazure1.png" alt=""></p>
<p>Hit <strong>Save</strong> to complete the process, then move back to the Alexa Developer Portal and hit <strong>Save</strong> also there. We're done! Now account linking should have been properly enabled.</p>
<p>This is how the configuration of your Alexa skill should look like:
<img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantauth1.png" alt=""></p>
<p>In order to test the linking, we need to open the Alexa web application, which you can find at <a href="https://alexa.amazon.com">https://alexa.amazon.com</a>. Login with your account, move to the <strong>Skills</strong> section and click on the <strong>Your skills</strong> button on the top right.</p>
<p><strong>Please note!</strong> I apologize if the following screenshots are in Italian, but it seems that there's no way to force Amazon to display the application in English if your account is based in Italy. However, they should be helpful to understand where to look for the various options.</p>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantyourskills1.png" alt=""></p>
<p>You will find multiple categories, including one called <strong>Skills for developers</strong>. Here you will find all the skills you have created in the Alexa Developer Portal. Look for the one you're working on and notice how, below the name, you will see now a message informing that account linking is required.</p>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantaccountlinkingneeded1.png" alt=""></p>
<p>Click on the skill and enable it. If you did everything correctly, another windows or tab of your browser will open up to display the Microsoft Account authentication page. Login with your Microsoft Account or Office 365 account and you should be all set! You should see a confirm message notifying you that your account is now linked to the skill.</p>
<h3 id="handling-the-authentication-in-the-azure-function">Handling the authentication in the Azure Function</h3>
<p>Now that we have completed the configuration on the portal, we need to start working on our backend, which is hosted by an Azure Function. We need, in fact, to retrieve the access token and use it to perform operations with the Microsoft Graph.
I won't explain from scratch how to build an Alexa Skill hosted by an Azure Function, since we already did it <a href="https://blogs.msdn.microsoft.com/appconsult/tag/alexa/">in the previous posts</a>. Here we will focus only on the relevant snippets for handling the authentication process.</p>
<p>Thanks to Alexa.NET it's easy to retrieve the token, since it's stored in the <strong>Session.User.AccessToken</strong> property of the <strong>SkillRequest</strong> object, which is the one that maps the JSON coming from Alexa with all the details about the request:</p>
<pre><code class="language-csharp">public static async Task&lt;IActionResult&gt; Run([HttpTrigger(AuthorizationLevel.Anonymous, &quot;post&quot;, Route = null)] HttpRequest req, ILogger log)
{
    var json = await req.ReadAsStringAsync();
    var skillRequest = JsonConvert.DeserializeObject&lt;SkillRequest&gt;(json);

    var token = skillRequest.Session.User.AccessToken;
    
    ///handle the request and return the response
}
</code></pre>
<p>Now that we have the token, we can use it to perform operations against the Microsoft Graph. The Graph is nothing more than a set of REST endpoints, which you can call by sending HTTP commands. Based on the type of operation, it could be a GET, a POST, a PUT, etc. The easiest way to understand the opportunities offered by the Microsoft Graph is to use <a href="https://developer.microsoft.com/en-us/graph/graph-explorer">Graph Explorer</a>, which is a sort of playground. You can login with your Microsoft Account or Office 365 account and then start making request to the APIs. The tool will offer you the opportunity to compose requests and to observe the JSON response, other than discovering all the available endpoints.</p>
<p><img src="https://msdnshared.blob.core.windows.net/media/2018/12/Alexa-Azure-Functions-Microsoft-Graph-a-smart-assistantgraphexplorer1.png" alt=""></p>
<p>However, we are not required to perform manual HTTP requests in order to use the Graph. Microsoft, in fact, <a href="https://github.com/microsoftgraph?utf8=%E2%9C%93&amp;q=sdk&amp;type=&amp;language=">provides multiple SDKs</a> which encapsulate all the logic to work with the Graph, similarly to how Alexa.NET abstracts all the JSON requests and responses and allows you to work with classes and objects. Of course, we have also <a href="https://www.nuget.org/packages/Microsoft.Graph">a SDK for .NET</a>, so we can easily integrate it in our Azure Function.</p>
<p>Right click on your project in Visual Studio, choose <strong>Manage NuGet packages</strong> and install the package called <strong>Microsoft.Graph</strong>.</p>
<p>The object that we can use to perform operations against the Graph is called <strong>GraphServiceClient</strong>, which is included in the <strong>Microsoft.Graph</strong> namespace. However, we can't use it as it is. We need to use an authenticated client, so we will need to supply the access token included in the request.</p>
<p>Here is a simple setup method that we can add to our Azure Function:</p>
<pre><code class="language-csharp">public static GraphServiceClient GetAuthenticatedClientForUser(string token, ILogger logger)
{
   GraphServiceClient graphClient = null;

   // Create Microsoft Graph client.
   try
   {
       graphClient = new GraphServiceClient(
           &quot;https://graph.microsoft.com/v1.0&quot;,
           new DelegateAuthenticationProvider(
               (requestMessage) =&gt;
               {
                   requestMessage.Headers.Authorization = new AuthenticationHeaderValue(&quot;bearer&quot;, token);
                   return Task.CompletedTask;
               }));

       return graphClient;

   }
   catch (Exception exc)
   {
       logger.LogError(exc, &quot;Could not create a graph client&quot;);
   }

   return graphClient;
}
</code></pre>
<p>We create a new instance of the <strong>GraphServiceClient</strong> object, passing as parameter:</p>
<ol>
<li>The endpoint we want to use for the Graph. We use the production one, which is <strong><a href="https://graph.microsoft.com/v1.0">https://graph.microsoft.com/v1.0</a></strong>. There's also a preview one, which provides access to all the beta APIs, and it's available at <strong><a href="https://graph.microsoft.com/beta">https://graph.microsoft.com/beta</a></strong>.</li>
<li>A <strong>DelegateAuthenticationProvider</strong>, which is the delegate used to handle the authentication. The delegate provides a reference to the HTTP request which is sent to the Microsoft Graph, that we need to customize by supplying the access token in the authorization header.</li>
</ol>
<p>Now that we have an authenticated client, we can use it to perform operations with the Graph. For example, let's customize the welcome message of the skill by adding the name of the user. We do this in case the incoming request type is <strong>LaunchRequest</strong>:</p>
<pre><code class="language-csharp">public static async Task&lt;IActionResult&gt; Run([HttpTrigger(AuthorizationLevel.Anonymous, &quot;post&quot;, Route = null)] HttpRequest req, ILogger log)
{
   var json = await req.ReadAsStringAsync();
   var skillRequest = JsonConvert.DeserializeObject&lt;SkillRequest&gt;(json);

   // Verifies that the request is indeed coming from Alexa.
   var isValid = await skillRequest.ValidateRequestAsync(req, log);
   if (!isValid)
   {
       return new BadRequestResult();
   }

   var request = skillRequest.Request;
   SkillResponse response = null;

   var token = skillRequest.Session.User.AccessToken;
   var client = GetAuthenticatedClientForUser(token, log);

   if (request is LaunchRequest launchRequest)
   {

       var me = await client.Me.Request().GetAsync();

       var welcomeMessage = $&quot;Welcome {me.DisplayName}&quot;;
       response = ResponseBuilder.Tell(welcomeMessage);
   }
   
    return new OkObjectResult(response);
}
</code></pre>
<p>The client simply maps all the endpoints that you can see in the Graph Explorer as objects. As such, in order to get the basic profile of the user (which is mapped with the endpoint <a href="https://graph.microsoft.com/v1.0/me/">https://graph.microsoft.com/v1.0/me/</a>), we can use the <strong>Me</strong> property exposed by the client. To actually perform the request we need to call the <strong>Request()</strong> method, followed by the HTTP method we need to use. In this case, the <strong>me</strong> endpoint replies to a HTTP GET, so we call the <strong>GetAsync()</strong> method.
We get in return an object which maps all the properties that we can see in the response JSON in Graph Explorer. For our scenario, we retrieve the name using the <strong>DisplayName</strong> property and we add it to the welcome message.
The rest of the code is the same we've seen in the other posts: we use the <strong>ResponseBuilder</strong> class to create a response and then we send it back as response to the Alexa service which invoked our function.</p>
<p>Now we that we have seen how to handle the authentication in the backend, the sky is the limit 😃 For example, if we follow our original idea of integrating OneDrive with our Alexa skill, we can create a new intent in the Interaction Model with name <strong>Quota</strong> and then, in the function, handle it with the help of the Graph client:</p>
<pre><code class="language-csharp">if (intentRequest.Intent.Name == &quot;Quota&quot;)
{
    var drive = await graphClient.Me.Drive.Request().GetAsync();
    int free = (int)(drive.Quota.Remaining.Value / 1024 / 1024 / 1024);

    var quotaMessage = $&quot;You have {free.ToString()} GB available&quot;;
    response = ResponseBuilder.Tell(quotaMessage);
}
</code></pre>
<p>The structure of the code is the same as the previous example. If we use <a href="https://developer.microsoft.com/en-us/graph/graph-explore">Graph Explorer</a>, we can see how the information about the OneDrive storage of the user is available through the <strong><a href="https://graph.microsoft.com/v1.0/me/drive">https://graph.microsoft.com/v1.0/me/drive</a></strong> endpoint. This endpoint is mapped by the property <strong>Me.Drive</strong>, which returns a <strong>Drive</strong> object that contains all the properties of the storage. Thanks to the <strong>Quota</strong> property we can get the information we're looking for, which is the available space, and we use it to build a response for the user.</p>
<h3 id="wrapping-up">Wrapping up</h3>
<p>In this post we have seen how to enable account linking for an Alexa Skill, allowing it to identify the user and to provide customized responses. In this specific example we have leveraged AAD authentication and the Microsoft Graph, but any service which supports OAuth 2.0 for the authentication flow is supported. You could integrate your Alexa skill, for example, with Twitter, GitHub, Facebook, etc.</p>
<p>Thanks to the OAuth 2.0 configuration provided in the Alexa Developer Portal, you don't have to handle the authentication flow on your own, by manually communicating with the various authentication and access token endpoints. You just have to provide to Amazon the configuration of your service and, automatically, you will receive the access token in the body of the request which is delivered to your skill.</p>
<p>You can find the full OneDrive sample on GitHub at <a href="https://github.com/Microsoft/Windows-AppConsult-samples-PWA/tree/master/OneDriveAlexaSkill">https://github.com/Microsoft/Windows-AppConsult-samples-PWA/tree/master/OneDriveAlexaSkill</a>. Of course, you will find only the code of the backend Azure Function. It's up to you to create the most appropriate interaction model and to setup an Azure AD application to support the authentication.</p>
<p>A huge thanks to my friend <a href="https://twitter.com/marcominerva">Marco Minerva</a>, who is sharing with me lot of interesting activities around Alexa skills and who helped me in setting up Account Linking.</p>
<p>Happy coding!</p>]]></content:encoded>
    </item>
    <item>
      <title>Computer Vision for Augmented Reality</title>
      <link>https://docs.microsoft.com/archive/blogs/appconsult/23635</link>
      <pubDate>Mon, 19 Nov 2018 05:12:14 GMT</pubDate>
      <dc:creator><![CDATA[Marc Plogas]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/appconsult/?p=23635</guid>
      <description><![CDATA[This blog post is a condensed version of one of my recent talks on Augmented Reality and computer...]]></description>
      <content:encoded><![CDATA[This blog post is a condensed version of one of my recent talks on Augmented Reality and computer vision. Since my colleagues <a href="https://blogs.msdn.microsoft.com/appconsult/2018/11/06/upgrade-your-winml-application-to-the-latest-bits/" rel="noopener" target="_blank">Matteo Pagani</a> and <a href="https://blogs.msdn.microsoft.com/appconsult/2018/11/15/23535/" rel="noopener" target="_blank">Sebastien Bovo</a> released the practical approach to WinML in Windows 10 and Hololens Unity, I felt it's time to shed some light on the theory.
<h2 id="1-the-why">1. The Why</h2>
Thanks to the runaway success of mobile AR games, such as Pokemon GO, the experience of augmented reality has become familiar to the mainstream audience. This gets even more important, as big companies such as Microsoft, Apple and Google made AR APIs part of their operating system, they're now available for everyone. In the beginning, those APIs were rather lean, only allowing to place holograms somewhere in that area but lateley SLAM capabilities (Simulataneous Localization and Mapping, algorithm-based position prediction based on sensory input) were have been added. That allows a more accurate placement of holograms in the environment, e.g. on top of shelves or beneath tables.

With computer vision, I think we will see a next step in AR, allowing even more realism and immersion in many fields in the consumer and enterprise space.
<h2 id="2-the-basics">2. The Basics</h2>
<em>Note: Please keep in mind that I'm conveniently skipping over the math part, as I'm just trying to give a basic understanding of how computer vision works.</em>
<h3 id="21-the-big-picture">2.1 The big picture</h3>
What is Machine Learning? Well, for a start it's one of those buzzwords StartUps keep using to get funded. If you talk to a computer scientist or data scientist however, they will tell you it's generally the idea of computers finding interesting things in sets of data with the help of generic algorithms without them (the scientist) having to write code specific to the problem. Instead, they only feed data to the generic algorithm and it builds it own logic based on the input.

For example, take the classification algorithm: it sorts data into different groups. The same generic algorithm that is used to differentiate cats from dogs can be used to recognize handwritten letters. It's the same algorithm, but it's fed different training data so it builds a different classification logic.

Pretty neat, huh?
<h3 id="22-supervised-learning">2.2 Supervised Learning</h3>
There are basically two main umbrella categories for machine learning. one is supervised learning, the other is, unsurprisingly, unsupervised learning.

<strong>So, what is supervised learning and why is the difference important?</strong>
Say you have a small retail business on eBay (or Amazon Markets) selling all sorts of cables. LAN, Lightning, USB, you name it! You're doing great and would like to go on extended vacation with your family and hand over the business to a trainee in the meantime. In order to help your trainee you have written down some previous sales in Excel, showing the price of a cable based on the port, color and length.
<table width="550" border="1" cellpadding="5" align="center">
<thead>
<tr>
<th>Length</th>
<th>Port</th>
<th>Color</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>1.0m</td>
<td>USB-C</td>
<td>Black</td>
<td>9.99€</td>
</tr>
<tr>
<td>0.5m</td>
<td>Lightning</td>
<td>White</td>
<td>29.99€</td>
</tr>
<tr>
<td>2.0m</td>
<td>microUSB</td>
<td>Red</td>
<td>12.99€</td>
</tr>
<tr>
<td>2.0m</td>
<td>USB-C</td>
<td>Red</td>
<td>13.99€</td>
</tr>
<tr>
<td>0.5m</td>
<td>microUSB</td>
<td>White</td>
<td>6.99€</td>
</tr>
</tbody>
</table>
Using the information from previous sales, you want your trainee to figure out the price for any other cable that is ordered.
<table width="550" border="1" cellpadding="5" align="center">
<thead>
<tr>
<th>Length</th>
<th>Port</th>
<th>Color</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>2.0m</td>
<td>Lightning</td>
<td>White</td>
<td>?.??€</td>
</tr>
</tbody>
</table>
S/He already knows how other cables were previously sold for and with some skills in arithmetics s/he could figure out the price of the 2.0m Lightning cable. And if s/he's smart, s/he would come up with weighting the input parameters to fine-tune the predictability of your algorithm.

<img src="https://msdnshared.blob.core.windows.net/media/2018/11/Community-MixedReality-MeetupBerlinsupervised_01.png" alt="" />

That is called supervised learing, as you letting your trainee (or your computer) figure out the relationship (and importance) between length, port, color and price.

<strong>Okay, letting my trainee do all the work while I'm on vacations sounds good to me! Why do I need unsupervised learning then?</strong>

Short answer: for computer vision, you won't! But if you're interested in patterns that could help you with marketing and sales, this is for you. For example you would find out that Lightning cables are usually sold in white and never in a size above 2.00m. Or that USB-C is sold equally in any color, except for the length below 1.00m, then it's alway black. And so on.

There are also other categories of machine learning (e.g. reinforcement learning), as well as hybrids (semi-supervised and active). For more information see here: <a href="https://en.wikipedia.org/wiki/Machine_learning#Machine_learning_tasks">https://en.wikipedia.org/wiki/Machine_learning#Machine_learning_tasks</a>
<h3 id="23-neural-networks">2.3 Neural Networks</h3>
Our trainee might have figured out that the algorithm only works for linear relationships between input and output. But what if the right pricing prediction only comes to light when combining parameter results into intermediate layers, e.g. color combined with a certain port has a completly different weight?

<img src="https://msdnshared.blob.core.windows.net/media/2018/11/Community-MixedReality-MeetupBerlinneuralnetwork_01.png" alt="" />

This small unit of input data creating an output is called a neuron. It doesn't do much, but imagine the power of combining tens or hundreds of these neurons into a big network. That is called a neuronal network. Or a brain, on a much bigger scale.

Easy, huh? Well not so fast! I did not talk about <strong>data preprocessing</strong> (e.g. mean normalization, standardization or min-max normalization) or <strong>activation</strong>. It's very important to preprocess and standardize the inputs for the generic algorithm, so each input contributes approximately proportionally to the output. And sometimes the neuro should only be activated once a certain treshold in the input is reached, comparable to the action potential firing a neuron in your brain. This is called the activation function of a node.

What I also did not cover yet is the state of a neural network. If we will run our stateless neuronal network on our business numbers, it will predict "predictable" but it will never be able to adapt to seasonal buying patterns or learn from its mistakes. The network needs a memory to improve the prediction and the memory updating the network everytime it is used. This very simple (and very hard) idea is called Recurrent Neuronal Network and is widely used in text generation, machine translation and speech recognition.

<img src="https://msdnshared.blob.core.windows.net/media/2018/11/Community-MixedReality-MeetupBerlinrnn_o1.png" alt="" />

Further information can be found here: <a href="https://www.wildml.com/2015/09/recurrent-neural-networks-tutorial-part-1-introduction-to-rnns/">https://www.wildml.com/2015/09/recurrent-neural-networks-tutorial-part-1-introduction-to-rnns/</a>
<h3 id="24-convolutional-neural-networks">2.4 Convolutional Neural Networks</h3>
So, we were talking about business numbers and predictions a lot, but the title clearly says <strong>computer vision</strong>. The connection isn't clearly visible yet (excuse the pun)!

Computer vision (as well as speech recognition) has kept the computer scientist puzzled for a long time and made some break-throughs only recently with so-called convolutional neural networks. We already covered the neural network part, but what is convolutional?

To explain this, we need to take a step back and look at our favorite cat picture (or dog picture, if you're a dog person). How could a binary input possibly fed into a neural network? Well in computer science everything is just a clever reprentation of numbers. Not the 1s and 0s, because that's a step too far but every colored pixel in the image is just a 3-dimensional (RGB, or 4-dimensional if you're talking CMYK) array of numbers. So a pixel of a firetruck is likely represented as <code>[255,0,0]</code> while a pixel of sun could be a <code>[100,255,0]</code> or a pixel of a leaf <code>[0,255,100]</code>. You get the point. By separating the color dimensions (and thus flattening them to grey-scale) and cutting the original image into smaller chunks (e.g. 32x32), we now have an array of 1024 values for each chunk. This is the input that is fed into our neuron.

<img src="https://msdnshared.blob.core.windows.net/media/2018/11/Community-MixedReality-MeetupBerlincnn_03.png" alt="" />

Of course, a single tile doesn't make a cat. What we need is more data! We get that data by analyzing all the pieces of the cat picture in many intermediate layers that feed their output in the next intermediate layer. This more complex neuronal network is called <strong>deep neuronal network</strong>, its training is called deep learning.

There is one catch, though. Using this neural network might allow me to recognize my cat laying on her back in the living room, but it won't be able to recognize any other cat or my cat in a different pose or different room. Does it mean we have to re-train the model for every cat in the world in every possible position? Eeek!

This is where Convolution comes to the rescue. The idea of convolution has its origin in biology and how mammal brains process image information. Some genius mathmaticians and computer scientist thought it's nice to convert that process into an algorithm. How right they were!

As a first step, the image is cut into overlapping chunks (e.g. of a size of 32x32) and its position in the original picture is stored. Each tile is then fed as input into the same neural network. Yes, the same neural network is used for every initial tile, therefore every chunk is evaluated equally! If the tile contains anything particulary interesting, it is marked as interesting. The output for each tile is placed according to the original position of the tile, so the overall result is a matrix of output arrays. This matrix contains information of where the most interesting parts of the picture were found. (Note: interesting is relative, and intrinsic to that layer - e.g. gradient changes, zig-zag patterns or even large patterns of blue). The matrix is rather large, however. Compression isn't an option as we actually need to achieve non-linear information loss. So downsampling it is, max pooling in particular. In layman terms, the algorithm just looks at each 2x2 square and just keeps the biggest (a.k.a. most interesting) number.

<img src="https://msdnshared.blob.core.windows.net/media/2018/11/Community-MixedReality-MeetupBerlinmax_pooling_01.png" alt="" />

And that's it! In a very, very simple world the reduced output array is now fed into a fully connected neural network that decides whether it's a cat or not. In real world, many convolutional and pooling layers stack on top of each other. To get a feeling you can peek into mature models, such as SqueezeNet, with the amazing Netron model visualizer by Lutz Röder (<a href="https://github.com/lutzroeder/Netron">https://github.com/lutzroeder/Netron</a>)

<img src="https://msdnshared.blob.core.windows.net/media/2018/11/Community-MixedReality-MeetupBerlincnn_02.png" alt="" />
<h3 id="25-testing-the-prediction">2.5 Testing the prediction</h3>
If you run your model on a service such as our Custom Vision service (<a href="https://customvision.ai">https://customvision.ai</a>) you may have seen some accuracy indicators. But what do they mean? If you feed your network with 10000 cat pictures and it predicted the correct answer in 97.8% of the time that sounds rather good. But does it really? Say I write a tiny method
<pre><code class="language-cs">private bool IsCat(byte[] image) 
{
    return true;
}
</code></pre>
and feed it 9850 cat pictures and 150 dog pictures, my dumb method is more accurate than our trained Convoluted Neural Network! I guess that settles it: <code>Programmers &gt; Data Scientist</code>. Yay!

Actually, no! In our custom vision service, a generic accuracy isn't displayed for a reason. Instead Precision and Recall are displayed

<img src="https://msdnshared.blob.core.windows.net/media/2018/11/Community-MixedReality-MeetupBerlinprecission_recall_01.png" alt="" />

To understand both, we need to define right and wrong in its 4 states:
<ol>
 	<li>True positive: a cat picture is correctly identified as cat</li>
 	<li>False positive: a dog picture is mistakenly labeled as cat</li>
 	<li>True negative: a dog picture is correctly identified as not-a-cat</li>
 	<li>False negative: a cat picture is mistakenly identified as not-a-cat</li>
</ol>
The results can be displayed in a 2x2 matrix.
<table width="550" border="1" cellpadding="5" align="center">
<thead>
<tr>
<th></th>
<th>cat</th>
<th>not-a-cat</th>
</tr>
</thead>
<tbody>
<tr>
<td>cat picture</td>
<td>9525</td>
<td>325</td>
</tr>
<tr>
<td>dog picture</td>
<td>27</td>
<td>123</td>
</tr>
</tbody>
</table>
Particulary interesting are the true positives and true negatives obviously, but also the mistakes. The weighting of the mistakes however depends on your particular case. Say you have a computer vision enabled cat feeding bowl, your cat might be more interested in the false negatives while your dog might be more interested in the false positives.

<strong>Precision</strong> is <code>True positives / positive guesses</code>. In layman terms if a cat is predicted by the model, how likely is that to be right?
<strong>Recall</strong> <code>True positives / total amount in dataset</code>. Or, much easier: What percentage of the actual cat pictures did the model correctly find?

So, in 94.2% the model guessed cats it was right. But it also found 93.6% of the cats in the data set.
<h2 id="3-the-implementation">3 The Implementation</h2>
The actual implementation is the easier part. It all should start with the evaluation of the use-case: is the device likely to be connected to the Internet? If so, do you require a continuous prediction or is an on-demand evaluation sufficient? On-Demand predictions on an always-connected device (e.g. a mobile device) are usually the easiest to implement, it's just a matter of REST calls and JSON deserialization. It's also nicer to the battery of the AR device.
<pre><code class="language-cs">public IEnumerator AnalyseCapturedImage(byte[] imageBytes)
{
    using (var unityWebRequest = UnityWebRequest.Post(endpoint, new WWWForm()))
    {
        unityWebRequest.SetRequestHeader("Content-Type", contentType);
        unityWebRequest.SetRequestHeader(headerKey, predictionKey);
        unityWebRequest.downloadHandler = new DownloadHandlerBuffer();
        unityWebRequest.uploadHandler = new UploadHandlerRaw(imageBytes) { contentType = contentType };
        yield return unityWebRequest.SendWebRequest();

        try
        {
            var jsonResponse = unityWebRequest.downloadHandler.text;
            var analysedObject = JsonUtility.FromJson&lt;AnalysedObject&gt;(jsonResponse);
            
            //you can now find the prediction result in analysedObject.predictions
        }
        catch (Exception e)
        {
            // exception handling
        }
    }
}
</code></pre>
If you're not connected to a reliable internet uplink or want to have continuous predictions, you should opt for a local evaluation. This is much heavier on the CPU or GPU, depending on the capabilities of your device and framework.

<img src="https://msdnshared.blob.core.windows.net/media/2018/11/Community-MixedReality-MeetupBerlingpu_winml.png" alt="" />

A Hololens running RS4 (1803) is not able to use the GPU, all predictions will be executed on the CPU. This will drain the battery really fast. If your device is upgraded to RS5 (1805) you are able to utilize the GPU. Just load the model from the local storage and bind the output. There is one catch though: if you're using the CustomVision service to train and export your model (like I do) you have to export it as v1.2 otherwise MLGen will give you a completly random error message.

My colleague Sebastian described the Windows ML implementation in great detail in his <a href="https://blogs.msdn.microsoft.com/appconsult/2018/11/15/23535/">blog post</a>]]></content:encoded>
    </item>
    <item>
      <title>Update your Windows desktop app to .NET Core 3.0.100-preview-009754</title>
      <link>https://docs.microsoft.com/archive/blogs/appconsult/update-your-windows-desktop-app-to-net-core-3-0-100-preview-009754</link>
      <pubDate>Fri, 16 Nov 2018 15:10:04 GMT</pubDate>
      <dc:creator><![CDATA[Matteo Pagani]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/appconsult/?p=23685</guid>
      <description><![CDATA[Recently we have learned how we can use the daily builds of .NET Core 3.0 to start experimenting...]]></description>
      <content:encoded><![CDATA[<a href="https://blogs.msdn.microsoft.com/appconsult/2018/10/29/move-your-first-steps-with-net-core-3-0-for-desktop-development/">Recently</a> we have learned how we can use the daily builds of .NET Core 3.0 to start experimenting with the upcoming support for WPF and Windows Forms. In the post we took <a href="https://github.com/Microsoft/Windows-AppConsult-Samples-DesktopBridge/tree/master/Blog-WpfNetCore/ExpenseIt">a WPF project</a>, a sample LOB app which I often use for my articles and sessions, and we migrated it to use .NET Core 3.0 instead of the traditional .NET Framework.

However, as highlighted in the previous post, the current .NET Core 3.0 support is highly experimental. The framework hasn't reached the public preview stage yet and we can play with it only using the daily build. As such, it isn't a big surprise that the newest version of .NET Core 3.0, specifically build <strong>3.0.100-preview-009754</strong>, has broken a few things 😃

If you would try to open the project <a href="https://blogs.msdn.microsoft.com/appconsult/2018/10/29/move-your-first-steps-with-net-core-3-0-for-desktop-development/">we have created the last time</a>, we won't be able to do it anymore due to an error returned by Visual Studio. Let's see in this post how to fix them. As first step, remember to download the latest .NET Core 3.0 daily build <a href="https://github.com/dotnet/core-sdk/blob/master/README.md#installers-and-binaries">from GitHub</a>.
<h3 id="welcome-visual-studio-2017-159">Welcome Visual Studio 2017 15.9</h3>
In the meantime the Visual Studio team has released a newer version of the IDE, 15.9 (previously available in the Preview channel), which includes an important change regarding .NET Core. By default, in fact, Visual Studio will now use only the latest stable version of .NET Core, even if you have a preview version installed on your machine. As such, after upgrading to Visual Studio 2017 15.9, if you try to open the project we have created the last time you will get the error <strong>Project file is incomplete. Expected imports are missing.</strong>:

<img alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/Update-your-Windows-desktop-app-to-.NET-Core-3.0.100-preview-009754error.png" />

To enable the usage of the preview version of .NET Core 3.0 we have just installed you need to go to <strong>Tools -&gt; Options -&gt; Projects and Solutions -&gt; .NET Core</strong>. You will find an option called <strong>Use previews of the .NET Core SDK</strong>, which you must turn on.

<img alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/Update-your-Windows-desktop-app-to-.NET-Core-3.0.100-preview-009754netcore.png" />

Now you can safely open the project we have built the last time. Well, more or less, since you'll get again the same error. The reason is that the definition of the project has changed with the last build. We can see that by opening a command prompt and creating a new project with the command:
<pre><code class="language-powershell">dotnet new wpf
</code></pre>
If we open the .csproj file with a text editor and we match it with the one of our existing project, we'll notice some differences:
<pre><code class="language-xml">&lt;Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"&gt;

  &lt;PropertyGroup&gt;
    &lt;OutputType&gt;WinExe&lt;/OutputType&gt;
    &lt;TargetFramework&gt;netcoreapp3.0&lt;/TargetFramework&gt;
    &lt;UseWPF&gt;true&lt;/UseWPF&gt;
  &lt;/PropertyGroup&gt;

&lt;/Project&gt;
</code></pre>
The file is simpler than the previous one. Other than a few key changes (like the name of the SDK), we can notice in fact that we don't have anymore an entry for each file which compose the project. Now, in fact, the project will automatically consider all the files which are included in the folder as part of the application.

Let's update the .csproj file of our <a href="https://github.com/Microsoft/Windows-AppConsult-Samples-DesktopBridge/tree/master/Blog-WpfNetCore/ExpenseItNetCore">previous project</a> to include the new changes. This is the final result:
<pre><code class="language-xml">&lt;Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"&gt;

  &lt;PropertyGroup&gt;
    &lt;OutputType&gt;WinExe&lt;/OutputType&gt;
    &lt;TargetFramework&gt;netcoreapp3.0&lt;/TargetFramework&gt;
    &lt;UseWpf&gt;true&lt;/UseWpf&gt;
  &lt;/PropertyGroup&gt;

  &lt;ItemGroup&gt;
    &lt;Content Include="Watermark.png"&gt;
      &lt;CopyToOutputDirectory&gt;PreserveNewest&lt;/CopyToOutputDirectory&gt;
    &lt;/Content&gt;
  &lt;/ItemGroup&gt;
&lt;/Project&gt;
</code></pre>
Here are the changes we've made:
<ul>
 	<li>We have changed the <strong>Sdk</strong> name in the <strong>Project</strong> entry from <strong>Microsoft.NET.Sdk.Wpf</strong> to <strong>Microsoft.NET.Sdk.WindowsDesktop</strong>. Now, in fact, the SDK is unique regardless of the platform's choice (WPF or Windows Forms).</li>
 	<li>We have added the <strong>UseWpf</strong> entry and we have set it to <strong>true</strong>. This is the new approach to specify the application's platform, in this case WPF.</li>
 	<li>We have removed all the previous entries inside the <strong>ItemGroup</strong> section, like <strong>ApplicationDefinition</strong> or <strong>Page</strong>. The only exception is for the <strong>Watermark.png</strong> file, since we need to customize the build action and to set it as <strong>Content</strong>.</li>
</ul>
That's it. Now try to reload the project in Visual Studio and it should be opened without problems. The application should compile and run just fine, even if with the same limitations we have seen <a href="https://blogs.msdn.microsoft.com/appconsult/2018/10/29/move-your-first-steps-with-net-core-3-0-for-desktop-development/">in the previous post</a> (like some debugging issues).

The new build of .NET Core 3.0 has brought also an improvement in the compilation chain. If you remember, <a href="https://blogs.msdn.microsoft.com/appconsult/2018/10/29/move-your-first-steps-with-net-core-3-0-for-desktop-development/">in the previous post</a> we were forced to build and run the project using MSBuild and Visual Studio. Trying to do the same using the .NET Core CLI was resulting in a compilation error.

Now, instead, we can compile and run our project also using the command line interface. Open a command prompt and move to the folder which contains your project, then execute the following command:
<pre><code class="language-powershell">dotnet build
</code></pre>
Unlike the last time, the operation will complete successfully.

<img alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/Update-your-Windows-desktop-app-to-.NET-Core-3.0.100-preview-009754build.png" />

And if you type:
<pre><code class="language-powershell">dotnet run
</code></pre>
your WPF application will start just fine.
<h3 id="wrapping-up">Wrapping up</h3>
In this post we have seen how we can migrate our WPF .NET Core 3.0 project to use the latest daily build, which introduced some breaking changes in the project's definition.
Remember that .NET Core 3.0 is still experimental. Starting to migrate your WPF and Windows Forms applications can be a good exercise to plan the future of your desktop application, but it shouldn't be used to move applications used in production.

You can find the updated code <a href="https://github.com/Microsoft/Windows-AppConsult-Samples-DesktopBridge/tree/master/Blog-WpfNetCore/ExpenseItNetCore">on GitHub</a>.

Happy coding!]]></content:encoded>
    </item>
    <item>
      <title>🔙 Back to the future now ⏩: Execute your Azure ☁ trained Machine Learning 🧪 models on HoloLens!</title>
      <link>https://docs.microsoft.com/archive/blogs/appconsult/23535</link>
      <pubDate>Thu, 15 Nov 2018 00:48:12 GMT</pubDate>
      <dc:creator><![CDATA[Sebastien Bovo]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/appconsult/?p=23535</guid>
      <description><![CDATA[Artificial Intelligence is everywhere and powered by the Cloud. We can now go even further and bring...]]></description>
      <content:encoded><![CDATA[<strong>Artificial Intelligence</strong> is everywhere and powered by the Cloud. We can now go even further and bring AI to <strong>HoloLens</strong> gracefully thanks to <a target="_blank" href="https://docs.microsoft.com/fr-fr/windows/ai/" rel="noopener">Windows Machine Learning</a> and Windows 10!

Let's go and make it real with a full working and reusable sample. Yes! <em>Reusable</em> because, you can train your own Custom Vision model and run it using this sample ♻ without any code modification.
<blockquote><strong>Note:</strong> My colleagues <a target="_blank" href="https://twitter.com/meulta" rel="noopener">Etienne Margraff</a> and <a target="_blank" href="https://twitter.com/qmatteoq" rel="noopener">Matteo Pagani</a> already gave lot of details and useful explanations about Windows ML. Feel free to refer to their good blog posts in the <em>References</em> section at the end of this article.</blockquote>
The idea is the following:
<ul>
 	<li>We use a <a target="_blank" href="https://www.customvision.ai/" rel="noopener">Custom Vision</a> model that we train in Azure to recognize objects/situations/machines/persons/etc. (In fact, almost what you want 😏).</li>
 	<li>We export this model as a ONNX 1.2 file.</li>
 	<li>We develop a HoloLens app which gets video frames in continue.</li>
</ul>
<strong>⏩✔ The app uses the model locally for evaluation and predicts what is in front of the user wearing the HoloLens!</strong>

--
<h2 id="step-1-train--a-machine-learning-model-in-azure">Step 1. Train 🥼 a Machine Learning Model in Azure</h2>
<h3 id="-create-the-custom-vision-model">🆕 Create the Custom Vision model</h3>
Connect to <a href="https://www.customvision.ai/">https://www.customvision.ai/</a> and click on the <strong>NEW PROJECT</strong> button to create a new Custom Vision project.

<img alt="Create a new Custom Vision project button" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningCreateACustomVisionProject.png" />

Fill in the details:
<ul>
 	<li>A <em>name</em> and a <em>description</em>.</li>
</ul>
<img alt="Name and description fields" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningNameDescription.png" />
<ul>
 	<li>Choose if you want to use the <strong>Limited Trial</strong> mode or use/create an <strong>Azure resource group</strong> for hosting the Custom Vision service in Azure.</li>
</ul>
<img alt="Resource group or Trial combobox" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningResourceGroupOrTrial.png" />
<blockquote><strong>Note:</strong> Choosing the resource group option makes sense if you want to use your Custom Vision model everywhere. I mean: it uses Azure to provide a REST endpoint API that can be used in mobile apps or on computers running Windows, MacOS, Linux or even in Web sites. And all this, without to worry about the technology used.

For evaluating the model locally on the HoloLens, you can go for the Limited Trial as we will not use the Azure Custom Vision endpoint. Please note that, later, if you want to instantiate an Azure resource for this Custom Vision model's evaluation on other platforms, you can do it by clicking on the <em>gear</em> on the top right of the page:

<img alt="Settings for the Custom Vision app" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningSettingsForTheCustomVisionApp.png" />

Then, at the bottom of the details' page for your model, you create the Azure resource by clicking on the <strong>Move To Azure</strong> button:

<img alt="Move to Azure button" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningMoveToAzureOption.png" /></blockquote>
So, let's go back to our model creation:
<ul>
 	<li>Choose <strong>Classification</strong> for the project type. That means that we would like to tag the whole image.</li>
</ul>
<img alt="Project Type classification" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningClassificationForProjectType.png" />
<blockquote><strong>Note:</strong> For your information, <strong>Object Detection</strong> finds also the location of the object within an image.</blockquote>
<ul>
 	<li>Go for <strong>Multilabel (Multiple tags per image)</strong> as we would like to not be blocked to use only one tag. As an example: The image can contain a machine factory B214 type 2 and another machine whom id is A78 Alpha2. Tags applied to the image will be "B214 type 2" and "A78 Alpha2".</li>
</ul>
<img alt="Multilabel Classification type radio button" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningClassificationType.png" />
<ul>
 	<li>Lastly, but may be the most important, ⚠ take <strong>General (compact)</strong> ⚠. Choosing a <strong>compact</strong> model is mandatory to be able to use it with Windows ML on HoloLens or in a Windows 10 UWP app.</li>
</ul>
<img alt="General compact model" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningGeneralCompact.png" />

🆗 We are all set for the creation!
<h3 id="-train-the-model">⚗ Train the model</h3>
To do so, the steps are straight forward:
<ol>
 	<li>Just upload photos using the <strong>Add images</strong> button.</li>
</ol>
<img alt="Add images to train the model" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningAddImageToTrain.png" />
<ol start="2">
 	<li>Give one or more tags to the images to upload.</li>
</ol>
<img alt="Add tags to image during the upload" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningAddTagToPhotos.png" />

At any time, you can review, add or change the tags to the images.
<img alt="Show the tags for images" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningShowTags.png" />

When you are done, click on the <strong>Train</strong> button.
<img alt="Green train button" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningTrainButton.png" />

For more details, feel free to read <a target="_blank" href="https://docs.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/test-your-model" rel="noopener">Test and retrain a model with Custom Vision Service</a>.

Here are some explanations about the results we get:
<ol>
 	<li>You can change the <strong>Probability Threshold</strong> for a prediction to be valid. For example: 85% means that any predictions whom score &lt; 85% will not be considered as a valid prediction.</li>
 	<li><strong>Precision</strong> = Gives you the % of correct predictions. For example: For <em>Benoit</em>, we have 7 tagged pictures and the model's evaluation predicted this tag for all 7 pictures (so 100%).</li>
 	<li><strong>Recall</strong> = Gives you the % of found tags. For example: For <em>Sebastien</em>, we have 12 tagged pictures and the model was able to predict this tag for 91,7% of the pictures (11 pictures).
<img alt="Train results pages with Precision and Recall" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningTrainResults.png" /></li>
</ol>
<h2 id="step-2-export--the-model-as-onnx-12">Step 2. Export 📦 the model as ONNX 1.2</h2>
Again, this steps is easy and well documented by the <a target="_blank" href="https://blogs.msdn.microsoft.com/appconsult/2018/11/06/upgrade-your-winml-application-to-the-latest-bits/" rel="noopener">article written by Matteo</a>: Just click on the <strong>Export</strong> button.
<img alt="Export button image" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningExportButton.png" />

⚠ Be sure to choose the <strong>ONNX 1.2 format</strong> ⚠

<img alt="ONNX 1.2 file format" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningONNX1.2Format.png" />

You see there that your app will run on Windows starting at the <strong>Build 17738</strong> which means <strong>Windows version 1809</strong> or above.
<blockquote><strong>Note:</strong> As I write this article, the Windows version 1809 can be installed on HoloLens by participating to the Windows Insider Preview Slow ring.</blockquote>
<h2 id="step-3-create-a-unity-app--for-hololens-that-captures-the-camera--frames">Step 3. Create a Unity App 🕹 for HoloLens that captures the camera 🎥 frames</h2>
<h3 id="project-setup-">Project setup 📏</h3>
I worked with the following versions:
<ul>
 	<li>Windows version 1809 for the PC and HoloLens</li>
 	<li>Visual Studio 2017 version 15.9.0</li>
 	<li>Windows SDK version 10.0.17763.0</li>
 	<li>Unity 2017.4.13f1</li>
</ul>
<blockquote><strong>Note:</strong> You can skip this part if you are familiar with Unity and Mixed Reality.

If not, please refer to <a target="_blank" href="https://blogs.msdn.microsoft.com/appconsult/2018/06/14/create-a-windows-mixed-reality-app-from-0-the-unity-project/" rel="noopener">Create a Windows Mixed Reality App from 0 – The Unity project</a>.</blockquote>
The Unity project has to be configured for Windows Mixed Reality:
<ul>
 	<li><strong>File</strong> menu / <strong>Build Settings</strong> ➡ <strong>Universal Windows Platform</strong> selected as the Build platform</li>
 	<li><strong>Edit</strong> menu / <strong>Project Settings</strong> / <strong>Player</strong> ➡ <strong>Virtual Reality Supported</strong> checked</li>
 	<li><strong>Edit</strong> menu / <strong>Project Settings</strong> / <strong>Player</strong> ➡ <strong>Other Settings</strong> / <strong>.NET</strong> as Scripting Backend. Please also use the <strong>Experimental (.NET 4.6 Equivalent)</strong> for the Scripting Runtime Version.</li>
</ul>
<h3 id="technical-piping--for-being-able-to-give-update-to-the-user">Technical piping 🔩 for being able to give update to the user</h3>
The purpose is to be able to display a text message in front of the user from any code within the app. We first add a startup script to the scene:

From the <strong>GameObject</strong> menu <strong>Create an empty object</strong> and name it "ScriptManager".

<img alt="Create an empty game object" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningCreateEmptyGameObject.png" />

Select the <strong>ScriptManager</strong> object in the <strong>Hierarchy</strong> and click on <strong>Add Componennt</strong> / <strong>new script</strong> and name it "UnityScanScene".

<img alt="Add Component" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningAddComponent.png" />
<img alt="StartUp script" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningStartUpScript.png" />

Double click on the <strong>UnityScanScene</strong> script to modify it in Visual Studio; Replace the existing code by the one below. Let me give you some details:
<ul>
 	<li>We use an interface <strong>IUnityScanScene</strong> with one unique public method <strong>ModifyOutputText</strong>.</li>
 	<li>The startup script we are modifying (UnityScanScene) implements this interface. The method <strong>ModifyOutputText</strong> just modifies a string.</li>
 	<li>The <strong>Update</strong> method of the script (UnityScanScene) is executed for each frame. We just modify the text of a 3D Text object based on the modified string.</li>
</ul>
All this "piping" is really useful for giving feedback to the user (text or other) from any code from any class within the project. You will see it in action later in this article.
<pre><code class="language-csharp">using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// &lt;summary&gt;
/// The Interface gives one method to implement. This method modifies the text to display in Unity
/// Any code can then call this method outside the Unity MonoBehavior object
/// &lt;/summary&gt;
public interface IUnityScanScene
{
	void ModifyOutputText(string newText);
}

public class UnityScanScene : MonoBehaviour, IUnityScanScene
{
	// Unity 3D Text object that contains 
	// the displayed TextMesh in the FOV
	public GameObject OutputText;
	// TextMesh object provided by the OutputText game object
	private TextMesh OutputTextMesh;
	// string to be affected to the TextMesh object
	private string OutputTextString = string.Empty;
	// Indicate if we have to Update the text displayed
	private bool OutputTextChanged = false;

	// Use this for initialization
	async void Start ()
	{
            OutputTextMesh = OutputText.GetComponent&lt;TextMesh&gt;();
            OutputTextMesh.text = string.Empty;

#if UNITY_WSA &amp;&amp; !UNITY_EDITOR // **RUNNING ON WINDOWS**
            // We will create our Camera scan engine here
#else                          // **RUNNING IN UNITY**
            ModifyOutputText("Sorry ;-( The app is not supported in the Unity player.");
#endif
	}

	/// &lt;summary&gt;
	/// Modify the text to be displayed in the FOV
	/// or/and in the debug traces
	/// + Indicate that we have to update the text to display
	/// &lt;/summary&gt;
	/// &lt;param name="newText"&gt;new string value to display&lt;/param&gt;
	public void ModifyOutputText(string newText)
	{
		OutputTextString = newText;
		OutputTextChanged = true;
	}

	// Update is called once per frame
	void Update ()
	{
		if (OutputTextChanged)
		{
			OutputTextMesh.text = OutputTextString;
			OutputTextChanged = false;
		}
	}

}
</code></pre>
<h3 id="display--some-text-in-the-field-of-view">Display 📺 some text in the field of view</h3>
Add a <strong>3D Text</strong> object as a child of the camera; Name it "OutputText"; Change its properties as shown below. The purpose is to see some text at a nice distance and in the center of the field of view.

<img alt="3D Text object as a child of the camera" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearning3DTextObjectAsChildOfCamera.png" />

To be able to update this <strong>3D Text</strong> object, drag &amp; drop the <strong>OutputText</strong> object from the hierarchy to the <strong>Output text</strong> property of the <strong>ScriptManager</strong> object. This action gives to the UnityScanScene class the reference to the 3D Text to modify.

<img alt="Drag and drop OutputText to Output Text property" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningDragAndDropOutputText.png" />

To do a small verification, you can press the Unity PLAY button.
<img alt="Play in Unity displays the message" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningPlayInUnity.png" />
<h3 id="camera-scan-engine--">Camera scan engine ⚙ 🎥</h3>
Ok, it is now time to take care of the camera:

Add a new folder in the Assets named "UWP" in order to place within it only C# code that runs on Windows.

Add a script named "ScanEngine". Here is the Assets folder look:

<img alt="Assets folder look" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningAssetsFolderLook.png" />

Replace the content of the ScanEngine.cs file with the code below.
<pre><code class="language-csharp">#if UNITY_WSA &amp;&amp; !UNITY_EDITOR
using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.Media.Capture;
using Windows.Media.Capture.Frames;
using Windows.Media.MediaProperties;

public class ScanEngine
{
    public TimeSpan PredictionFrequency = TimeSpan.FromMilliseconds(400);

    private MediaCapture CameraCapture;
    private MediaFrameReader CameraFrameReader;

    private Int64 FramesCaptured;

    IUnityScanScene UnityApp;


    public ScanEngine()
    { 
    }

    public async Task Inititalize(IUnityScanScene unityApp)
    {
        UnityApp = unityApp;

        await InitializeCameraCapture();
        await InitializeCameraFrameReader();
    }

    private async Task InitializeCameraCapture()
    {
        CameraCapture = new MediaCapture();
        MediaCaptureInitializationSettings settings = new MediaCaptureInitializationSettings();
        settings.StreamingCaptureMode = StreamingCaptureMode.Video;
        await CameraCapture.InitializeAsync(settings);
    }

    private async Task InitializeCameraFrameReader()
    {
        var frameSourceGroups = await MediaFrameSourceGroup.FindAllAsync(); 
        MediaFrameSourceGroup selectedGroup = null;
        MediaFrameSourceInfo colorSourceInfo = null;

        foreach (var sourceGroup in frameSourceGroups)
        {
            foreach (var sourceInfo in sourceGroup.SourceInfos)
            {
                if (sourceInfo.MediaStreamType == MediaStreamType.VideoPreview
                    &amp;&amp; sourceInfo.SourceKind == MediaFrameSourceKind.Color)
                {
                    colorSourceInfo = sourceInfo;
                    break;
                }
            }
            if (colorSourceInfo != null)
            {
                selectedGroup = sourceGroup;
                break;
            }
        }

        var colorFrameSource = CameraCapture.FrameSources[colorSourceInfo.Id];
        var preferredFormat = colorFrameSource.SupportedFormats.Where(format =&gt;
        {
            return format.Subtype == MediaEncodingSubtypes.Argb32;

        }).FirstOrDefault();

        CameraFrameReader = await CameraCapture.CreateFrameReaderAsync(colorFrameSource);
        await CameraFrameReader.StartAsync();
    }

    public void StartPullCameraFrames()
    {
        Task.Run(async () =&gt;
        {
            for (; ; ) // Forever = While the app runs
            {
                FramesCaptured++;
                await Task.Delay(PredictionFrequency);
                using (var frameReference = CameraFrameReader.TryAcquireLatestFrame())
                using (var videoFrame = frameReference?.VideoMediaFrame?.GetVideoFrame())
                {

                    if (videoFrame == null)
                    {
                        continue; //ignoring frame
                    }

                    if (videoFrame.Direct3DSurface == null)
                    {
                        videoFrame.Dispose();
                        continue; //ignoring frame
                    }

                    try
                    {
                        // HERE, We will evaluate the model
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine(ex.Message);
                    }
                    finally
                    {
                    }
                }

            }

        });
    }

}
#endif
</code></pre>
The UnityScanScene.cs script will use this class this way:
<pre><code class="language-csharp">	async void Start ()
	{
        OutputTextMesh = OutputText.GetComponent&lt;TextMesh&gt;();
        OutputTextMesh.text = string.Empty;

#if UNITY_WSA &amp;&amp; !UNITY_EDITOR // RUNNING ON WINDOWS**
        CameraScanEngine = new ScanEngine();       // &lt;-- 1
        await CameraScanEngine.Inititalize(this);  // &lt;-- 2
        CameraScanEngine.StartPullCameraFrames();  // &lt;-- 3
#else                          // RUNNING IN UNITY**
        ModifyOutputText("Sorry ;-( The app is not supported in the Unity player.");
#endif
	}
</code></pre>
❗ It is now time to modify the UnityScanScene.cs accordingly in order to have the code above for the <code>Start</code> method.

I have to give you some explanations 😅.
<ol>
 	<li>We create our Camera helper <strong>CameraScanEngine</strong> from the <strong>ScanEngine</strong> class.</li>
 	<li>Calling <code>CameraScanEngine.Inititalize(this)</code> in the UnityScanScene.cs startup script gives the ability to call the public <strong>ModifyOutputText</strong> method of the IUnityScanScene interface from the CameraScanEngine object. Here is the proof:</li>
</ol>
<img alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningCallingModifyTextFromAnotherClass.png" />

Also, it really initializes the HoloLens camera for being able to capture the video frames. Under the hood, we use the <code>MediaCapture</code> class.
<ol start="3">
 	<li>The HoloLens camera is initialized and we can get the frames. The <code>StartPullCameraFrames()</code> call initiates an infinite loop for pulling for frames. We will replace the line <code>// HERE, We will evaluate the model</code> by the code for evaluating the model on the frame later.</li>
</ol>
For this camera helper code, I thank Etienne Margraff with his article (<a target="_blank" href="https://meulta.com/en/2018/05/18/experimenting-with-windows-machine-learning-and-mixed-reality/" rel="noopener">Preview API - Experimenting with Windows Machine Learning and Mixed Reality</a> - Feel free to read it for further details about this code).
<h2 id="step-4-integrate--the-model-in-the-app">Step 4. Integrate ⤵ the model in the app</h2>
<h3 id="adding-the-file-in-the-package-">Adding the file in the package 📥</h3>
Back to step 2, we saved the model as a ONNX 1.2 file on the disk. It is now time to add it to the Unity App:

Just name the model "ONNXModel.onnx" and drag &amp; drop it to a new folder named <strong>StreamingAssets</strong> in the <strong>Assets</strong> folder.

<img alt="StreamingAssets folder" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningStreamingAssets.png" />

This <a target="_blank" href="https://docs.unity3d.com/Manual/StreamingAssets.html" rel="noopener">StreamingAssets folder</a> is special for Unity: it will be copied to the <strong>Data</strong> folder inside the UWP application that will be deployed on the HoloLens. This way, we will be able to load the file by code from the package installation folder.
<blockquote><strong>Note:</strong> It is also possible to add the ONNX file directly to the resulting C# UWP application. The Unity way of adding it is not mandatory.</blockquote>
<h3 id="add-a-wrapper-class--for-the-model">Add a wrapper class 🔧 for the model</h3>
This was the tricky part of the job and the one that changed from the Preview APIs and the ones released. The long story is well detailed by Matteo Pagani in the two referenced articles (<a target="_blank" href="https://blogs.msdn.microsoft.com/appconsult/2018/05/23/add-a-bit-of-machine-learning-to-your-windows-application-thanks-to-winml/" rel="noopener">Preview API - Add a bit of machine learning to your Windows application thanks to WinML</a> and <a target="_blank" href="https://blogs.msdn.microsoft.com/appconsult/2018/11/06/upgrade-your-winml-application-to-the-latest-bits/" rel="noopener">Upgrade your WinML application to the latest bits</a>).

For today, long story short: we do not use the generated class by Visual Studio for our model wrapper but the following one below. This class is 'generic' and works for your own custom vision trained model.

Here are the steps:

In Unity, add a new script named 'ONNXModel' in the <strong>Assets/UWP</strong> folder. This is our 'generic' model wrapper class.

<img alt="ONNX Model C# Helper" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningONNXModelCSCode.png" />

Double click on <strong>ONNXModel.cs</strong> and replace the content of the script by the following code:
<pre><code class="language-csharp">#if UNITY_WSA &amp;&amp; !UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.AI.MachineLearning;
using Windows.Media;
using Windows.Storage;

public sealed class ONNXModelInput
{
    public VideoFrame Data { get; set; }
}

public sealed class ONNXModelOutput
{
    public TensorString ClassLabel = TensorString.Create(new long[] { 1, 1 });
    public IList&lt;IDictionary&lt;string, float&gt;&gt; Loss = new List&lt;IDictionary&lt;string, float&gt;&gt;();
}

/// &lt;summary&gt;
/// These classes ONNXModel, ONNXModelInput, ONNXModelOutput never change
/// We just load a different custom model
/// 
/// In order to evalutate a model:
/// 1. Call the static method ONNXModel.CreateOnnxModel(&lt;&lt;MyModelStorageFile&gt;&gt;)
/// 2. Call EvaluateAsync method on the created Model before
/// &lt;/summary&gt;
public sealed class ONNXModel
{
    private LearningModel _learningModel = null;
    private LearningModelSession _session;

    public static async Task&lt;ONNXModel&gt; CreateOnnxModel(StorageFile file)
    {
        LearningModel learningModel = null;

        try
        {
            learningModel = await LearningModel.LoadFromStorageFileAsync(file);
        }
        catch (Exception e)
        {
            var exceptionStr = e.ToString();
            Debug.WriteLine(exceptionStr);
            throw e;
        }
        return new ONNXModel()
        {
            _learningModel = learningModel,
            _session = new LearningModelSession(learningModel)
        };
    }

    public async Task&lt;ONNXModelOutput&gt; EvaluateAsync(ONNXModelInput input)
    {
        var output = new ONNXModelOutput();
        var binding = new LearningModelBinding(_session);
        binding.Bind("data", input.Data);
        binding.Bind("classLabel", output.ClassLabel);
        binding.Bind("loss", output.Loss);
        LearningModelEvaluationResult evalResult = await _session.EvaluateAsync(binding, "0");

        return output;
    }
}
#endif
</code></pre>
<blockquote><strong>Note:</strong> All code dedicated to UWP is surrounded by <code>#if UNITY_WSA &amp;&amp; !UNITY_EDITOR</code>. It allows us to be sure to run this code only on Windows.</blockquote>
The <code>CreateOnnxModel()</code> static method is in charge of loading the file. The <code>EvaluateAsync()</code> performs the model' evaluation.

Again, this code will not change if you create your own custom vision model (Classification / Multilabel / General Compact).

Let's add now a 'high level' model helper in order to put the glue between the captured frame and the model evaluation.
<h3 id="load--and-evaluate--the-model-for-each-frame">Load 📤 and evaluate ⚙ the model for each frame</h3>
In Unity, add a new script named 'ONNXModelHelper' in the <strong>Assets/UWP</strong> folder.

<img alt="ONNX Model helper class" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningONNXModelHelper.png" />

Use this code:
<pre><code class="language-csharp">#if UNITY_WSA &amp;&amp; !UNITY_EDITOR
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Media;
using Windows.Storage;

public class ONNXModelHelper
{
    private ONNXModel Model = null;
    private string ModelFilename = "ONNXModel.onnx";
    private Stopwatch TimeRecorder = new Stopwatch();
    private IUnityScanScene UnityApp;

    public ONNXModelHelper()
    {
        UnityApp = null;
    }

    public ONNXModelHelper(IUnityScanScene unityApp)
    {
        UnityApp = unityApp;
    }

    public async Task LoadModelAsync() // &lt;-- 1
    {
        ModifyText($"Loading {ModelFilename}... Patience");

        try
        {
            TimeRecorder = Stopwatch.StartNew();

            var modelFile = await StorageFile.GetFileFromApplicationUriAsync(
                new Uri($"ms-appx:///Data/StreamingAssets/{ModelFilename}"));
            Model = await ONNXModel.CreateOnnxModel(modelFile);

            TimeRecorder.Stop();
            ModifyText($"Loaded {ModelFilename}: Elapsed time: {TimeRecorder.ElapsedMilliseconds} ms");
        }
        catch (Exception ex)
        {
            ModifyText($"error: {ex.Message}");
            Model = null;
        }
    }

    public async Task EvaluateVideoFrameAsync(VideoFrame frame) // &lt;-- 2
    {
        if (frame != null)
        {
            try
            {
                TimeRecorder.Restart();
                ONNXModelInput inputData = new ONNXModelInput();
                inputData.Data = frame;
                var output = await Model.EvaluateAsync(inputData).ConfigureAwait(false); // &lt;-- 3

                var product = output.ClassLabel.GetAsVectorView()[0]; // &lt;-- 4 
                var loss = output.Loss[0][product]; // &lt;-- 5
                TimeRecorder.Stop();

                var lossStr = string.Join(product, " " + (loss * 100.0f).ToString("#0.00") + "%");
                string message = $"({DateTime.Now.Hour}:{DateTime.Now.Minute}:{DateTime.Now.Second})" +
                    $" Evaluation took {TimeRecorder.ElapsedMilliseconds}ms\n";

                string prediction = $"Prediction: {product} {lossStr}";
                if (loss &gt; 0.5f)
                {
                    message += prediction;
                }

                message = message.Replace("\\n", "\n");

                ModifyText(message); // &lt;-- 6
            }
            catch (Exception ex)
            {
                var err_message = $"error: {ex.Message}";
                ModifyText(err_message);
            }
        }
    }

    private void ModifyText(string text)
    {
        System.Diagnostics.Debug.WriteLine(text);
        if (UnityApp != null)
        {
            UnityApp.ModifyOutputText(text);
        }
    }
}
#endif
</code></pre>
Explanations 📚:
<ol>
 	<li>The helper method effectively loads the ONNX Model using <code>StorageFile.GetFileFromApplicationUriAsync()</code>.</li>
 	<li><code>EvaluateVideoFrameAsync()</code> is called by the ScanEngine for every frame.</li>
</ol>
So, there is an action for you 😅: Please replace <code>// HERE, We will evaluate the model</code> by

<code>await ModelHelper.EvaluateVideoFrameAsync(videoFrame).ConfigureAwait(false);</code>.
<ol start="3">
 	<li><code>Model.EvaluateAsync()</code> calls the wrapper method for the model's evaluation. We get the result in the <strong>output</strong> object.</li>
 	<li><code>var product = output.ClassLabel.GetAsVectorView()[0]</code> is the name of the most scored prediction.</li>
 	<li><code>output.Loss[0][product]</code> is the score of this prediction.</li>
 	<li>We call the private method <code>ModifyText</code> to modify the text to display in HoloLens thanks to <code>UnityApp.ModifyOutputText()</code>. The display is about giving the predication and the score.</li>
</ol>
We should have all set 🤯😪🥳! You just have to build the Unity app; It generates the C# UWP Solution that you can compile in <strong>MASTER x86</strong> and deploy to you HoloLens.

Here is what you can get 😂

<em>Good prediction for <a target="_blank" href="https://twitter.com/benoitlp" rel="noopener">Benoit</a>!</em>

<img alt="Prediction = Benoit" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningBenoitMini.png" />

<em>A 'low' prediction for <a target="_blank" href="https://twitter.com/Flo_Plsr" rel="noopener">Florent</a> (who is not me 😉 and who was not part of the Model's training)</em>

<img alt="Prediction = Sebastien with a low score" src="https://msdnshared.blob.core.windows.net/media/2018/11/HoloLensMachineLearningFlorentMini.png" />
<blockquote><strong>Disclaimer ⚖:</strong> Again, this model was only trained with less than 20 pictures which is a way too low to pretend having a correct model for prediction. But you have the idea!</blockquote>
All updated and optimized source code is on GitHub - <a target="_blank" href="https://github.com/Microsoft/Windows-AppConsult-Samples-MixedReality/tree/master/HoloLensWinML" rel="noopener">https://github.com/Microsoft/Windows-AppConsult-Samples-MixedReality/tree/master/HoloLensWinML</a>.
<h2 id="conclusion">Conclusion</h2>
Talking about performance: The app deployed on HoloLens loads the ~3Mb ONNX model in about 300ms. The model's evaluation is done in average in 250 to 400ms. So right now, we have a minimum of 2 frames analyzed by second; Based on the fact that only the HoloLens processor does the job, it is pretty good: We can imagine scenarios in factories for safety or monitoring, in maintenance or diagnostics operations or even in medical assistance.

The future? Who knows? <a target="_blank" href="https://twitter.com/akipman" rel="noopener">Alex Kipman</a> and his team for sure 😉

What I can say is that <a target="_blank" href="https://www.microsoft.com/en-us/research/blog/second-version-hololens-hpu-will-incorporate-ai-coprocessor-implementing-dnns/" rel="noopener">work is in progress a new Holographic Processing Unit (HPU) for HoloLens</a>:
<blockquote>...the second version of the HPU, currently under development, will incorporate an AI coprocessor to natively and flexibly implement DNNs.</blockquote>
DNN stands for <strong>Deep Neural Networks</strong> which is what we are using 🎉. We can expect that this future AI chip would be dedicated for this kind of work and performance would be decoupled 💹!

Last word of this article is from the link above:
<blockquote>
<h2 id="mixed-reality-and-artificial-intelligence-represent-the-future-of-computing-and-were-excited-to-be-advancing-this-frontier">Mixed reality and artificial intelligence represent the future of computing, and we’re excited to be advancing this frontier.</h2>
</blockquote>
Bye,

<a target="_blank" href="https://twitter.com/sbovo" rel="noopener">@sbovo</a> for the 💻 🎮 Windows AppConsult team.

--
<h2 id="credits">Credits</h2>
I would like to thank
<ul>
 	<li><a target="_blank" href="https://twitter.com/meulta" rel="noopener">Etienne Margraff</a> for the first article on this topic on HoloLens/</li>
 	<li><a target="_blank" href="https://twitter.com/qmatteoq" rel="noopener">Matteo Pagani</a> for his articles and reviewing this one.</li>
 	<li><a target="_blank" href="https://twitter.com/benoitlp" rel="noopener">Benoit</a> my co-presenter on Mixed Reality events</li>
 	<li><a target="_blank" href="https://twitter.com/Flo_Plsr" rel="noopener">Florent</a> for his support</li>
</ul>
<h2 id="references">References</h2>
<ul>
 	<li>All source code - <a href="https://github.com/Microsoft/Windows-AppConsult-Samples-MixedReality/tree/master/HoloLensWinML">https://github.com/Microsoft/Windows-AppConsult-Samples-MixedReality/tree/master/HoloLensWinML</a></li>
 	<li>Custom Vision - <a href="https://www.customvision.ai/">https://www.customvision.ai/</a></li>
 	<li>Windows Machine Learning - <a href="https://docs.microsoft.com/fr-fr/windows/ai/">https://docs.microsoft.com/fr-fr/windows/ai/</a></li>
 	<li>Second version of HoloLens HPU will incorporate AI coprocessor for implementing DNNs - <a href="https://www.microsoft.com/en-us/research/blog/second-version-hololens-hpu-will-incorporate-ai-coprocessor-implementing-dnns/">https://www.microsoft.com/en-us/research/blog/second-version-hololens-hpu-will-incorporate-ai-coprocessor-implementing-dnns/</a></li>
 	<li>Open Neural Network Exchange Github - <a href="https://github.com/onnx/onnx">https://github.com/onnx/onnx</a></li>
 	<li>ONNX Format initiative - <a href="https://onnx.ai/">https://onnx.ai/</a></li>
 	<li>(Preview API) Experimenting with Windows Machine Learning and Mixed Reality - <a href="https://meulta.com/en/2018/05/18/experimenting-with-windows-machine-learning-and-mixed-reality/">https://meulta.com/en/2018/05/18/experimenting-with-windows-machine-learning-and-mixed-reality/</a></li>
 	<li>(Preview API) Add a bit of machine learning to your Windows application thanks to WinML - <a href="https://blogs.msdn.microsoft.com/appconsult/2018/05/23/add-a-bit-of-machine-learning-to-your-windows-application-thanks-to-winml/">https://blogs.msdn.microsoft.com/appconsult/2018/05/23/add-a-bit-of-machine-learning-to-your-windows-application-thanks-to-winml/</a></li>
 	<li>Upgrade your WinML application to the latest bits - <a href="https://blogs.msdn.microsoft.com/appconsult/2018/11/06/upgrade-your-winml-application-to-the-latest-bits/">https://blogs.msdn.microsoft.com/appconsult/2018/11/06/upgrade-your-winml-application-to-the-latest-bits/</a></li>
 	<li>Integrate a model into your app with Windows ML - <a href="https://docs.microsoft.com/fr-fr/windows/ai/integrate-model">https://docs.microsoft.com/fr-fr/windows/ai/integrate-model</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>4 Cool things in Windows 10 version 1809</title>
      <link>https://docs.microsoft.com/archive/blogs/appconsult/3-cool-things-in-windows-10-version-1809</link>
      <pubDate>Mon, 12 Nov 2018 17:00:21 GMT</pubDate>
      <dc:creator><![CDATA[Luís Henrique Demetrio]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/appconsult/?p=23165</guid>
      <description><![CDATA[I wrote this post to share some of the great features available on Windows 10 version 1809 that I...]]></description>
      <content:encoded><![CDATA[I wrote this post to share some of the great features available on Windows 10 version 1809 that I really liked.

&nbsp;

<a href="https://msdnshared.blob.core.windows.net/media/2018/11/winver.png"><img width="415" height="376" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/winver.png" /></a>

&nbsp;
<h3>Dark Mode in File Explorer</h3>
The option to enable the dark mode is available under <strong>Settings</strong> &gt; <strong>Personalization</strong> &gt; <strong>Colors</strong>.

It is possible switch between <strong>Light</strong> and <strong>Dark</strong> app mode.

&nbsp;

<img width="600" height="400" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/light.png" />

&nbsp;

After switching between the App modes, any App or Windows UI that support theme will be updated including <strong>File Explorer</strong>.
&nbsp;
<a href="https://msdnshared.blob.core.windows.net/media/2018/11/dark-explorer.png"><img width="600" height="400" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/dark-explorer-1024x586.png" /></a>

&nbsp;
<h3>Notepad enhancements</h3>
You can zoom in to text now on Notepad by pressing CTRL + or CTRL -. That is pretty useful during presentations.

&nbsp;

<img width="600" height="400" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/notepad-zoom.png" />

&nbsp;

Finally wrap-around to find or replace is now available in Notepad too.

&nbsp;

<img width="600" height="400" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/notepad3.png" />

&nbsp;

Notepad now allows you to search on Bing by selecting the text and pressing CTRL+E. That simplifies a lot the cases when you need to copy a test and search for it on Internet.
&nbsp;
<img width="600" height="400" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/bing2.png" />

&nbsp;

F5 in Notepad inserts the current date time.
&nbsp;
<a href="https://msdnshared.blob.core.windows.net/media/2018/11/f5.jpg"><img width="604" height="430" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/f5-1024x728.jpg" /></a>
&nbsp;

<h3>The new clipboard</h3>
Pressing Windows Key + V you have access to the clipboard history. That is really cool and save a lot the time allowing us to get the copied content back from the historical clipboard.

You can also enable this functionality under <span>Settings &gt; System &gt; Clipboard.</span>

&nbsp;

<img width="400" height="500" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/notepad.png" />

&nbsp;

Observe that the clipboard also shows the images that were copied and gives you the option to pin the items to use all the time:

&nbsp;

<img width="405" height="507" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/clipboard.png" />

&nbsp;

In addition to the clipboard history, it is also possible to copy the content across the devices that have at least Windows 10 version 1809 version.

&nbsp;

The Windows + Shift + S, used to capture a screenshot, now displays a toast notification that open up the Snip &amp; Sketch App:
&nbsp;
<img width="600" height="400" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/notepad2.png" />

&nbsp;

If you click on the toast notification the Snip &amp; Sketch App is opened:
&nbsp;
<img width="600" height="400" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/snip-1024x796.png" />

&nbsp;
<h3>Registry autocomplete</h3>
Windows 10 1809 comes with an autocomplete function for the registry editor. That saves a lot of time to navigate to the hives.
&nbsp;
<a href="https://msdnshared.blob.core.windows.net/media/2018/11/registry.png"><img width="975" height="578" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/11/registry.png" /></a>
&nbsp;
This was an introduction to the new functionalities of Windows 10 version 1809 version.

&nbsp;

I hope you liked.

&nbsp;]]></content:encoded>
    </item>
  </channel>
</rss>