nuits.jp blog

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

Xamarin.Forms 2.5.xで「"Xamarin.Forms.Build.Tasks.GetTasksAbi" タスクをアセンブリ~から読み込めませんでした。」というエラーが発生する場合の対処方法

とりあえずメモ程度に。

  1. Xamarin.Formsのバージョンを最新に更新する(2.5.0.77107だと無理かも知れません)
  2. ソリューションをクローズして開き直す

これでだめなら、Visual Studioを再起動しましょう。
一応私はこれでいけました。
海外のフォーラムでも同様の問題を見かけましたが、対処方法はこれ以外見当たりません。

forums.xamarin.com

技術書典3にXamarin本出展します!

来る11月22日(日)に秋葉原UDXにて技術書展3が開催されます。

techbookfest.org

今回も榎本さん率いるサークル「Xamaritans」では新刊「Extensive Xamarin」を用意してお待ちしております。 新刊の詳細情報はこちら。

https://atsushieno.github.io/xamaritans/tbf3.html

今回も私も「Plugins for Xamarin & Unit Test」という内容で寄稿させていただいています。 具体的には

  • Plugins for Xamarinの詳細な仕組みについて
  • Plugins for Xamarinを利用する場合のUnit Test戦略について

記載させていただいています。 他にも面白そうな記事が目白押しです。

残念ながら当日は家庭の事情で現地には行けませんが、興味のある方はぜひお手に取ってみていただけないでしょうか? また既刊である「Essential Xamarin」の商業誌版も当日は併売いたしますので、興味のある方はぜひお立ち寄りください!

www.amazon.co.jp

それでは(某たっきー&つばさコンビが)お待ちしております!

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に統一されていくのに幸せを感じざるをえません。