SharePoint アドイン モデルにおける OneDrive for Business のカスタマイズ

新しい SharePoint アドイン モデルで OneDrive for Business サイトをカスタマイズする方法は、完全信頼コードの場合とは異なります。 一般的な完全信頼コード (FTC)/ ファーム ソリューション シナリオでは、SharePoint タイマー ジョブは SharePoint サーバー側オブジェクト モデル コードを使用して作成、ファーム ソリューションで展開、および SharePoint サーバーの全体管理 Web サイトで管理されます。 このシナリオでは、SharePoint は、スケジュール設定とタイマー ジョブの実行の両方を処理します。

SharePoint アドイン モデル シナリオでは、タイマー ジョブが作成され、SharePoint の外部でスケジュール設定されます。 このシナリオでは、SharePoint はスケジュールの設定やタイマー ジョブの実行を行いません。

OneDrive for Business サイトをカスタマイズする理由

OneDrive for Business (OD4B) サイトへのカスタマイズの適用には、さまざまな側面があります。 これらのサイトは SharePoint サイトであるため、カスタマイズが可能ですが、同時に、カスタマイズの短期的および長期的な影響を考慮する必要があります。

基本ガイドライン

OD4B サイトのカスタマイズについては、大まかに次のような基本ガイドラインが提供されています。

  • Office 365 のテーマまたは SharePoint サイトのテーマ エンジンを使用してブランド化カスタマイズを適用する
  • テーマ エンジンが十分でない場合は、代替 CSS オプションを使用していくつかの CSS 設定を調整できます。
  • カスタム マスター ページを使用して OD4B サイトをカスタマイズすることができますが、長期にわたる追加コストと将来の更新に関する課題が生じる可能性があります。
    • ほとんどの場合、テーマと代替 CSS を使用してすべての一般的なブランド化シナリオを実現できるため、これが制限要因になることはありません
    • カスタム マスター ページを使用する場合は、Office 365 に主要な機能更新プログラムが適用されたときにサイトに変更を適用する準備をしておいてください
  • サイトの機能を変更または非表示にするには、JavaScript 埋め込みを使用できます
  • CSOM を使用して、OD4B サイトの言語や地域の設定を制御できます (「新しい API」を参照)
  • 必要なフィールドやその他の要素が変更されないよう、OD4B サイトでコンテンツ タイプやサイト列を使用することはお勧めしません。これにより、OD4B サイトの通常の使用で問題が発生する可能性があります。
    • OD4B サイトは、個人の非構造化データとドキュメントと考えてください。 すると、チーム サイトとコラボレーションの位置付けが、会社のデータとドキュメントを対象としたものになり、あらゆる情報管理ポリシーとメタデータを確実に使用できるようになる。

要約すると、Office 365 では、カスタマイズは間違いなくサポートされており、OD4B サイトで使用し続けることができます。 カスタマイズの短期的および長期的な影響を運用と保守の観点から考慮してください。 これは、実際には SharePoint に限定されず、任意のプラットフォームで構築されたすべての IT ソリューションに当てはまる経験則です。

上記のガイドラインを使用してカスタマイズした OD4B サイトの例を以下に示します。 ここでは、最終的な結果を得るために、Office 365 のテーマ、サイトのテーマ、いわゆる JavaScript 埋め込みパターンの使用を組み合わせています。

完成したカスタムの OD4B サイトのビュー。

OneDrive for Business サイトのカスタマイズを適用する場合の課題

最初に、どのような課題があり、ここで何を解決しようとしているかを定義することから始めましょう。 技術的には、各OneDrive for Business サイトは現在、SharePoint 2007 または 2010 バージョンで個人用サイトまたは個人用サイトが使用したアーキテクチャと同じアーキテクチャを使用しています。 つまり、技術的には各 OneDrive for Business サイトは、独自のサイト コレクションであり、ブランド化などのカスタマイズを適用する一元的な場所はありません。

OneDrive for Business サイトのカスタマイズを適用する場合の課題

必要な構成を OneDrive for Business サイト (マイ サイトまたは個人用サイトを含む) に適用する従来のソリューションは、ファーム レベルの機能の関連付けに基づいていました。 つまり、SharePoint ファームにファーム ソリューションを展開し、マイ サイトが作成されるたびにカスタム機能をアクティブ化するよう、機能フレームワークを使用してカスタム機能を関連付け、その後、必要なカスタマイズを適用していました。 ファーム ソリューションを展開する必要があり、Office 365 のサイトではこれが不可能なため、このような方法は Office 365 では機能しません。 したがって、必要な変更をサイトに適用するため、代替案を探す必要があります。

Office 365 では、OD4B サイトが作成されるときにカスタム コードをアタッチできるような、一元的なイベントは発生しません。 つまり、アプリ モデルのアプローチで非常によく用いられる、別の解決策を考える必要があります。 古いモデルにこだわらず、新しい API とテクノロジを使って、同じ最終的な結果を達成する方法について考えましょう。 ビジネス要件は機能の関連付けを使うことではないため、サポートされるなんらかの技術的メカニズムを使って必要なカスタマイズを適用することに関して、純粋な要件の観点から見ると、適用される限り、どんな方法でサイトにカスタマイズを適用するかはたいした問題ではありません。

カスタマイズを適用するためのさまざまなオプション

実際には、Office 365の OD4B サイトに一元化されたカスタマイズを適用するための 4 つの異なるメカニズムがあります。 5 番目として手動オプションを検討することもできますが、数百、数千の OD4B サイトがある場合は、手動オプションの使用は現実的ではありません。 4 つのオプションを次に示します。

  1. Office 365 スイート レベルの設定 (Office 365 テーマおよび他の設定)
  2. ユーザー コンテキストが含まれる非表示のアプリ パーツ
  3. 構成を事前に作成して適用する
  4. ユーザー プロファイルの更新に基づくリモート タイマー ジョブ

各オプションには長所と短所があり、適切なオプションは詳細なビジネス要件によって異なります。 一部の設定は、Office 365 スイート レベルから適用することもできますが、多くの場合、いくつかの詳細を探しているため、実際のカスタマイズが必要になります。 これは明らかに、正確な要件とビジネスケース分析によって、短期的および長期的な影響に関するものです。

Office 365 スイート レベルの設定

ご存じのように、Office 365 には SharePoint より多くの機能があります。 Delve、Yammer、および予定されている多くのサービスのように、SharePoint アーキテクチャにさえ基づいていない、多くの追加サービスを次々に見つけることができます。 つまり、企業のブランド化と構成とは SharePoint サイトの内容を制御することだけではなく、むしろエンド ユーザー エクスペリエンス全体や、さまざまなサービスで一貫性のある構成を提供する方法について考える必要があります。

これらのエンタープライズ要件の従来の例としては、ブランド化があります。そのため、既にOffice 365テーマが導入されており、これを使用して、あるレベルのブランド化を制御できます。 また、Office 365ロードマップに現在記載されているOffice 365のコンプライアンス センターなど、サイト コレクションの設定外の一元的な場所から、サイト ガバナンスやその他の設定を制御するのに役立つその他の今後の機能もあります。

次の図は、今後すべての Office 365 サービスに適用される、Office 365 のテーマの現在の設定を示しています。

「Manage custom themes for your organization」というタイトルが付いたカスタム テーマのタブ ページを示している Office 365 サイトが表示されています。このページでは、自分の組織のブランドを反映するように Office 365 をカスタマイズします。カスタム ロゴ、クリック可能なロゴの URL、背景画像、アクセント カラー、ナビゲーション バーの背景色、テキストとアイコンの色、およびアプリ メニュー アイコンの色についての設定が使用できます。

既定では、Office 365テーマ設定は OD4B サイト スイート バーを制御するため、このオプションを他のオプションと共に使用して、OD4B サイト間で少なくとも適切なブランド化要素を確実に提供できる可能性があります。 たとえば、管理ツール Office 365でテーマ設定Office 365変更すると、OD4B サイトに設定が適用されるまでにかなり長い時間がかかるため、忍耐が必要です。

ユーザー コンテキストが含まれる非表示のアプリ パーツ

これは、必要なカスタマイズ プロセスを開始するための場所として、一元管理されたランディング ページを使うアプローチです。 つまり、企業イントラネットのフロント ページのような、ユーザーがブラウザーを開いたときに常にランディングする一元管理された場所を用意する必要があります。 これは、企業のランディング ページが AD のグループ ポリシー設定を使ってコントロールされる、中規模および大規模なエンタープライズでの一般的なプロセスです。 そうすることで、エンド ユーザーが会社のドメインに参加するブラウザーの既定のウェルカム ページを上書きできなくします。

ユーザーがイントラネットにアクセスしたときに、ページに非表示のアプリ パーツを配置することで、カスタマイズ プロセスを開始します。 通常のユーザーはサイト作成プロセスが開始する前に一度 OD4B サイトを訪問する必要があるため、実際にはこのアプリ パーツは、OD4B サイトの作成全体を実行します。 実際には非表示のアプリケーション パーツは、Azure でホストされるプロバイダー ホスト型アプリケーションのページをホストしています。 次に、このページはカスタム プロセスを開始します。

では、このアプローチの論理設計について詳しく説明します。

リレーションシップを示すダイアグラム。SharePoint サイトのアプリ パーツは、インスタンス化を使用してプロバイダー ホスト型のアプリに向かっています。プロバイダー ホスト型アプリは、メッセージの追加を使用してストレージ キューに向かっています。ストレージ キューは、インスタンス化を使用して WebJob に向かっています。WebJob は、変更の適用を使用して OD4B サイトに向かっています。

  1. 非表示のアプリ パーツを、エンドユーザーが到着する集中管理サイトに配置します。 通常これは、企業のイントラネットのフロント ページです。
  2. アプリ パーツはプロバイダー ホスト型アプリのページをホストし、サーバー側のコードでは、必要なメタデータを Azure ストレージ キューに追加してカスタマイズ プロセスを開始します。 つまり、このページのカスタマイズ要求のみを受信しますが、処理時間を通常どおり維持するため、実際には変更を適用しません。
  3. これは、処理をキューに追加するために受信される、実際の Azure ストレージ キューです。 このようにして、エンド ユーザーがイントラネットのフロント ページに留まる時間が問題とならないよう、カスタマイズ制御プロセスを非同期的に処理します。 カスタマイズ プロセスを同期すると、ページの実行が完了するまでイントラネットのフロント ページでブラウザーを開いたままにするかは、エンドユーザーに依存します。 これは間違いなく最適とは言えず、しばらく前のブログ記事に書いた元の OD4B のカスタマイズ プロセス課題でした。
  4. WebJob は次のストレージ キューにフックされ、ストレージ キューに新しいアイテムが配置されたときに呼び出されます。 この WebJob は、正しいサイト コレクションにアクセスするため、キューのメッセージから必要なパラメーターとメタデータを受信します。 WebJob は、App Only トークンを使用しており、テナントのレベルでサイト コレクションを操作するために必要なアクセス許可が付与されます。
  5. 実際のカスタマイズは、プロセスを開始するイントラネットのフロント ページにアクセスした人のサイトに対して、個々に適用されます。

これは、間違いなく、OD4B サイトに適切な構成が存在することを保証する最も信頼性の高いプロセスです。 また、プロセスにカスタマイズ バージョン管理ロジックを簡単に追加することもでき、そうすることで必要な更新がありユーザーが次回イントラネットのフロント ページにアクセスしたときに、OD4B サイトに必要な更新を適用されます。 ただし、このオプションでは、エンド ユーザーがランディングする一元管理された場所が必要です。

ファーム ソリューションを使用した従来の SharePoint 開発モデルに慣れている場合、これはワンタイム実行タイマー ジョブと非常に似たプロセスです。

構成を事前に作成して適用する

このオプションは、ユーザーがアクセスする前の、OD4B サイトの事前作成に依存しています。 これは、CSOM または REST のいずれかを使用して、一括プロセスで特定のユーザーの OD4B サイトを作成する比較的新しい API を使用して実現できます。 PowerShell スクリプトを使用するか、リモート API を呼び出す実際のコードを記述することで必要なコードを開始できます。

管理者は、事前作成とカスタマイズを使用して OD4B サイトを作成します。

  1. 管理者は、リモート作成 API を使用してユーザーの OD4B サイトを作成し、スクリプト プロセスの一部として OD4B サイトに必要なカスタマイズを適用します。
  2. 実際の OD4B サイトは特定のユーザーのために Office 365 に作成され、ユーザー プロファイルに関連付けられます。

ある意味では、これは本当に信頼性の高いプロセスでもありますが、新しい人を管理し、"手動で"更新する必要があります。これは、 隠されたアプリパーツ のアプローチを使用して、より多くの作業を意味する可能性があります。 これは間違いなく有効なアプローチであり、他のファイル共有ソリューションから OD4B に移行する場合に、実際のサイト作成を開始する前にエンド ユーザーが OD4B サイトに 1 回アクセスする必要を回避する場合に特に便利です。

ユーザー プロファイルの更新に基づくリモート タイマー ジョブ

この方法では、OD4B サイトの作成者を確認するためにユーザー プロファイルをスキャンした後、必要に応じて変更をサイトに適用します。 つまり、SharePoint の外部で実行されるスケジュールされたジョブは、定期的に状態をチェック、必要なカスタマイズを実行します。 スケジュールされたジョブは、Azure での WebJob として、または独自の Windows スケジューラーでスケジュールされた PowerShell スクリプトとしてシンプルに実行することができます。 明らかに、展開の規模は選択したスケジュール設定オプションに大きな影響を与えます。

リモート タイマー ジョブは、サイト コレクション内のループを使用して各サイトをカスタマイズします。

  1. スケジュールされたタスクが開始し、OD4B サイトのプロビジョニングを行ったユーザーを確認するため、ユーザー プロファイルにアクセスします。
  2. 実際のサイトは、個々のビジネス要件に基づいてカスタマイズされます。

このオプションのキーの欠点の 1 つは、カスタマイズが適用される前に、ユーザーが OD4B サイトにアクセスできる状況の可能性が明確にあるということです。 同時に、このオプションは、エンドユーザーがサイト上の必要な設定を変更しないようにする、または OD4B サイトのコンテンツが会社ポリシーに沿っていることを確認するための他のオプションにとって興味深いアドオンでもあります。

アプリ パーツ ベースのカスタマイズの強化

ここでは、強化されたアプリ パーツ ベースのカスタマイズについて詳しく説明します。これは、OD4B サイトに必要なカスタマイズを適用および管理するための一般的なアプローチと思われます。 このソリューションのソース コードとその他の詳細については、Office 365開発者パターンとプラクティスに関するガイダンスを参照してください。

非表示のアプリ パーツのアプローチに続き、実際の論理設計 (以前、このブログの投稿で説明しました) を示します。 つまり、Office 365 環境に必要なアプリ パーツを配置できる集中管理イントラネットがあり、エンド ユーザーがブラウザーを開くと、ようこそページにリダイレクトされることを前提としています。 エンド ユーザーがブラウザーを開くと常に集中管理された場所から開始するよう、グループ ポリシーを使用して各会社ブラウザーに同じホーム ページを設定することは一般的です。 この場所に、幅と高さのサイズを 0 ピクセルに設定可能なアプリ パーツを配置します。 ここで重要なポイントは、エンド ユーザー コンテキストを使用して、プロバイダー ホスト型アドインのページを含むアプリ パーツを実行するということです。

パフォーマンスの最適化と保守に関する考慮事項

このアプリ パーツは、ユーザーがイントラネットのフロント ページに移動するたびに実行されるため、このパフォーマンスへの影響や、コードを効率的に動作させ、本当に必要なときにコード実行の重要な部分のみを実行する方法を考慮する必要があります。 2 つ目の最適化の考慮事項は、各サイトで使用される実際の資産を配置する場所でもあります。 これらは、あらゆるカスタマイズに取り組むための非常に一般的な課題です。 アプリ モデルの実装に集中する簡単な一覧を次に示します。

  • 資産の場所 – 一元的なコンテンツ配信ネットワーク (CDN) ソリューションを、各サイト コレクションまたはルート サイト コレクションのどちらに配置しますか。
  • クライアント側のブラウザーのキャッシュに関係なく最新バージョンスクリプトの (JavaScript) を実行し、最新バージョンの画像を確実に表示できる資産のリフレッシュ レートや、その確認方法は何ですか。
  • コードの実行を削減し、Azure と Office 365 サービスに不要な負荷を避ける
  • OD4B サイトに適用されるバージョンのカスタマイズ

資産の場所

これにはいくつかの解決策があります。 参照コードの例では、会社のポリシーのメッセージを提供し、サブ サイトの作成の可能性を排除 (またはリンクを非表示に) するため、各 OD4B サイトで JavaScript の埋め込みを使用しています。 この解決策では、必要な JavaScript ファイルを OneDrive for Business アドレス スキームのルート サイト コレクションにアップロードし、個々 の OD4B サイトでその 1 つの場所から直接そのファイルを参照します。 つまり、変更が必要な場合、1 つの場所で JavaScript ファイルの保守と更新を行うことができます。

この参照実装では、WebJob が実行されるたびにこのファイルを実際に更新します。これは確かに必要ありませんが、サンプル コードは追加の手順や可能な限り簡単に動作するように意図されていました。 同様に、JavaScript ファイルをルート サイト コレクションに手動でアップロードし、そこからそれを参照することもできます。 別の解決策は、いくつかのCNDを使用して必要なファイルを格納するか、プロバイダーでホストされているアプリ側からJavaScriptを参照することです。 ファイルのコピーが 1 つしかない限り、次の内容が得られます。

資産の場所

クライアント側キャッシュの課題と解決法

JavaScript ベースのの実装での課題の 1 つは、クライアント側キャッシュです。 使用されている JavaScript ファイルをダウンロードするとき、ブラウザーは、次回の要求でダウンロードする資産の量を減らすため、それらのファイルをキャッシュします。 このことは、パフォーマンスの最適化の観点で優れていますが、JavaScript ファイルの更新が必要となったときに問題が発生します。 最悪の場合、キャッシュされた JavaScript ファイルによって、更新後のバージョン導入された他の更新プログラムで例外が発生します。

この問題を解決するために、JavaScript URL リファレンスでリビジョン属性の使用を開始できます。 ユーザー カスタム アクションを OD4B サイトに関連付けると、URL に一意の GUID を持つ JavaScript の URL が含まれます。 サイト コレクションのルート サイトを指す参照の例を次に示します。 URL の rev 属性の後に追加された追加の GUID に注目してください。 特定の OD4B サイトに対してカスタマイザーが実行されるたびに、この属性が更新されます。 実際には、これは、OD4B サイトに新しいバージョンが追加されるまで JavaScript ファイルがブラウザーにキャッシュされることを意味します。URL が変更されるため、ブラウザーは新しいバージョンをダウンロードし、次の更新後にそのファイルをキャッシュします。

  • /OneDriveCustomization/OneDriveConfiguration.js?rev=4bb89029e7ba470e893170d4cba7de00

ユーザー カスタム アクション用の JavaScript URL の生成に使用されるコードを次に示します。

/// <summary>
/// Just to build the JS path which can be then pointed to the OneDrive site.
/// </summary>
/// <returns></returns>
public string BuildJavaScriptUrl(string siteUrl)
{
    // Solve root site collection URL
    Uri url = new Uri(siteUrl);
    string scenarioUrl = String.Format("{0}://{1}:{2}/{3}", 
                            url.Scheme, url.DnsSafeHost, 
                            url.Port, JSLocationFolderName);
    // Unique rev generated each time JS is added, so that we force browsers to 
    // refresh JS file wiht latest version
    string revision = Guid.NewGuid().ToString().Replace("-", "");
    return string.Format("{0}/{1}?rev={2}", scenarioUrl, JSFileName, revision);
}

コードの実行を削減する

このページはイントラネットのフロント ページに非表示のアプリ パーツを搭載する方法に基づいているため、ユーザーがブラウザーを更新またはページに移動するたびにコードが実行されます。 このフロント ページは多くの場合、企業内のユーザーの既定ブラウザーのホーム ページとして設定されているため、ブラウザー セッションを起動するたびにコードが実行されます。

ただし、頻繁に OD4B サイトに適用されるカスタマイズは更新されないため、最初にカスタマイズ更新プロセス全体を開始しても意味がありません。 これにより、ストレージ キューと Web ジョブの実行の使用量を削減し、設計で CPU やその他のリソースをあまり使用しないため、プロバイダーでホストされているアプリ側に関連するコストを直接削減します。

各要求で処理が実行されないようにする最も簡単な方法は、特定の有効期間で特定の Cookie をクライアント ブラウザーに保存する従来のブラウザー Cookie アプローチを使用することです。 この Cookie の存在を確認することで、Cookie の有効期限が切れ、OD4B サイトの実際のカスタマイズ状態を再チェックするまで、実行をスキップできます。

アプリ パーツのページ読み込みメソッドは、次のとおりです。 このメソッドの呼び出しは、cookie の存在を確認し、cookie が存在する場合、実行が再度必要になるまで、実際のビジネス コードをスキップします。

// Check if we should skip this check. We do this only once per hour to avoid 
// perf issues and there's really no point even hitting the user profile 
// in every request.
if (CookieCheckSkip())
    return;

Cookie の実際の状況と cookie の設定は、次のように行われます。

/// <summary>
/// Checks if we need to execute the code customization code again. 
/// Timer set to 60 minutes to avoid constant execution of the code for nothing.
/// </summary>
/// <returns></returns>
private bool CookieCheckSkip()
{
    // Get cookie from the current request.
    HttpCookie cookie = Request.Cookies.Get("OneDriveCustomizerCheck");

    // Check if cookie exists in the current request.
    if (cookie == null)
    {
        // Create cookie.
        cookie = new HttpCookie("OneDriveCustomizerCheck");
        // Set value of cookie to current date time.
        cookie.Value = DateTime.Now.ToString();
        // Set cookie to expire in 60 minutes.
        cookie.Expires = DateTime.Now.AddMinutes(60);
        // Insert the cookie in the current HttpResponse.
        Response.Cookies.Add(cookie);
        // Output debugging information
        WriteDebugInformationIfNeeded(
            string.Format(@"Cookie did not exist, adding new cookie with {0} 
                            as expiration. Execute code.",
                            cookie.Expires));
        // Since cookie did not existed, let's execute the code, 
        // so skip is false.
        return false;
    }
    else
    {
        // Output debugging information
        WriteDebugInformationIfNeeded(string.Format(@"Cookie did existed, 
                                    with {0} as expiration. Skipping code.", 
                                    cookie.Expires));
        //  Since cookie did existed, let's skip the code
        return true;
    }
}

アプリ パーツ ページにあるコードを詳しく見ると、呼び出しのたびにエンド ユーザーに対して OD4B サイトの存在を確認していることがわかります。 この動作は、ユーザー プロファイルにアクセスすることによってのみ実行可能なため、コードはパフォーマンスに影響を与えます。 上記の cookie のチェックを使用することで、エンド ユーザー エクスペリエンスが向上し、実際の要件がないにもかかわらずユーザーのプロファイル サービスをヒットし続けるのを回避します。 また、必要な場合はすべてのプロセスをスキップするよう、Page_Load メソッドの最初のステップとして cookie の確認を配置しています。 コードのプロセスを表示する Page_Load メソッド (Customizer.aspx) の短いスニペットを次に示します。

protected void Page_Load(object sender, EventArgs e)
{
    // Check if we should skip this check. We do this only once per hour to avoid 
    // perf issues and there's really no point even hitting the user profile 
    // in every request.
    if (CookieCheckSkip())
        return;
  
    var spContext = 
        SharePointContextProvider.Current.GetSharePointContext(Context);
    using (ClientContext clientContext = 
        spContext.CreateUserClientContextForSPHost())
    {
        // Get user profile
        ProfileLoader loader = ProfileLoader.GetProfileLoader(clientContext);
        UserProfile profile = loader.GetUserProfile();
        Microsoft.SharePoint.Client.Site personalSite = profile.PersonalSite;

        clientContext.Load(profile, prof => prof.AccountName);
        clientContext.Load(personalSite);
        clientContext.ExecuteQuery();

        // Let's check if the site already exists
        if (personalSite.ServerObjectIsNull.Value)
        {

OD4B サイトに適用されるバージョンのカスタマイズ

コード プロセスの最適化の 2 番目のレベルは、OD4B のサイトに展開されるカスタマイズのバージョンを具体的に管理することで行われます。 つまり、OD4B サイトのプロパティ バッグにカスタマイズのバージョンを格納し、必要に応じてファイルや資産のみを更新します。 WebJob の実行時、OD4B の現在のカスタマイズ バージョンとこれから展開するバージョンを比較し、OD4B サイト内にカスタマイズ バージョンが存在しない場合にのみ、必要な資産をアップロードし、他の設定を適用します。

この方法でも、必要でない場合は実際のカスタマイズ コードの更新や実行を行わないため、Microsoft Azure から必要なリソースを大幅に削減します。 つまり、Microsoft Azure における CPU やその他のリソース使用量、および Office 365 に対する要求を削減します。

このサンプルで格納されているすべてのカスタマイズ ロジックは、ApplySiteConfiguration メソッド (OD4B.Configuration.Async.Common.SiteModificationManager クラス) にあります。 また、このメソッドは、カスタマイズ プロセスを開始するための適切なパラメーターを持つ WebJob によっても呼び出されます。 実際に操作を実行する前に、「Contoso_OneDriveVersion」のキーでプロパティ バッグの値をチェックし、サイト内の現在のバージョンが、適用を計画しているバージョンより低い場合にのみ実行が続行されます。 コードを簡素化するために Office PnP コア コンポーネント を使用している実際のコードは、次のとおりです。

// Check current site configuration status - is it already in right version?
if (ctx.Web.GetPropertyBagValueInt(
    SiteModificationManager.OneDriveMarkerBagID, 0) 
    < SiteModificationManager.BrandingVersion)
{

サイトにカスタマイズを適用すると、次回の実行に備え、適用されたカスタマイズ バージョンをプロパティ バッグに設定します。

// Save current branding applied indicator to site
ctx.Web.SetPropertyBagValue(SiteModificationManager.OneDriveMarkerBagID, SiteModificationManager.BrandingVersion);

これは比較的単純なプロセスですが、Azure から必要なリソースを大幅に削減し、Office 365 に対する不要なリモート操作も削減するため、パフォーマンスによい影響を与えます。

Azure で必要な構成

このサンプルが正しく動作するために重要な要件は、Azure ストレージ データ サービスを作成し、それらを使用するプロジェクトに従ってストレージの接続文字列を更新しているということです。 Azure 管理ポータル (manage.windowssazure.com) からストレージ サービスとして作成するには、[新規] - [データ サービス] - [ストレージ] ->>> [クイック Create] の順に選択します。 その後、名前、場所、およびその他のいくつかの設定を定義するだけで完了です。

簡易作成の設定:[URL] フィールドは

ストレージが作成されていると、接続文字列に必要なキーをコピーする必要があります。 ストレージの詳細ページに移動すると、ページの下部にある [アクセス キーの管理] をクリックして、キー情報にアクセスできます。

[アクセス キーの管理] へのリンクが、ページの一番下で強調表示されています。

Visual Studio ソリューションで、次のプロジェクト用に App.config ファイルを更新する必要があります。 各プロジェクトの詳細については、このブログの記事で後述します。

OD4B.Configuration.Async.WebJob OD4B.Configuration.Async.Console.SendMessage WebJob プロジェクトには 2 つのキーがあり、同じ接続を示すよう更新できます。SendMessage には、更新が必要なキーが 1 つだけあります。

App.config ファイルの appSettings 要素の部分が Visual Studio で開かれています。Add という名前の 2 つの子要素が、appSettings 要素の下に示されています。最初の Add 要素には、属性 key=ClientId があり、その value 属性は 1 対の二重引用符と等号で結ばれています。2 番目の Add 要素には、属性 key=ClientSecret があり、その value 属性も 1 対の二重引用符と等号で結ばれています。

リファレンス ソリューションの構造

この Visual Studio のソリューションは、多数のソリューションで構成されていますが、それぞれに非常に合理的な理由があります。 ソリューションの各プロジェクトの概要と、それらが存在する理由、およびそれらの目的を次に示します。

ソリューション エクスプローラーには、Documentation という名前のフォルダーと、その後に 6 つのプロジェクトが表示されます。これらのプロジェクトの詳細を次に示します。

OD4B.Configuration.Async

これは実際の SharePoint アプリ プロジェクトで、プロバイダーでホストされているアプリを SharePoint に導入し、必要なアクセス許可を求めます。 実際にはアプリ パーツからテナント レベルの操作を実行しない場合でも、アドインに対して非常に高いアクセス許可を求めていることに注意してください。 これは、WebJob の実行で、このアプリ ファイルから同じクライアント ID とシークレットを使用するためです。 この方法を使用すると、アプリ ID とシークレットを SharePoint に手動で登録する必要はなく、同じ識別子とシークレットクロス ソリューションを使用するだけです。

アクセス許可の一覧:スコープ [テナント] には、FullControl のアクセス許可が付与されています。スコープ [ユーザー プロファイル (ソーシャル)] には、FullControl のアクセス許可が付与されています。チェック ボックス [アプリで SharePoint へのアプリ専用呼び出しを許可します。] はオンになっています。

このプロジェクトには、ホスト Web に展開されるアプリ パーツ定義も含まれています。

OD4B.Configuration.Async.Common

このプロジェクトには、ストレージ キューに配置されるデータ オブジェクトの定義や OD4B サイトをカスタマイズするための実際のビジネス ロジックなど、すべての実際のビジネス ロジックと共有コードクロス プロジェクトが含まれています。 ここにコードを配置する理由は、プロジェクトの作成時に操作を簡単に開発してテストする方法を提供するためだけです。 一般的な開発と同様に、テストやコードの再利用を容易にするために、ビジネス ロジック コードを WebJob またはアプリ パーツに直接配置するのではなく、ビジネス ロジック レイヤーに配置する必要があります。

OD4B サイトに対する実際の操作はすべて、OD4B.Configuration.Async.Common.SiteModificationManager クラスにあります。

OD4B.Configuration.Async.Console.Reset

このプロジェクトは、実際のカスタマイズのためのテストおよびデバッグ プロジェクトです。 必要なカスタマイズを任意の OD4B サイトに手動で適用するために使用できます。 開発期間中、このプロジェクトは、Web ジョブにフックされる前にカスタマイズ プロセスをテストするためのテスト プロジェクトでした。 また、プロジェクトを使用して、デモやテストのために任意の OD4B サイトからのカスタマイズをリセットすることもできます。 実際のビジネス ロジックは共通プロジェクトに配置されているため、このプロジェクトでは、サイトからのカスタマイズを適用またはリセットするために、他のプロジェクトと同じ SiteModificationManager クラスが使用されます。

カスタマイズをテストするときには、メイン メソッドのコードで「適用」と「リセット」を切り替え、目的の操作を変更できます。

static void Main(string[] args)
{
  
    Uri url = 
        new Uri("https://vesaj-my.sharepoint.com/personal/vesaj_veskuonline_com");
  
        //get the new site collection
    string realm = TokenHelper.GetRealmFromTargetUrl(url);
    var token = TokenHelper.GetAppOnlyAccessToken(
                    TokenHelper.SharePointPrincipal, 
                    url.Authority, realm).AccessToken;
    using (var ctx = 
        TokenHelper.GetClientContextWithAccessToken(url.ToString(), 
        token))
    {
        // Uncomment the one you need for testing/reset
        // Apply(ctx, url);
        Reset(ctx);
    }
}

app.config 内のこのプロジェクトのアプリ ID とシークレットが、テナントに必要なアクセス許可を与えたものと一致していることを確認する必要があります。 プロジェクトを右クリックして [デバッグ] > [新しいインスタンスを開始] を選択することで、プロジェクトを簡単に実行し、実行されるコードを 1 行ずつ確認できます。

OD4B.Configuration.Async.Console.SendMessage

このプロジェクトは、アプリ パーツにフックされる前にストレージ キュー メカニズムをテストするため、ソリューションに追加されました。 プロジェクトを使用して、ストレージ キューに新しいメッセージを追加するアプリ パーツ プロセスを回避できます。 プロジェクトが正常に動作するよう、app.config に従ってストレージ キュー接続文字列を更新する必要があります。

プロジェクトを右クリックして [デバッグ] > [新しいインスタンスを開始] を選択することで、プロジェクトを簡単に実行し、実行されるコードを 1 行ずつ確認できます。

OD4B.Configuration.Async.WebJob

これは、Visual Studio 2013 Update 4 で導入された WebJob プロジェクト テンプレートを使用して作成された、実際の WebJob のプロジェクトです。 このテンプレートを使用すると、正しい参照を配置して WebJob プロジェクトを簡単に作成できるようにします。 また、プロジェクトの正しいクリック サポートにより、優れた展開の自動化を提供します。 単にプロジェクトの初期バージョンまたは新しいバージョンのプロジェクトを右クリックし [Azure Web ジョブとして発行] を選択すると発行ウィザードが開き、それらを Azure に展開できます。

[Web の発行] ダイアログ ボックスが表示され、[接続] タブが表示されます。[サーバー] フィールドには vesaj-od4bconf.scm.azurewebsites.net:443 値が含まれます。[サイト名] フィールドには値 vesaj-0d4bconf が含まれており、[ユーザー名] フィールドが編集され、[パスワード] フィールドがマスクされ、[パスワードの保存] チェック ボックスがオンになっており、[宛先 URL] フィールドに値が含まれていますhttp://vesaj-od4bconf.azurewebsites.net.

この WebJob は、キュー ベースの処理に必要な継続的な WebJob として作成されます。 つまり、メイン メソッドでは、次のようにプロセスを連続で実行するのみ設定します。

class Program
{
    // Please set the following connection strings in app.config for this 
    // WebJob to run: AzureWebJobsDashboard and AzureWebJobsStorage
    static void Main()
    {
        var host = new JobHost();
        // The following code ensures that the WebJob will be 
        // running continuously
        host.RunAndBlock();
    }
}

実際のキュー プロセスは、WebJobs を使用すると非常に簡単です。 必要な操作は、メソッドに適した属性を設定し、アプリ構成内の Azure ストレージ接続文字列が適宜更新され、Microsoft Azure で作成したストレージ キューと一致していることを確認するだけです。 次は、functions.cs クラスの ProcessQueueMessage メソッドです。 WebJob から SharePoint にアクセスするための、App Only トークン モデルの使用方法に注意してください。 これが動作するためには、プロジェクトの app.config に正しいアプリ ID とシークレットがコピーされたことを確認する必要があります。 実際のビジネス ロジックは SiteModificationManager クラスにあるため、適切なクライアント コンテキストおよびパラメーターを使用して呼び出すだけです。

// This function will get triggered/executed when a new message is written 
// on an Azure Queue called queue.
public static void ProcessQueueMessage(
    [QueueTrigger(SiteModificationManager.StorageQueueName)] 
    SiteModificationData request, TextWriter log)
{
    Uri url = new Uri(request.SiteUrl);
  
    //Connect to the OD4B site sing App Only access
    string realm = TokenHelper.GetRealmFromTargetUrl(url);
    var token = TokenHelper.GetAppOnlyAccessToken(
        TokenHelper.SharePointPrincipal, url.Authority, realm).AccessToken;

    using (var ctx = TokenHelper.GetClientContextWithAccessToken(
        url.ToString(), token))
    {
        // Set configuration object properly for setting the config
        SiteModificationConfig config = new SiteModificationConfig()
        {
            SiteUrl = url.ToString(),
            JSFile = Path.Combine(Environment.GetEnvironmentVariable
                ("WEBROOT_PATH"), "Resources\\OneDriveConfiguration.js"),
            ThemeName = "Garage",
            ThemeColorFile = Path.Combine(Environment.GetEnvironmentVariable
                ("WEBROOT_PATH"), "Resources\\Themes\\Garage\\garagewhite.spcolor"),
            ThemeBGFile = Path.Combine(Environment.GetEnvironmentVariable
                ("WEBROOT_PATH"), "Resources\\Themes\\Garage\\garagebg.jpg"),
            ThemeFontFile = "" // Ignored in this case, but could be also obviously set
        };

        new SiteModificationManager().ApplySiteConfiguration(ctx, config);
    }
}

注目すべきもう 1 つの点は、Web ジョブを展開したときに、すべての依存アセンブリが Azure に適切にコピーされるよう、プロジェクトの SharePoint CSOM アセンブリ参照プロパティの [ローカル コピー] プロパティを設定していることを確認する必要があるということです。 これは、単にこれらのアセンブリが既定では標準の Azure Web サイトには格納されていないためです。このプロパティ True を設定することで、参照アセンブリが確実にクラウドにコピーされていることを同様に確認します。

OD4B.Configuration.AsyncWeb

これは、Microsoft Azure でホストされる実際のプロバイダー ホスト型アプリです。 アプリ パーツに搭載されたページを含むアプリ パーツは、イントラネットのフロント ページに配置されます。 実際、このアプリの Default.aspx ページにすべての操作が含まれておらず、アプリの使用方法について詳しく説明します。

注意してください。 WebJob またはアプリのみのアクセスに関するアクセス拒否の問題に直面する場合は、このプロジェクトの web.config の値と一致するように、app.config のアプリ クライアント ID とシークレットが更新されていることを確認してください。 Visual Studio では、特定のシナリオでこれらの値を変更できます。

WebJob でのキューの処理

ストレージ キューの使用は、Azure から入手できる API を使用して簡単に行います。 作業を開始する最も簡単な方法は、必要なすべての API やその他のパッケージをプロジェクトに関連付ける "Windows Azure Storage" Nuget パッケージを使用することです。 この Nuget パッケージを追加したら、処理にストレージ キュー API の使用を開始するだけです。 OD4B のスニペットを次に示します 。Configuration.Async.Common プロジェクト (SiteModificationManager クラスの AddConfigRequestToQueue メソッド) は、実際のキュー メッセージ処理コードを含み、多数のプロジェクトから使用されます (開発時間のデバッグが容易になります)。

public void AddConfigRequestToQueue(
            string account, string siteUrl, string storageConnectionString)
{
    CloudStorageAccount storageAccount = 
                        CloudStorageAccount.Parse(storageConnectionString);
  
    // Get queue... create if does not exist.
    CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
    CloudQueue queue = 
        queueClient.GetQueueReference(SiteModificationManager.StorageQueueName);
    queue.CreateIfNotExists();

    // Pass in data for modification
    var newSiteConfigRequest = new SiteModificationData()
    {
        AccountId = account,
        SiteUrl = siteUrl
    };

    // Add entry to queue
    queue.AddMessage(
        new CloudQueueMessage(
            JsonConvert.SerializeObject(newSiteConfigRequest)));
}

この場合、実際のキュー処理は、WebJob プロジェクトで行われていました。 WebJob の場合、キューの処理を自動化するだけ特定の属性を使用できます。 ここで行うべきことは、受信部分と送信部分の両方で同じストレージ接続文字列とキュー名の両方を使用していることを確認するだけです。

// This function will get triggered/executed when a new message is written 
// on an Azure Queue called queue.
public static void ProcessQueueMessage(
    [QueueTrigger(SiteModificationManager.StorageQueueName)] 
    SiteModificationData request, TextWriter log)
{
    Uri url = new Uri(request.SiteUrl);

これ以上簡単にすることはできません。 キュー名が一致していることを確認するため、SiteModificationManager.StorageQueueName を両側で使用していることに注意してください。

サイトに実際の構成を適用する

この参照実装では、次のカスタマイズを各 OD4B サイトに実行しています。

  • OD4B サイトで常に表示される会社ポリシー メッセージを追加します
  • サイト コンテンツ ページからサブ サイト リンク の作成オプションを非表示にする
  • 会社のブランド化と一致するよう OD4B サイトにカスタム テーマを適用する

会社のポリシーとサブサイトの作成リンクの非表示は、特定の JavaScript ファイルを参照してサイト レベルにカスタム ユーザー アクションを追加する、いわゆる JavaScript 埋め込みパターンを使用して実現されています。これにより、すべてのページ要求で実行されます。 つまり、任意のページ内の任意の要素を追加、削除、または更新することで、クライアント側テクノロジを使用してページ処理を制御できます。 この方法を使用すると、カスタム マスター ページを導入する必要はありません。これは、特に必要な変更がほとんどない場合に、長期的なメンテナンス コストが大幅に増加する可能性があります。

カスタム テーマを使用する 2 番目の操作では、追加のファイルをいくつかサイトにアップロードし、それらをテーマ設定として使用するように設定する必要があります。 機能フレームワーク要素の関連付けによる将来の複雑な問題を回避するために、必要なすべてのファイルをサイトにアップロードするには、厳密に CSOM を使用します。 CSOM を使用して SharePoint にファイルをアップロードするのは非常に簡単なので、これは間違いなく自動化を実行する最も簡単な方法であり、サンドボックス ソリューションへの xml 固有の構成の依存関係について心配する必要はありません。OD4B の実際のサイト構成方法を次に示します。Configuration.Async.Common.SiteModificationManager クラス。 必要な操作の一部を簡略化するために、Office 365 Developer PnP コア コンポーネントを使用していることに注意してください。

また、個人用 OD4B サイトをカスタマイズするたびに、JS の新しいバージョンをルート サイト コレクションにアップロードしていることにも注目してください。 これは間違いなく最適なソリューションではなく、この参照ソリューションのわかりやすくするためにあります。 アプリのインストール時に 1 回だけ実行されるように、JavaScript ファイルのアップロード操作をアプリの Installed イベントに追加することを検討できますが、その場合は、その JS ファイルに対する更新プログラムで追加作業を行う必要があります。

// This function will get triggered/executed when a new message is written 
// on an Azure Queue called queue.
public static void ProcessQueueMessage(
    [QueueTrigger(SiteModificationManager.StorageQueueName)] 
    SiteModificationData request, TextWriter log)
{
    Uri url = new Uri(request.SiteUrl);
  
    //Connect to the OD4B site using App Only token
    string realm = TokenHelper.GetRealmFromTargetUrl(url);
    var token = TokenHelper.GetAppOnlyAccessToken(
        TokenHelper.SharePointPrincipal, url.Authority, realm).AccessToken;

    using (var ctx = TokenHelper.GetClientContextWithAccessToken(
        url.ToString(), token))
    {
        // Set configuration object properly for setting the config
        SiteModificationConfig config = new SiteModificationConfig()
        {
            SiteUrl = url.ToString(),
            JSFile = Path.Combine(Environment.GetEnvironmentVariable
                ("WEBROOT_PATH"), "Resources\\OneDriveConfiguration.js"),
            ThemeName = "Garage",
            ThemeColorFile = 
                Path.Combine(Environment.GetEnvironmentVariable
                ("WEBROOT_PATH"), "Resources\\Themes\\Garage\\garagewhite.spcolor"),
            ThemeBGFile = 
                Path.Combine(Environment.GetEnvironmentVariable
                ("WEBROOT_PATH"), "Resources\\Themes\\Garage\\garagebg.jpg"),
            ThemeFontFile = "" // Ignored in this case, but could be also set
        };

        new SiteModificationManager().ApplySiteConfiguration(ctx, config);
    }
}

明らかに、必要な操作はお客様のビジネス要件に大きく依存しています。 「Office 365 Developer パターンおよびプラクティス」から CSOM ベースの操作を使用したさまざまなパターンと方法を見つけることができます。

WebJob ベースのソリューションについてのその他の注意事項

Azure での WebJob 開発に関連するその他の注意事項をいくつか示します。 これは、間違いなく Office 365 のカスタマイズ全体で広く使用される、非常に強力な手法です。 WebJob テクノロジに基づいた新しいソリューションや拡張ソリューションが、Office 365 Developer パターンおよびプラクティスのプログラムにも追加されていることを確認できます。

WebJob とカスタマイズ プロセスのデバッグ

一般的にコードでは、最初にコンソール アプリケーションを使用した必要なコードのテストや、Visual Studio でのプロジェクトのテストに集中できるよう、実際の操作を実際の最終的な実行 プロセスの外に配置することをお勧めします。 この方法では、最終的なプロセス (ここでは WebJob) に実際にフックする前に、実際のビジネス ロジックが完全に機能していることを確認できます。 この参照ソリューションでは、すべてのビジネス コードを OD4B.Configuration.Async.Common.SiteModificationManager クラスに配置し、そここからさまざまな場所から呼び出しました。

これは、開発期間中に OD4B を使用できることを意味しました。Configuration.Async.Console.Reset コンソール アプリケーションを使用して、サイトから必要な回数だけカスタマイズをテストおよびリセットして、ビジネス ロジックが完全に強固であることを確認します。 これは、SharePoint アドイン モデルや Azure 開発とは関係なく、使用するテクノロジに関係なく、実用的な段階的な開発プラクティスです。 MCM for SharePoint 認定トレーニングの講演者だった時、私はこれを NKOTB メソッドと呼んでいたが、それは業界標準の用語ではない:-)

Visual Studio 2014 Update 4 では、WebJobs のデバッグの側面から、優れた改善点が導入されました。 新しく導入された Azure 接続およびプロジェクト テンプレートでは、Azure 側で実行する WebJob でリモート デバッグを実際に実行できます。 WebJob を Azure に展開する必要があり、その後で [サーバー エクスプローラー] で WebJob インスタンスを右クリックし、コンテキスト メニューから [デバッガーの接続] を選択してデバッグ セッションを開始できます。

[サーバー エクスプローラー] では、ネストされたオブジェクトが [Web サイト]、[vesaj-od4bconf]、[Web ジョブ]、[連続番号]、OD4BConfigurationAsyncWebJob

参照ソリューションのキューに適切な形式のメッセージを送信するためのテスト担当者もあります。 OD4B。Configuration.Async.Console.SendMessage プロジェクトは、WebJob プロセスをデバッグする機会を得るために、アプリ パーツを任意の場所に強制的にデプロイすることなく作成されました。 これは、プロセス全体を段階的にデバッグしてテストすることで、再び戻ってきました。

WebJob 環境変数

WebJobs の興味深い点の 1 つは、Azure Web サイトで実行されていても、実行場所は Azure の通常の Web サイトとは若干異なるということです。 追加のファイルまたは資産を WebJob と共に Azure に展開し、WebJob コードで従来の相対パスを使用してこれらの資産を直接参照できると想定していた場合、課題に直面する可能性があります。

この場合、カスタム テーマに対し 1 つの JavaScript ファイルといくつかのファイルがあり、それらは必要に応じて SharePoint サイトにアップロードができるよう、Azure Web サイトに展開されていました。 特定の Web サイトの下でファイルの分岐を展開すると、Azure でそれらのファイルを表示できます。

[サーバー エクスプローラー] では、ネストされたオブジェクトが [Web サイト]、[vesaj-od4bconf]、[ファイル]、[リソース]、[テーマ]、[Garage] の順に展開されていて、[Garage] フォルダー内のファイルが表示されています。

通常、Azure Web サイトでは、次の形式を使用してこれらのファイルを参照できていました。

string path = HostingEnvironment.MapPath(
    string.Format("~/{0}", "Resources/OneDriveConfiguration.js"));

ただし、WebJobs は別の場所で実行され、IIS のコンテキストではないため、WebJob プロセスのコンテキストからマッピングを行うことはできず、ファイルに対する上記の参照は機能しません。 ここで、WebJob 固有の環境変数が役立ちます。 参照ソリューションのケースでは、WebJob 固有の環境変数 WEBROOT_PATH を使用して、関連付けられた Web サイト フォルダーのアクセス権を取得しました。

string jsFile = Path.Combine(
    Environment.GetEnvironmentVariable("WEBROOT_PATH"), 
    "Resources\\OneDriveConfiguration.js");

また、役立つ可能性がある WebJobs 用の環境変数が他にもいくつかあります。 コードを使用して別の環境変数をチェックすることができ、GitHub にはこのための優れた参考資料があります。

ソリューションとアクションを示すビデオ

このビデオはソリューションの構造の説明や、Office 365 環境で使用して OneDrive for Business サイトを変更する方法など、実践でのソリューションを示しています。

PnP サンプル

適用対象

  • Office 365 マルチテナント (MT)
  • Office 365 専用 (D) 一部
  • SharePoint 2013 オンプレミス - 一部

専用およびオンプレミスの場合のパターンは SharePoint アドイン モデル手法と同じですが、使用可能なテクノロジは異なる可能性があります。