話の発端はこんな依頼からだった。
「Azure FunctionsからSharePoint OnlineへCSOMでアクセスできない??」
普通にCSOMのライブラリを使えばいけるだろ!と思っていただが、約半日もハマってしまったので覚書。
開発言語はC#で、Visual Studio 2019を使用。
Azure Functionsは.Net Core
まず最初にハマったのが、Azure FunctionsをC#で実装する場合は.Net Coreが対象になる、という点。
下の公式ページに書いてあるのだが、Azure Functionsのランタイムv2とv3は.Net Coreが対象。
Azure Functions ランタイム バージョンの概要
ランタイムv1は.Net Frameworkを対象としているが、今回こちらは選択肢にはなかった。
.Net Coreであることの何が問題か?
それは、.Net Core上でCSOMを動作させるための情報が少なすぎるという点。
.Net CoreとCSOMライブラリ
.Net Core上でCSOMとつなごうとした場合、ちょっとめんどくさい手順を踏むことになる。
詳しくはこちら(Qiita)で紹介してくれているが、もう少し手順を詳しく説明。
まずはV16のCSOMパッケージをインストールする。
Visual StudioのNuGetマネージャーで「CSOM」と検索するとパッケージがたくさんでてくるので、V16のパッケージをインストール
続いて、.Net Coreに必要なライブラリのみを参照するように設定する。
まずは、ソリューションエクスプローラーで[依存関係]-[パッケージ]を開いて、先ほどインストールしたCSOMパッケージを見つける
そのCSOMパッケージのプロパティを開くと、インストールされた場所が見れる。
その場所をエクスプローラーで開くとこんなフォルダ構成になっているので、
netcore45フォルダに
- Microsoft.SharePoint.Client.Portable.dll
- Microsoft.SharePoint.Client.Runtime.Portable.dll
が、
net45フォルダに
- Microsoft.SharePoint.Client.Runtime.Windows.dll
があることを確認する
そしたらVisual Studioに戻って、上の3つのdllへの参照を追加し、Microsoft.SharePoint.Client.dllとMicrosoft.SharePoint.Client.Runtime.dllへの参照を消す。
僕はめんどくさかったので、CSOM V16のパッケージを全消しして、上の3つの参照を追加した。
これでようやく開発の準備が整った。
ExecuteQuery・・・Async??
今回一番ハマったのがここ。ExcecuteQueryにAsyncがついちょる。。。
ひとまず普通に作ってみよう!と思って作ったコードがこちら。
// url:SharePointサイトのURL、accountID:アカウントID、password:パスワード using (ClientContext context = new ClientContext(url)) { context.Credentials = new SharePointOnlineCredentials(accountID, password); FileCreationInformation fileCreation = new FileCreationInformation(); fileCreation.Content = System.Text.Encoding.UTF8.GetBytes("ファイルの内容"); fileCreation.Overwrite = true; fileCreation.Url = "SampleText.txt"; List spList = context.Web.Lists.GetById(new Guid("ドキュメントライブラリのID")); Microsoft.SharePoint.Client.File uploadFile = spList.RootFolder.Files.Add(fileCreation); context.Load(spList); context.Load(spList.RootFolder); context.Load(uploadFile); context.ExecuteQueryAsync().Wait(); }
何のことはない、GUIDで指定したドキュメントライブラリの直下にSampleText.txtファイルを追加するだけのプログラム。
普通のCSOMライブラリであればこれで動作した。
なのに.Net Core上では動かない。コードは特に問題なく終了しても動かない。
なんでだろ。。。
ということで、しばらく悩んだ結果、動作したコードがこちら。
using (ClientContext context = new ClientContext(url)) { context.Credentials = new SharePointOnlineCredentials(accountID, pass); FileCreationInformation fileCreation = new FileCreationInformation(); fileCreation.Content = System.Text.Encoding.UTF8.GetBytes("ファイルの内容"); fileCreation.Overwrite = true; fileCreation.Url = "SampleText.txt"; List spList = context.Web.Lists.GetById(new Guid("ドキュメントライブラリのID")); Microsoft.SharePoint.Client.File uploadFile = spList.RootFolder.Files.Add(fileCreation); context.Load<List>(spList); context.Load<Folder>(spList.RootFolder); context.Load<Microsoft.SharePoint.Client.File>(uploadFile); context.ExecuteQueryAsync().Wait(); }
ジェネリックかーい!Async関係ないんかーい!
ということで、Loadをジェネリックにしたら無事動作した。
まとめ
今回、開発していて何が一番困ったかというと情報が全然ないこと。
もちろん公式のドキュメント「ClientContext.ExecuteQueryAsync method」も見てみたんだけど例は書いてないし、ExecuteQueryAsyncって調べるとJavaScriptやSilverLightのコードがたくさん出てきて探すのも大変だし、と久しぶりにドハマりした内容でした。
コメント