Windows 10 UWP 33 of N: Dot Net standard 2.0 with UWP app ( .Net Standard 2.0)

  • 206
  • 0
  • UAP
  • 2021-04-30

如何在UWP app上使用.Net standard 2.0 的Library

前言

在.Net standard進入到2.0之後很多缺少的API直接加入到了這個強大的set中!基本上只要是.net的 application (包含web app, desktop app, uwp, xamarin)都可以享受到.net standard 2.0所帶來的優勢!

 


使用 .net standard 2.0在 UWP的專案上有一個必要的限制! 也就是需要調整最低的Api support到 Fall creator update( offical 16299 SDK) 目前這算是會比較麻煩的問題點所在,畢竟在企業內部很有可能還是在 creator update 或是 anniversary update的Windows 10。

Demo 環境
Windows 10 FCU
Visual studio 2017 15.4.4
UWP develop environment + Fall creator update SDK ( build-16299 )

在UWP專案直接調整最低支援版本為FCU就可以了(當然目前也只有到FCU為Offical的最新SDK)

如果有安裝過 .net standard 2.0的SDK 就可以在新增專案的選單中看到大致如下的畫面

會是在所選取之語言之下的獨立選單(.Net Standard) 建立起來的Libarary基本上會使直接使用2.0的版本。

而這邊有趣的是在使用.Net Standard 2.0專案的時候只會看到有相依性的參考目錄,展開後就可以看到.NetStandard.Library在SDK之下。

接著就可以直接在UWP的參考中加入新增之.Net standard 2.0的專案了!但是....這邊依然有些Code是沒辦法在UWP上面跑的。請參考以下Link

https://github.com/dotnet/corefx/wiki/UWP-Compat

這邊有說明到有些 .Net Core的API 再目前設計把 UWP的Compatible設定為false,說真的有些好用的API都只能看看是否有upload到nuget了...

這邊有個很好用的API在Reflection裡面~Assembly.GetExecutingAssembly 可以抓到現在正在執行的app domain的assembly!也是要到16299之後的UWP專案才Support。


接著來介紹一下如何在.Net Standard中使用UWP的API,在.Net standard中支援所謂的Multiframework build的功能!也就是可以將Code寫在同一個專案之中,並且可以提供不同平台之實作。以HttpClient為例,在UWP 配上C#的時候可以使用如下

  1. Windows.Web.Http.HttpClient
  2. System.Net.Http.HttpClient

這邊可以參考 https://blogs.windows.com/buildingapps/2015/11/23/demystifying-httpclient-apis-in-the-universal-windows-platform/ 來說明。

簡單來說System.Net.Http的是適用所有.Net framework的實作,而使用Windows.Web.Http的是使用UWP的Framework的實作!所以使用 System開頭的Namespace可以使用在C#、VB的專案;而Windows的namespace可以使用在C#、VB、C++/CX、Javascript上!

這邊直接說明如何實作在.net standard上使用UWP的API!

  1. 建立.net standard 2.0的專案
  2. 在專案右鍵選擇編輯csproj
  3. 加入以下Code
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;uap10.0</TargetFrameworks>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
    <CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
    <NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
    <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
    <TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
    <TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
    <TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
    <TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
    <DefineConstants>$(DefineConstants);WINDOWS_UWP</DefineConstants>
    <LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
    <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  </PropertyGroup>

  <ItemGroup Condition=" '$(TargetFramework)' == 'uap10.0' ">
    <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.0.6" />
  </ItemGroup>

</Project>
需要將TargetFrame修改成TargetFrameworks、加入識別 uap10.0 的Framework宣告以及 .NetCore for UWP的Nuget package。

接下來直接來看C# code就可以使用 #if 的語法 來區分targetframework。

public Uri BuildRequestUriString(IDictionary<string, object> parameters = null)
        {
            var baseUriString = $"{BaseEndpointUriString}/{ApiVerb1}/{ApiVersion}/{ApiVerb2}";
            if (parameters == null)
            {
                System.Diagnostics.Debug.WriteLine(baseUriString);
                return new Uri(baseUriString);
            }
            else
            {
#if NETSTANDARD2_0
                var queryString = HttpUtility.ParseQueryString(string.Empty);
                foreach (var parameter in parameters)
                {
                    queryString[parameter.Key] = $"{parameter.Value}";
                }

                System.Diagnostics.Debug.WriteLine($"{baseUriString}?{queryString}");
                return new Uri($"{baseUriString}?{queryString}");
#elif WINDOWS_UWP
                foreach(var parameter in parameters)
                {
                    var index = parameters.ToList().IndexOf(parameter);
                    if (index == 0)
                    {
                        baseUriString+= $"?{parameter.Key}={parameter.Value}";
                    }
                    else
                    {
                        baseUriString+= $"&{parameter.Key}={parameter.Value}";
                    }
                }
                System.Diagnostics.Debug.WriteLine($"{baseUriString}");
                return new Uri($"{baseUriString}");
#endif
            }

.Net standard 2.0可以使用HttpUtility,但UWP並沒有提供該語法!

展開相依性之後可以看到如下圖片

總結

.Net standard 2.0 並不是Framework!所以基本上時做了.net 的大多的API,如果使用P/Invoke的部分沒有實作。因為.net  standard的用意是可以跨在各個.net standard所能支援的OS platform ( windows, xamarin ) 想對.net standard更多認識可以看以下兩個 channel 9 影片

https://channel9.msdn.com/Shows/XamarinShow/Episode-37-NET-Standard-Libraries-with-Immo-Landwerth

https://channel9.msdn.com/Shows/On-NET/NET-Standard-Deep-Dive?term=.net%20standard

 

***以上Code以及說明都有可能隨著Windows 10 的版本以及Visual Studio 版本有所調整!***

參考資料 Microsoft Docs, Github of dotnet standard ( https://github.com/dotnet/standard/issues/462 )

下次再分享Windows 10 的新技術拉~