WebSurfer's Home

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

W3C 検証にパスしない

by WebSurfer 2011年6月13日 22:58

ページングする際に &page=n(n はページ番号)というクエリ文字列がページャーのリンクの URL に追加 される場合があります。しかしながら、& のままでは W3C Markup Validation に通りません。HTML エンコー ドして & にする必要があります。この問題には今まで気がつきませんでした。(汗)

この問題を解決するには、User controls/PostList.ascx.cs の InitPaging メソッドを以下のように修正しま す。

private void InitPaging()
{
  string path = Request.RawUrl;

  if (!(Request.QueryString["year"] != null || 
    Request.QueryString["date"] != null))
    path = REMOVE_DEFAULT_ASPX.Replace(path, string.Empty);

  if (path.Contains("?"))
  {
    if (path.Contains("page="))
    {
      int index = path.IndexOf("page=");
      path = path.Substring(0, index);
    }
    else
    {
      path += "&";
    }
  }
  else
  {
    path += "?";
  }

  int page = GetPageIndex();
  string url = path + "page={0}";

  // 下記の追加のみ
  url = url.Replace("&", "&");

  hlNext.HRef = string.Format(url, page);		
  hlPrev.HRef = string.Format(url, page + 2);

  if (page == 0)
  {
    hlNext.Visible = false;
  }
  else
  {
    (Page as BlogBasePage).AddGenericLink(
      "next", 
      "Next page", 
      hlNext.HRef);
    Page.Title += " - Page " + (page + 1);
  }

  if (hlPrev.Visible)
    (Page as BlogBasePage).AddGenericLink(
      "prev", 
      "Previous page", 
      string.Format(url, page + 2));
}

Tags:

BlogEngine.NET

BlogEngine.NET 2.0 の導入

by WebSurfer 2011年6月11日 15:49

今年の 1 月にリリースされた BlogEngine.NET バージョン 2.0 を導入しました。

BlogEngine.NET 2.0 の導入

と言っても、既存のバージョン 1.6.1 のブログ(ここがそれです)をアップグレードしたわけではなく、ここは 1.6.1 のまま残しておいて、BlogEngine2 という名前の別アプリケーションとして構築しました。

まだ試験段階ですので、試験のための記事しかありませんし、スタイルもデフォルトのままですが、以下の URL から入れます。

http://surferonwww.info/BlogEngine2/default.aspx

今回は、、データストアとして、今まで使っていなかった MySQL を使うことにしました(現在のホスティングサービスでは SQL Server と MySQL がそれぞれ 300MB ずつ使えます)。ちなみに、既存のブログ(ここ)は SQL Server を使用しています。

Forms 認証にはサイト内で共通の SQL Server を利用した SqlMembershipProvider, SqlRoleProvider を使って、サイト内でアプリケーション間を移動するとき再認証を受けなくても済むようにしました。

とりあえず見つけた問題はすべて解決できましたので、どのような問題があったのか、どう解決したのかを備忘録として書いておきます。

データベース構築の問題

BlogEngine.NET/setup/MySQL フォルダの中にデータベースを構築するためのスクリプトファイルが用意されており、これを走らせて必要なテーブルを生成します。このスクリプトは各テーブルを DEFAULT CHARSET=latin1 で作るように指定しています。(latin1 が MySQL のデフォルトらしい)。

一方、MySQL 全体とデータベースのキャラクターセットはすべて UTF-8 で設定しており、その状態で日本語を使うと、Incorrect string value というエラーが出て投稿できませんでした。

結局 latin1 で作ったデータベースはドロップして、スクリプトの DEFAULT CHARSET=latin1 を utf8 に書き換えてテーブルを作り直して解決しました。

バージョン 1.6.1 の諸問題

以下の致命的な問題(詳細はリンク先の記事を参照ください)はすべて解消されていました。(1) については Encoding.Default が Encoding.UTF8 に変更されていました。(2), (3) は大幅にコードが書き換えられており、1.6.1 で問題だったコードは見つからず、実際に試して不具合は出ませんでした。

(1) 日本語の文字化け

(2) SyntaxHighlighter のコードの間違い

(3) reCaptcha のコードの間違い

以下は見栄えなどの軽微な問題です。1.6.1 の場合と同様な修正が必要でした。問題の詳細および修正方法はリンク先の記事を参照ください。

(4) 各記事の左上の日付の表示が 31. 5月 2010 12:15 のようになる

(5) Search の結果、タイトルの表示が「の検索結果 'XXXX'」となる

(6) 「関連するブログ」でテキストの折り返しがされない

(7) ウィジェットのカレンダーが月曜日から始まっている

(8) タイトルが 5月 31. 2011 のように表示される

以下の問題は 1.6.1 の場合(詳細はリンク先の記事を参照ください)より悪化していました。詳細は CodePlex の Discussions のページにアップしました。まだ検証中ですので、サーバーには修正済みファイルはアップしていません。検証が終わって修正版をサーバーにアップしたら、詳しい話を書きます。

(9) Tag cloud 中の日本語の Tag の問題

最後に、以下の問題は、SyntaxHighlighter のバージョンが変わったためか、解消されていました。

(10) SyntaxHighlighter とフラグメント識別子

------------ 2011/6/14 追記 ------------

上の (9) で書いた日本語の Tag の問題の解決策は BlogEngine.NET 2.0 の Tag cloud の問題 に詳細を書きました。興味がありましたらそちらを参照ください。

Tags:

BlogEngine.NET

jQuery AJAX と Web サービス

by WebSurfer 2011年6月4日 21:05

注意:
今頃になって何ですが、 jQuery Ajax の仕様が変わって、バージョン 1.5 以降では dataFilter に指定したメソッドで JSON 文字列を JavaScript オブジェクトにパースできなくなりました。詳しい説明はこの記事の下の方にある「2013/8/9 追記」を見てください。

先の記事 ASP.NET AJAX と Web サービス では、AJAX 対応 ASP.NET Web ページから Web サービスにアクセスする例を書きましたが、この記事では jQuery を使って AJAX 通信を行う例を書きます。

ASP.NET .aspx ファイルでない Web ページでは、ScriptManager コントロールを使用できません。従って、先の記事に書きましたプロキシクラスは利用できません。

この記事では、静的な html ページから、jQuery を使った AJAX 通信を行い、Web サービスからデータを JSON 形式で取得する方法について説明します。

基本的には、先の記事で紹介したページ Handling JSON Arrays ... に記載されていたサンプルとほぼ同じです。

ただし、d パラメータ有り(.NET 3.5 以降)/無し(.NET 2.0 以前)の両方に対応するためのコードと、ブラウザに実装されているネイティブの JSON パーサーを使えるように手を加えました。

それらの機能を追加しても、先の記事で書いた ScriptManager を利用してプロキシを自動生成する場合と同等以上に簡単と思いますがいかがでしょう。マイクロソフトが jQuery を Visual Studio 2010 に統合した理由が分かるような気がします。

以下のコードは、実際に動かして試せるよう 実験室 にアップしましたので、興味のある方は試してみてください。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>jQUery AJAX and Web Service</title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript">
  </script>
  <script type="text/javascript">
  //<![CDATA[
  function getCars() {
    $.ajax({
      type: "POST",
      url: "097_jQueryAjaxAndWebService.asmx/GetCarsByDoors",
      data: '{"doors":' + $("#ddlDoors").val() + '}',

      // JSON を期待する場合必須(下の追記参照)
      contentType: "application/json; charset=utf-8",

      // success ハンドラで d の有無を判定しないで済むように
      // dataFilter を使う。
      // その際、dataType: "json" は不用。
      // dataType は応答データをどのように deserialize する
      // かを jQuery に指示するもの。"json" が指定されてい
      // ると jQuery は内部的に eval メソッドを使って 
      // deserialize する。dataType: "json" が指定してある
      // と  dataFilter と二重に deserialize されてしまう。

      dataFilter: function (data) {
        // ブラウザの native JSON パーサがあればそれを
        // 使う(セキュリティ対策)  
        var msg = "";            
        if (typeof (JSON) !== 'undefined' &&
          typeof (JSON.parse) === 'function') {
          msg = JSON.parse(data);
        } else {
          msg = eval('(' + data + ')');
        }

        // .NET 3.5 で追加された d パラメータの処置。
        if (msg.hasOwnProperty('d')) {
          return msg.d;
        } else {
          return msg;
        }
      },
      success: function (cars) {
        $('#output').empty();
        $.each(cars, function (index, car) {
          $('#output').append(
            '<p><strong>' + car.Make + ' ' +
            car.Model + '</strong><br /> Year: ' +
            car.Year + '<br />Doors: ' +
            car.Doors + '<br />Colour: ' +
            car.Colour + '<br />Price: £' +
            car.Price + '</p>');
          });
        },
        // failure を error に訂正。下の追記参照。
        // failure: function (msg) {
        //   $('#output').text(msg);
        // }
        error: function (jqXHR, textStatus, errorThrown) {
          $('#output').text('textStatus: ' + textStatus + 
            ', errorThrown: ' + errorThrown);
        }
    });
  }
  //]]>
  </script>
</head>
<body>
  <div>
    Number of doors: 
    <select name="ddlDoors" id="ddlDoors">
	  <option value="2">2</option>
	  <option value="3">3</option>
	  <option value="4">4</option>
	  <option value="5">5</option>
    </select>   
  </div>
  <input type="button" 
    id="Button1" 
    value="Get Cars" 
    onclick="getCars();" /> 
  <div id="output"></div>
</body>
</html>

------ 2011/9/3 追記 ------

上記コードの $.ajax のオプション設定の中の failure は、参考にしたサイト Handling JSON Arrays returned from ASP.NET Web Services with jQuery のコードをコピペしたものですが、どうも間違っているようです。

jQuery の本家のサイトの jQuery.ajax() の説明を見ると、オプション設定の中に failure というのはなく、error が正しいはずです。実際に試してみましたが、失敗しても制御は failure に設定した function には飛ばず、error に設定した function に飛びました。

という訳で、訂正しました。やはり、何も考えずにコピペして、しかも検証もしないというのはダメですね。(汗)

----- 2012/7/16 追記(2014/3/24 一部訂正) -----

jQuery Ajax で contentType: "application/json; charset=utf-8" を設定しないと、Web サービスのメソッドから返されるデータは xml 形式になってしまいます。結果、パースエラーになり error に設定したメソッドに制御が飛びます。

jQuery のサイトの API Documentation の説明によると、jQuery.ajax() の contentType のデフォルトは 'application/x-www-form-urlencoded; charset=UTF-8' とのことですが、何も設定しないと要求ヘッダには Content-Type: そのものが設定されません(1.4.1 でしか試してませんが)。その場合でも、Web サービスのメソッドが返すデータ合は Xml 形式になります。

なお、要求ヘッダが Content-Type: application/x-www-form-urlencoded もしくは何も指定しない場合は ScriptMethodAttribute クラスResponseFormat プロパティ を Json に指定しても無視されます。

jQuery.post() や jQuery.get() では contentType が指定できないので注意してください。

----- 2012/12/23 追記 -----

POST する JSON 文字列が {doors:5} となっており、正しく {"doors":5} となってなかったので以下のように訂正しました。

data: "{doors: " + $('#ddlDoors').val() + "}",
 ↓↓↓
data: '{"doors":' + $("#ddlDoors").val() + '}',

以前の形式でも問題なく Web サービスのメソッドは呼び出され、応答は正しく帰ってきましたが、気分の問題ということで直しました。(笑)

------ 2013/8/9 追記 ------

jQuery バージョン 1.4(多分それ以前のバージョンも)では、dataFilter のメソッドの戻り値が string 型以外のときは、そのまま結果を success のメソッドの引数に渡します(string 型の時に限り戻り値をパースしてから success のメソッドに渡します)。

なので、上のサンプルコードのように、dataFilter のメソッドで JSON をパースして JavaScript オブジェクトに変換すると、string 型ではないので、JavaScript オブジェクトがそのまま success のメソッドの引数 cars に渡され、問題なく結果が表示されます。

ところが、バージョン 1.5 以降では、上のサンプルコードのように dataFilter のメソッドで JSON 文字列を JavaScript オブジェクトにパースすると、 success のメソッドの引数 cars に渡されるのは null になり、結果スクリプトエラーとなってしまいます。その理由は以下の通りです。

  1. サーバーからの応答の Content-Type が application/json の場合、dataFilter の結果を parseJSON: function(data){...} で定義されているメソッドの引数 data に渡す。
  2. parseJSON: function(data){...} メソッドは、引数として受け取った data をパースして JavaScript オブジェクトを戻り地として返すようになっているが、typeof data !== "string" の場合は、パース等何もしないで null を返す。
  3. dataFilter のメソッドで JSON 文字列をパースして JavaScript オブジェクトに変換してしまうと、data は string 型ではないので null が返される。
  4. 結果、success のメソッドの引数 cars に null が渡され、スクリプトエラーとなる。

従って、バージョン 1.5 以降では、パースは jQuery に任せて(dataFilter のメソッドは記述しないで)、d パラメータの処置のみを success のメソッドで行うことになります。上記のサンプルコードの function getCars() は以下のように修正してください。

function getCars() {
  $.ajax({
    type: "POST",

    url: "097_jQueryAjaxAndWebService.asmx/GetCarsByDoors",

    data: '{"doors":' + $("#ddlDoors").val() + '}',

    contentType: "application/json; charset=utf-8",

    success: function (cars) {
      if (cars.hasOwnProperty('d')) {
          cars = cars.d;
      }
      $('#output').empty();
      $.each(cars, function (index, car) {
        $('#output').append(
          '<p><strong>' + car.Make + ' ' +
          car.Model + '</strong><br /> Year: ' +
          car.Year + '<br />Doors: ' +
          car.Doors + '<br />Colour: ' +
          car.Colour + '<br />Price: £' +
          car.Price + '</p>');
        });
      },

      error: function (jqXHR, textStatus, errorThrown) {
        $('#output').text('textStatus: ' + textStatus + 
          ', errorThrown: ' + errorThrown);
      }
  });
}

Tags: ,

AJAX

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年5月  >>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar