SharePoint Server 2013 ビュー ステートの注意点

こんにちは SharePoint サポートの森 健吾 (kenmori) です。

SharePoint Server 2013 / SharePoint Online では分散キャッシュが導入されました。

比較的身近な部分でも使用されており、その 1 つにビューステート キャッシュ (ViewStateCache) があります。詳細は後ほど記載しますが、ビュー ステートは ASPX ページにおいて、すべてのページにおいて基盤として使用されています。
SharePoint 2013 / SharePoint Online からは、このビュー ステートがサーバー側でキャッシュされるということで、様々な影響があります。今回の投稿では、特に開発者向けとして、このビューステートの動作がどのように変更されたかなどを説明し、注意点についてご説明します。

現象

まずは例を用いてご説明いたします。

 1. 下記のようなページを表示して、31 分以上置いておきます。

2. その後、ボタンクリックなどを実施します。

3. 上記のようなページとなります。

 

 

DropDown の選択肢や、ラベルに累積的に追加していた文字列が消失しました。

SharePoint Server 2013 に Web ソリューションを展開した場合、ほとんどの状況において、この影響を受けることになります。開発者は、このような状況が発生する原因について正確に理解をしておく必要があります。

 

 

実装コード

 

上記例にして使用したコードを記載します。

Visual Studio 2013 にて、空の SharePoint プロジェクトを作成し、新しい項目の追加でアプリケーション ページを追加します。そして、下記のようなコードを実装します。

 

 

    public partial class ViewStateTest : LayoutsPageBase

    {

        protected void Page_Load(object sender, EventArgs e)

        {

            if (!this.IsPostBack)

            {

               DropDownList1.Items.Add("AAA");

                DropDownList1.Items.Add("BBB");

                DropDownList1.Items.Add("CCC");

                DropDownList1.Items.Add("DDD");

 

            }

            Label1.Text += "<BR>" + DateTime.Now.ToString();           

 

        }

 

        protected void Button1_Click1(object sender, EventArgs e)

        {

 

            Label1.Text += " " + DropDownList1.SelectedValue;

        }

    }

 

ドロップダウン リストの選択肢項目は、初回ロード時 (!this.IsPostBack) のみに描画されます。また、ラベルに表示されるテキスト情報は、これまでの累積的な操作の結果 (Label1.Text += ...) が格納される動作として実装されています。

今回の現象は、これまで格納されたビュー上に反映された情報がサーバー側でクリアされてしまうことに起因します。クリアされたビュー ステートの上で、POST 要求が処理されている状況となります。

 

原因

 

SharePoint Server 2013 からは、分散キャッシュが導入されました。この機構を使用して、ビュー ステートに格納されていた情報を、サーバー側分散キャッシュ内に ビュー ステート キャッシュ (ViewStateCache) として格納される動作となり、その代わりに HTML フォーム内のビュー ステートに格納されなくなりました。

 

この ViewState キャッシュは、既定で 31 分を上限とし、それ以上ユーザー アクセスがなく経過したものはサーバー側のキャッシュから自動的に削除されます。そのため、ページを操作するまでに 31 分程時間を空けてしまった場合、サーバー上のキャッシュ上からビュー ステートが消失しており、クライアントからはビュー ステートが送信されないため、これらの状態がない前提で処理が動作します。結果的に、上記画面キャプチャにて紹介した通り、ビュー上に表示された項目が消失してしまいます。

 

<診断ログ>

ViewState キャッシュが消失した場合、サーバー側には下記のログが記録されます。

 

08/15/2014 23:54:46.55 w3wp.exe (0x4AF4) 0x43B8 SharePoint Foundation General ajb4t Monitorable ViewStateLog: Failed to find entry in cache: https://kenmori4-52/_layouts/15/SPAppPage/ViewStateTest.aspx, 2fd6b501-061d-4166-9f70-a91c37945d07 6cc5ae9c-4644-d0e4-46ae-6594c5d843c9

 

 

補足 1 : ASP.NET におけるビュー ステートについて

 

ASP.NET は、Web アプリケーション上で Windows フォーム アプリケーション同様 RAD 開発を実施するために、様々なテクノロジーを導入しました。

Windows フォームと HTML Web フォームの一般的な相違点としては、HTML Web フォームは HTTP 要求と応答のやりとりからページを生成するため、これまでの累積的な状態を管理することができない点があります。

 

例えば、今回のコード例のように初回表示時に追加したドロップダウン リストの項目や、前回ラベルに追記した文字列を、その後 2 回、 3 回とポストバックした際にも以前の状態を保持する必要があります。

これらの情報を保持するために、ASP.NET はこれまでにビュー ステートと呼ばれる領域を用意して、状態を管理してきました。

 

このビュー ステートは、Web フォーム上の HTML hidden データに _VIEWSTATE という名前の隠しデータを保持し、ボタンクリックなどの操作時 (すなわち POST バックする際) において毎回送信し、サーバーからもこの内容を返し続けることにより状態を保持している機構となります。

Web は逐次 HTTP の要求と応答の内容で描画されますため、継続的な状態の管理を実施する仕組みは本来ありません。これを _VIEWSTATE というデータを毎回送受信する機構によって実現しているのが、ビューステートとなります。下記図を参考にしてください。

下記のページに詳細が記載されておりますので、ご参考にしてください。

 

タイトル : ASP.NET のビュー ステートの理解

アドレス : https://msdn.microsoft.com/ja-jp/library/ms972976.aspx

 

補足 2 : 分散キャッシュ ビュー ステート キャッシュについて

 ASP.NET は上記の機構を実装することで、Web フォームに状態管理を実施できる基盤を提供しました。しかし、その弊害として毎回追記格納される _VIEWSTATE 値によって HTTP パケット容量が増え、性能等への問題に及ぶこともこれまで発生してきました。
この状況を防ぐために、用意された機構が AppFabric Caching Service、分散キャッシュ サービスにおける ViewState キャッシュとなります。

 

ViewState キャッシュは、AppFabric Caching Service の機構から下記のような設定とされています。

 

 

PS:> Get-AFCache | % {Get-AFCacheConfiguration -CacheName $_.CacheName}

ただし、SharePoint はいくつかの設定値については独自設定を実装しております。

例えば、ViewState キャッシュの TTL は、セキュリティ検証のタイムアウト値 (SPWebApplication.FormDigestSettings.Timeout + 1 分) を既定値としております。そのため、既定では 31 分でタイムアウトする設定となっております。

 

 

対処策

 

上記の問題を対処するための一般的な対処策は下記のいずれかとなります。

 

1. Timer コントロールを使用して定期的な通信を実施する。

ASPX ページ上に下記コントロールを配置して、定期的な (例. 5 分に 1 回など) ポーリングを実現する。

 <asp:Timer ID="Timer1" runat="server"></asp:Timer>

タイトル : Timer クラス
アドレス : https://msdn.microsoft.com/ja-jp/library/system.web.ui.timer(v=vs.110).aspx

  

2. ViewState キャッシュを無効にする。

SharePoint 管理シェルを起動して、下記のコマンドレットを実行します。

 

$contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService

 

$contentService.ViewStateOnServer = $false

 

$contentService.Update()

 

注意

ファーム上のすべてのページの ViewState キャッシュが無効化されるため、パフォーマンスに多大な影響を与えます。そのため、十分なテストを実施した上で適用ください。

 

3. セキュリティ検証のタイムアウトを延ばす。

SharePoint サーバーの全体管理画面から Web アプリケーションの管理画面に遷移し、全般設定をクリックします。
下記赤枠の設定値に指定した値を延長して [OK] をクリックします。

PowerShell で実行する場合は以下となります。

 

$webApp = Get-SPWebApplication https://sharepoint

$webApp.FormDigestSettings.Timeout = "0:30"

$webApp.Update()

 

注意

Web アプリケーション配下すべてのページの ViewState キャッシュの期限が延長されるため、全体のキャッシュ サイズに影響を与えます。そのため、十分なテストを実施した上で適用ください。

 

参考情報

以下の情報は、今回ご紹介した現象に関連した情報となりますので、ご参考にしていただけますと幸いです。

タイトル : AppFabric Caching and SharePoint: Concepts and Examples (Part 1)
アドレス : https://blogs.msdn.com/b/besidethepoint/archive/2013/03/27/appfabric-caching-and-sharepoint-1.aspx

タイトル : AppFabric Caching (and SharePoint): Configuration and Deployment (Part 2)
アドレス : https://blogs.msdn.com/b/besidethepoint/archive/2013/03/27/appfabric-caching-and-sharepoint-2.aspx

AppFabric には下記のような問題が報告されております。状況を問わず、もし何か問題に直面した場合は、下記の修正プログラムを適用することをご検討ください。

タイトル : Microsoft AppFabric 1.1 for Windows Server 累積的更新プログラム 5 (KB2932678)
アドレス : https://www.microsoft.com/ja-JP/download/details.aspx?id=42281

 

補足となりますが SharePoint Server 2013 のリッチテキスト コントロールについては、ユーザーの編集時間が 30 分を超えることは通常想定されます。

そのため、Serivce Pack1 にてリッチテキストが配置されているページに限定して ViewState キャッシュを使用せず、これまで通り _VIEWSTATE を経由してビューの状態を管理するように修正されました。

 

今回の投稿は以上になります。