WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

Safari は downlevel browser?

by WebSurfer 2010年7月30日 23:14

ブラウザ Safai

Windows 版でしかチェックしていませんが、最新の Safari 5.0.1 は ASP.NET 3.5 でも依然として downlevel(Internet Explorer 4.0 より前のブラウザ)として扱われているようです。

(2014/3/3 追記: 現時点の ASP.NET によるブラウザ判定で Safari が downlevel と判断されることはありません。ただし、ASP.NET 2.0, 3.0, 3.5 での Menu コントロールについては話が別です。詳しくは下の「2014/3/3 追記」を見てください)

2 年ほど前、Menu コントロールの子メニュー/孫メニューをポップアップするスクリプトが生成されないことでこの問題を知りました。

2006 年の初めには Connect にレポートされていますが、そのままになっているようです(ただし、ASP.NET 4.0 でどうなったかは未確認です)。(2011/8/22 追記: ASP.NET 4 では対処済みでした。下の追記を参照)

ニュースグループ Microsoft Discussion Groups に応急処置が書いてあったんですが、すでにリンク切れになっているので、ここにそれを書いておきます。

応急処置は、簡単に言うと、Page クラスの PreInit イベントで "uplevel" であると誤魔化すということです。

具体的には、PreInit イベントで HTTP ヘッダーの中の User-Agent を調べ、Safari という文字列があったら、そこで Page.ClientTarge プロパティを uplevel に設定するというものです。

つまり、以下のようなクラスを作って、"uplevel" に誤魔化す必要のあるページはこれを継承してページを実装するということです。

public class CBaseMasterEvents : System.Web.UI.Page
{
  public CBaseMasterEvents()
  {
    Page.PreInit += new EventHandler(CBaseMaster_PreInit);
  }

  private void CBaseMaster_PreInit(object sender, EventArgs e) 
  { 
    if (Page.Request.Browser.Browser.Contains("Safari")) 
    {
      Page.ClientTarget = "uplevel"; 
    } 
  } 
}

ただし、この応急処置を適用すると、他の部分で互換性の問題が出る恐れがありますので、十分な検証が必要だと思います。


------ 2011/8/22 追記 ------

原因は ASP.NET 2.0 の CONFIG フォルダにあるブラウザ定義ファイル *.browser に Safari 用がないからでした(downlevel と定義されていうわけではなかったです)。それは Chrome も同じで、Menu コントロールは適切に表示されません。

(2014/3/3 追記: 「Menu コントロールは適切に表示されません」という表現は間違ってました。詳しくは下の「2014/3/3 追記」を見てください)

ASP.NET 4 の CONFIG フォルダには safari.browser, chrome.browser が含まれており、Menu コントロールは IE と同様に適切に表示されます。


------ 2014/3/3 追記 ------

ASP.NET 2.0, 3.0, 3.5 用のブラウザ定義ファイルは %windir%\Microsoft.NET\Framework\v2.0.50727 (ASP.NET 4 用は \v4.0.30319)の CONFIG\Browsers サブフォルダにあります。

昔のブラウザ定義ファイルは分かりませんが(Windows Update でアップデートされるので)、2014/3/3 時点では mozilla.browser ファイルの中に id="Safari" という browser 要素があって、Safari および Chrome はその定義の適用を受けます(継承元の Default ← Mozilla ← Gecko の定義も)。

その browser 要素の中に controlAdapters 要素(使用するコントロールアダプタを定義)が含まれており、それが Menu サーバーコントロール用のアダプタに、以下のように MenuAdapter クラス を使うよう指定しています。

<controlAdapters>
 <adapter 
  controlType="System.Web.UI.WebControls.Menu"
  adapterType="System.Web.UI.WebControls.Adapters.MenuAdapter" />
</controlAdapters>

このため、ASP.NET 2.0, 3.0, 3.5 では、Menu コントロールが html コードにレンダリングされた時、Safari, Chrome は span 要素、IE, Firefox は table 要素になり、ブラウザ上での動作が大幅に異なるという結果になります。

一方、ASP.NET 4 の CONFIG\Browsers サブフォルダには safari.browser, chrome.browser という専用のブラウザ定義ファイルがあり、その中にも継承元の Default ← Mozilla ← WebKit にも controlAdapters 要素は含まれていません。

それゆえ、ASP.NET 4 では、Menu コンロトールは IE, Forefox, Safari, Chrome いずれも同じ table 要素としてレンダリングされ、ブラウザ上での動作は同じになります。

(注)ASP.NET が CONFIG\Browsers サブフォルダのブラウザ定義ファイルの通りにブラウザを判定するかと言えば、必ずしもそういうわけではないので注意してください。ASP.NET はブラウザ判定ルーチンを System.Web.dll の中に持っており、既定ではそれを使っているそうです。詳しくは MSDN Blog の記事 ASP.NET の IE10 対応について を見てください。


------ 2016/1/12 追記 ------

MaintainScrollPositionOnPostBack(ポストバック前後で上下左右のスクロール位置を維持する機能)も ASP.NET 2.0, 3.0, 3.5 ではブラウザ定義の問題で Safari, Chrome では動きませんでした。(ASP.NET 4 では問題なし)

スクロール位置を維持する仕組み、Safari, Chrome のブラウザ定義は何故ダメか、その対処方法については別の記事「ポストバック前後でスクロール位置維持」に書きましたので、興味がありましたら見てください。

Tags: ,

ASP.NET

接続文字列の取得方法

by WebSurfer 2010年7月30日 12:36

SQL Server などの接続文字列は、ソース中にハードコーディングせず、Web アプリなら web.config ファイルに、Windows アプリなら Settings.settings ファイルに格納しておき、そこから取得します。

その接続文字列を取得するコードは以下のようになります。

Web アプリケーション

string connectionString = 
  ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString;

Windows アプリケーション

string connectionString = 
  Properties.Settings.Default.MyDB;

上記で、MyDB は接続文字列を定義する際に自ら名づけた名前で、当然任意に別名をつけることができます。例えば MyDB と名づけると、web.config, Settings.settings ファイルの中では以下のようになります。

web.config

<connectionStrings>
  <add name="MyDB"
       connectionString="Data Source= ..."
       providerName="System.Data.SqlClient" />
</connectionStrings>

Settings.settings

<Settings>
  <Setting Name="MyDB" Type="(Connection string)" Scope="Application">

  ・・・中略・・・

  </Setting>
</Settings>

正確に憶えていないので、その度に昔のコードを調べるという面倒なことをしていましたが、自分のブログの索引からも見つけられるように書いておきました。

Tags:

ADO.NET

Forms 認証のタイムアウト判定

by WebSurfer 2010年7月30日 08:37

あまり役に立たないかもしれませんが、ASP.NET 標準の Forms 認証システムで、認証チケットが期限切れになっているかどうかを判定するという話です。なお、前提条件としてクッキーが有効になっていることを想定しています。

例えば、一旦認証を受けたユーザーが、ログオフせず、ブラウザを立ち上げたまま、長時間席を外すなどして、タイムアウトに設定した時間を超えてアクセスしなかった場合を考えてください。

ユーザーが席に戻ってきて再度アクセスした場合、アクセスしたページに匿名アクセスを許可してなければ、ログインページにリダイレクトされるというのが Forms 認証の通常の設定です。

そこで、ユーザーに認証チケットが期限切れとなっていることを知らせるにはどうしたらいいでしょうか?

User.Identity.IsAuthenticated ではダメです。認証されているか否かは判定できますが、認証チケットが期限切れかどうかはわかりませんから。

一旦認証を受けたが、認証チケットが期限切れになっているというのは、サーバー側では以下の条件で判定できるはずです。

  • 要求 HTTP ヘッダーに認証クッキーが含まれる。
  • 認証クッキーの中の認証チケットが期限切れ。

認証クッキーと認証チケットは違うことに注意してください。クッキーはチケットの入れ物に過ぎません。認証チケットの有効期限は、認証クッキーの Value の中に入っている情報の一つです。HttpCookie.Expires ではありません。

一般的に、一旦認証クッキーの発行を受ければ、セッションが切れない限り、次の要求の時にブラウザはサーバーにクッキーを送ります。

認証クッキーを取得し、その Value を復号して認証チケットを取得し、ユーザー名、期限切れか否かなどの情報を取得できます。それで上記の 2 つの条件を確認できます。例えば、ログインページにリダイレクトされたときに期限切れを知らせる場合は、Global.asax で以下のようにします(もしくは HTTP Module を作る)。

void FormsAuthentication_Authenticate(object sender, 
  FormsAuthenticationEventArgs args)
{
  // "/login.aspx" は実際に合わせて適宜変更してください。
  if (Request.CurrentExecutionFilePath != "/login.aspx")
  {
    return;
  }

  string cookieName = FormsAuthentication.FormsCookieName;
  HttpCookie authCookie = Context.Request.Cookies[cookieName];

  if (null == authCookie)
  {
    return;
  }

  FormsAuthenticationTicket authTicket = null;
  try
  {
    authTicket = FormsAuthentication.Decrypt(authCookie.Value);
  }
  catch (Exception ex)
  {
    return;
  }

  if (null == authTicket)
  {
    return;
  }

  if (authTicket.Expired)
  {
    // 知らせるための処置を書く。例えば下記:
    Context.Response.Write("<h1><font color=red>" +
      "Forms Authentication Ticket Expired" +
      "</font></h1><hr>");
  }
}

認証チケットが期限切れの場合、FormsAuthenticationModule が認証クッキーを削除しているようで、タイミングによっては認証クッキーは取得できないので注意してください。

従って、認証クッキーを取得できるのは、FormsAuthenticationModule.Authenticate イベント以前のタイミングになります。

Tags: ,

Authentication

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  2018年1月  >>
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910

View posts in large calendar