nuits.jp blog

C#, Xamarin, WPFを中心に書いています。Microsoft MVP for Development Technologies。

Xamarin.Forms 2.3.4.247で"XamlCTask task failed unexpectedly"の回避方法

Xamarin.Formsではバージョンに関係なく、次のようなケースで元々"XamlCTask task failed unexpectedly"が発生する事がありました。

  • ソリューション内のプロジェクトによってXamarin.Formsのバージョンが違う
    (よくUWPのプロジェクトだけ更新に失敗したりします)
  • Xamarin.Formsのバージョンをアップデートして、packagesフォルダに古いバージョンが残っている

これらはそれぞれ次の対策で解決する事ができまいした。

  • ソリューション内のXamarin.Formsのバージョンを統一する
  • packagesフォルダから古いXamarin.Formsのフォルダを削除する

ただ、2.3.4.247のバージョンには固有の不具合があり、これらとは別原因で"XamlCTask task failed unexpectedly"が発生する事があります。
ただし個人的な経験から再現性は100%ではなく、ただし低くもないといった感じです。

これの対策方法ですが、つぎの二つの対処方法があります。

  1. Xamarin Forms 2.3.5-pre3より新しいバージョンにアップデートする
  2. Xamarin.Forms.targetsファイルを手で修正する

つぎのXamarin.Forms 2.4から対処されるでしょうが、Previewは入れられないという人も多いでしょう。
というわけで2.の方法を記載しておきます。

まずソリューションフォルダ下のpackagesフォルダ内の次のパスを開いてください。

Xamarin.Forms.2.3.4.270\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20

開くと、つぎのようなファイルがありますが、この中のXamarin.Forms.targetsをテキストエディタで開きます。

f:id:nuitsjp:20170830091334p:plain

ファイルの末尾のほうに、つぎのような記載があります。

<Target Name="XamlC">
    <XamlCTask
        Assembly = "$(IntermediateOutputPath)$(TargetFileName)"
        ReferencePath = "@(ReferencePath)"
        Verbosity = "2"
        OptimizeIL = "true"
        DebugSymbols = "$(DebugSymbols)"
        DebugType = "$(DebugType)"/>
</Target>

ここの「DebugType = “$(DebugType)"」を削除して次のように修正します。

<Target Name="XamlC">
    <XamlCTask
        Assembly = "$(IntermediateOutputPath)$(TargetFileName)"
        ReferencePath = "@(ReferencePath)"
        Verbosity = "2"
        OptimizeIL = "true"
        DebugSymbols = "$(DebugSymbols)"/>
</Target>

これで問題なくビルドできるはずです。

元々海外のフォーラムで対策を見つけたのですが、元情報がどこだったか完全に失念したため、リンク張るのは諦めます。。。

.NET FrameworkからHttpClientを利用している.NET Standardのプロジェクトを利用する

本エントリーはこれを書いている2017.08.26時点での話ですぐ状況は変わるかもしれませんのでご注意ください。

表題の件、普通にやるとなぜかつぎのようなエラーが出ます。

System.IO.FileNotFoundException
ファイルまたはアセンブリ ‘System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。

  • .NET Frameworkは4.7 & .NET Standard 2.0
  • .NET Frameworkは4.7 & .NET Standard 1.4
  • .NET Frameworkは4.6.2 & .NET Standard 1.4

どのパターンでもうまく動きません。 バージョンの不一致なのでしょうが、.NET 4.6.2も4.7もクラスライブラリプロジェクトを作成した直後からSystem.Net.Httpへのアセンブリ参照を持っていますが、バージョンは4.0.0.0です。

f:id:nuitsjp:20170826215713p:plain

f:id:nuitsjp:20170826215727p:plain

そして.NET Standard側は4.3.0です。

f:id:nuitsjp:20170826215819p:plain

4.0.0.0のアセンブリ参照を削除しても動作しませんし、4.1.0.0てどこからでたのやら?私にはまったく分かりませんが、とりあえず対処法はわかりました。

  1. .NET Frameworkプロジェクト作成直後にデフォルトで登録されているアセンブリ参照のSystem.Net.Httpを削除する
  2. NuGetからSystem.Net.Httpの4.3.0をインストールする

NuGet上のSystem.Net.Httpの最新は4.3.2ですが、これを入れると正しく動きませんので(.NET Standard側も4.3.2いれたら動くかも?未確認です)気を付けてください。

以上です。動いたけどいまいち釈然としませんね。。。

WPF&xUnitでテストコードからViewオブジェクトを生成する方法

例えば次のコードがあったとします。

[Fact]
public void WhenClosed()
{
    var window = new Window();
}

これを実行すると次のようなエラーがでます。

f:id:nuitsjp:20170825115056p:plain

UIはテストしないんじゃないの?と言われそうな気もしますが、Windowに貼り付ける汎用Behaviorをライブラリ化して使いまわしたいとかいう時に、Windowインスタンスが作れないがためにUnitTest書けないじゃんてな事が、稀に良くあります。

WPFなどはUI層はSingle Thread Apartment(STA)なスレッド上で実行される必要があります(この表現はもしかしたら正しくないかもしれません)。
よくUIはUIスレッドで実行しろと言われるあれです。

xUnitはマルチスレッドでテスト実行されますし、STAではもちろんありません。どうしましょう?こまったな。
と思っていたら、神がいました。

www.nuget.org

このパッケージをインストールして次のようにコードを修正します。

[WpfFact]
public void WhenClosed()
{
    var window = new Window();
}

FactAttributeからWpfFactAttributeに変更するだけでちゃんとSTAで動作させてくれます。凄い!どうなってるの!?

という訳で、今日はこれだけ。
いやあ、自力で何とかしようとしかけて、しないで済んで助かったなあ。

Xamarin(Formsもね)で.NET Standard 2.0なライブラリを利用する

Visual Studio 2017 Update 3がリリースされたことで、待望の.NET Standard 2.0が利用できるようになりました。
XamarinでもAndroidやiOSからは既に利用可能なようです。UWPは少々お待ちください?(少々っていつ?誰か教えて

さて、使うにはまずは.NET Standard 2.0を利用できる環境にする必要があります。
こちらの記事を参照してください。

www.nuits.jp

www.nuits.jp

手順としては簡単です。SS取り損ねたので文字だけでごめんなさい。
今回はXamarin.Formsを例にしていますが、Xamarin.Nativeから.NET Standardの共通ライブラリを利用する場合も大差ないはずです。

.NET Standard対応のPreview版のXamarin.Formsを使う

  1. PCLプロジェクトを削除する(AppとMainは取っとくと楽です)
  2. .NET Standard 2.0のクラスライブラリを作成する
  3. .NET Standard 2.0の.csprojを開いて編集する(以下を参照)
  4. AppとMainクラスを追加する
  5. AndroidとiOSのプロジェクトのXamarin.Formsのパッケージを2.3.5.256-pre6に上げる
  6. AndroidとiOSのプロジェクトから、.NET Standardライブラリのプロジェクトへ参照を追加する
  7. Androidの各種ライブラリをNuGetから最新版をダウンロードし、リビルドする
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Compile Update="**\*.xaml.cs" DependentUpon="%(Filename)" />
    <EmbeddedResource Include="**\*.xaml" SubType="Designer" Generator="MSBuild:UpdateDesignTimeXaml" />
  </ItemGroup>
  
  <ItemGroup>
    <PackageReference Include="Xamarin.Forms" Version="2.3.5.256-pre6" />
  </ItemGroup>
</Project>

これだけです。
簡単ですね。

いつからか不明ですが、こちらの問題は解消されていて、<None Remove=“***.xaml” />は不要になっている気がします?
https://bugzilla.xamarin.com/show_bug.cgi?id=55591

PCL版のStableなXamarin.Formsを使う

そんなに難しい事ないです。
.NET Standardのライブラリでは、PCLのライブラリを明示的にどのプロファイルのものを利用するのか指定する「PackageTargetFallback」という機能があるのでそれを利用します。
上の手続きの内、.csprojを次のように記述してください。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <PackageTargetFallback>portable-net45+win8+wpa81+wp8</PackageTargetFallback>
  </PropertyGroup>

  <ItemGroup>
    <Compile Update="**\*.xaml.cs" DependentUpon="%(Filename)" />
    <EmbeddedResource Include="**\*.xaml" SubType="Designer" Generator="MSBuild:UpdateDesignTimeXaml" />
  </ItemGroup>
  
  <ItemGroup>
    <PackageReference Include="Xamarin.Forms" Version="2.3.4.247" />
  </ItemGroup>
</Project>

まだ未検証なとこ

.NET StandardプロジェクトでNuGetパッケージを参照していると、プラットフォーム側でエラーがでるかもしれません(1.6では出ていた)。
その場合はこちらのブログを参照して、CopyNuGetImplementationsなどの設定をプラットフォーム側に追加してあげてください。

medium.com

以上です!ワクワクしますね! ライブラリ作成者としては.NET Standardに統一されていくのに幸せを感じざるをえません。

.NET Standard 2.0対応クラスライブラリを作る

Visual Studio 2017 Update 3の個人的な目玉は何と言っても、.NET Standard 2.0対応です。
という訳で、早速Xamarinの共通部分を2.0にして試してみましょう!

f:id:nuitsjp:20170815105803p:plain

入ってないのかよ(´・ω・`)
しかも、「他のフレームワークをインストールする」のリンク先に無いし(´・ω・`)

てことで、.NET Core SDK入れたら解決するんじゃね?ってことでここから入れてみました。

www.microsoft.com

そして解決しました。

f:id:nuitsjp:20170815110119p:plain

ちゃんちゃん!ってか、入れといてよ最初からさ(´・ω・`)

Visual Studio 2017 Update 3でAzure Functions and WebJobs Toolsを有効にする方法

Visual Studio 2017 Update 3では、デフォルトでAzure Functions and WebJobs Toolsがインストールされているのですが、おそらく?PreviewのUpdate3用の様で、デフォルトではAzure Functionsのプロジェクトテンプレートが有効になりません。

f:id:nuitsjp:20170815100754p:plain

個別にUpdate 3を入れると、Azure Functions and WebJobs Toolsインストールされて、更新できる状態となっていますのでそれを更新かける必要があるようです。

f:id:nuitsjp:20170815100848p:plain

Update掛けたら無事、Azure Functionsのプロジェクトテンプレートが表示されました。

f:id:nuitsjp:20170815100917p:plain

それだけ!

Visual Studio 2017 Update 2へUpdate3を適用する方法

普段Visual Studioの更新は、VSメニューバーの「ツール」>「拡張機能と更新プログラム」から入れられた気がするのですが、どうも今回は2017.08.15時点ではそこから上げられないようです?

f:id:nuitsjp:20170815094207p:plain

という訳で、Visual Studio Installerを手動で起動して(インストーラーはダウンロードしてもいいし、次のように検索しても出てくるはずです)更新すれば適用できるようです。

f:id:nuitsjp:20170815094350p:plain

インストーラーを起動したら、あとは更新ボタンを押すだけで現時点ではそんなに待たずにアップデートできました。

f:id:nuitsjp:20170815094427p:plain

それだけです。チャンチャン!