WebSurfer's Home

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

requestEncoding の設定

by WebSurfer 2011年5月22日 17:52

応答のエンコーディングを UTF-16 にする場合、MSDN ライブラリの globalization 要素 (ASP.NET 設定スキーマ) に、requestEncoding 属性と responseEncoding 属性は同じにする必要があると書いてあるので、以下のように両方 UTF-16 に設定してしまうことがあるかもしれません。

<configuration>
  <system.web>
    <globalization
      requestEncoding="utf-16"
      responseEncoding="utf-16"/>
  </system.web>
</configuration>

でも、そうすると、サーバー側でポストデータが正しく取得できず、IsPostPack プロパティが true にならなかったり、Button.Click などのイベントが発生しないという問題が起こります。

原因は、以下のマイクロソフトサポートオンラインのページに詳しく書いてありますが、IE が submit するデータのエンコーディングです。

INFO: Internet Explorer Always POSTs Unicode Data as UTF-8

IE は、ページのエンコーディングが UTF-16 の場合、submit するデータは UTF-8 でエンコーディングするそうです。

データのエンコーディングが UTF-8 なのに、requestEncoding="utf-16" と設定されているため、サーバー側が UTF-16 として処置するので、データが正しく取得できないということのようです。

IE 以外のブラウザ(Firefox 3.6.17 と Chrome 11.0.696.68)でも試してみましたが、結果は同じでした。

ちなみに Shift_JIS の場合は、ページのエンコーディングが Shift_JIS ならブラウザが submit するデータのエンコーディングも Shift_JIS になるので、UTF-16 の時のような問題ないそうです(というより、requestEncoding と responseEncoding の両方を Shift_JIS としておかないとダメ)。

解決策は、globalization 要素の requestEncoding="utf-16" を削除(デフォルトで UTF-8 になる)することです。

または、特定のページだげ応答のエンコーディングを UTF-16 にしたいのであれば、そのページのページディレクティブで ResponseEncoding="UTF-16" と設定し、その他はすべてデフォルトのまま(globalization 要素は指定しない)とすればよさそうです。

Tags:

ASP.NET

GridView のヘッダ、列を固定

by WebSurfer 2011年4月30日 12:52
2017/8/16 注記追加
Windows 10 IE11 では Quirks モード(IE5 相当)にしても expression 関数が働かないようで、テーブルのヘッダ・列は固定されませんのでご注意ください。この記事はもう意味がないかもしれませんが、せっかく書いたので残しておきます。

以前の記事 table のヘッダ、列を固定 では ListView を使ったときの例を書きましたが、ここでは GridView を使ったときの例を紹介します。  (2013/2/7 追記:このページに紹介したのは IE の互換モード(Quirks モード)専用ですが、GridView のヘッダ、列を固定(その 2)のページに IE7+ (標準モードの), Firefox, Chrome, Safari, Opera コンパチのものを書きましたので、そちらも見てください)

GridView のヘッダ、列を固定

GridView も html にレンダリングされると table, tr, th, td などの要素になりますが、それらは自動的に(勝手に)生成され、かつ、直接スタイルを適用できないので結構面倒です。

今回は先の ListView を使った場合の例よりヘッダーを少し複雑にしました(一部のセルの rowspan を 2 にしてみました)ので、ますます面倒になっています。(笑)

という訳で、実際にはあまり役に立たないと思いますが、せっかく苦労して作ったので書いておくことにしました。

上の画像を出力したコードは下記の通りです。実際に動かして試せるよう 実験室 にアップしましたので、興味のある方は試してみてください。

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>

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

<script runat="server">
  DataTable CreateDataTable()
  {
    DataTable dt = new DataTable();
    DataRow dr;

    dt.Columns.Add(new DataColumn("Code", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Name", typeof(string)));
    dt.Columns.Add(new DataColumn("Price", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Qty", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Amount", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Remarks", typeof(string)));
        
    for (int i = 0; i < 50; i++)
    {
      dr = dt.NewRow();
      dr["Code"] = i;
      dr["Name"] = "Item " + i.ToString();
      dr["Price"] = 123000 * (i + 1);
      dr["Qty"] = i + 1;
      dr["Amount"] = 123000 * (i + 1) * (i + 1);
      dr["Remarks"] = "Remarks " + i.ToString();
      dt.Rows.Add(dr);
    }
    return dt;
  }

  void Page_Load(Object sender, EventArgs e)
  {
    if (!IsPostBack)
    {
      GridView1.DataSource = CreateDataTable();
      GridView1.DataBind();
    }
  }

  // RowDataBound で細工すると PostBack で表示が崩れるので
  // 注意(ViewState との関係が崩れるらしい)
  protected void GridView1_RowCreated(object sender, 
    GridViewRowEventArgs e)
  {
    if (e.Row.RowType == DataControlRowType.Header)
    {
      System.Collections.Generic.List<TableCell> cells =
        new System.Collections.Generic.List<TableCell>();
      foreach (TableCell cell in e.Row.Cells)
      {
        cells.Add(cell);
      }

      GridViewRow row1 =
        new GridViewRow(
          -1,
          -1,
          DataControlRowType.Header,
          DataControlRowState.Normal);
      cells[0].RowSpan = 2;
      cells[1].RowSpan = 2;
      cells[5].RowSpan = 2;

      TableHeaderCell headerCell = new TableHeaderCell();
      headerCell.ColumnSpan = 3;
      headerCell.Controls.Add(new LiteralControl("注文詳細"));
      row1.Cells.Add(cells[0]);
      row1.Cells.Add(cells[1]);
      row1.Cells.Add(headerCell);
      row1.Cells.Add(cells[5]);

      GridViewRow row2 =
        new GridViewRow(
          -1,
          -1,
          DataControlRowType.Header,
          DataControlRowState.Normal);
      for (int i = 2; i < 5; i++)
      {
        row2.Cells.Add(cells[i]);
      }
      row1.CssClass = "FreezingHeader1";
      row2.CssClass = "FreezingHeader2";
      GridView1.Controls[0].Controls.Clear();
      GridView1.Controls[0].Controls.Add(row1);
      GridView1.Controls[0].Controls.Add(row2);
    }
  }    
 
  // position:relative を適用することにより border の
  // 幅が変わってしまう。以下はその調整。
  protected void GridView1_PreRender(object sender, EventArgs e)
  {
    // ヘッダは 3 行できるのでそれの識別用
    int count = 0;
        
    // GridView.Rows はデータ行の GridViewRow のみ
    // GridView1.Controls[0].Controls はヘッダ、
    // フッターも含む
    foreach (GridViewRow row in GridView1.Controls[0].Controls)
    {
      if (row.RowType == DataControlRowType.Header)
      {
        if (count == 0)
        {
          row.Cells[0].Style["border-width"] = "2 1 1 2";
          row.Cells[1].Style["border-width"] = "2 1 1 1";

          // これがないとヘッダの "備考" のセルの下半分
          // が切れてしまう。
          // "コード" と "商品名" セルには FreezingCol 
          // に position:relative が含まれるので不用
          row.Cells[3].Style["position"] = "relative";
          row.Cells[3].Style["border-width"] = "2 2 1 1";
        }
        // 何故か自動でできてしまうヘッダの 3 行目を消去
        if (count == 2)
        {
          row.Style["display"] = "none";
        }
      }
      else if (row.RowType == DataControlRowType.DataRow)
      {
        if (row.RowIndex == GridView1.Rows.Count - 1)
        {
          row.Cells[0].Style["border-width"] = "1 1 2 2";
          row.Cells[1].Style["border-width"] = "1 1 2 1";
        }
        else
        {
          row.Cells[0].Style["border-width"] = "1 1 1 2";
          row.Cells[1].Style["border-width"] = "1 1 1 1"; 
        }                
      }
      else if (row.RowType == DataControlRowType.Footer)
      {
        // 今回、フッターはないので何もしない。
      }
      count++;
    }
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
  <%--Quirks モードに設定--%>
  <meta http-equiv="X-UA-Compatible" content="IE=5" />
  <style type="text/css">
    .FreezingHeader1
    {
      z-index: 10;
      position: relative;
      top: expression(this.offsetParent.scrollTop);
      background-color: #0000cc;
    }

    .FreezingHeader2
    {
      z-index: 5;
      position: relative;
      top: expression(this.offsetParent.scrollTop);
      background-color: #0000cc;
    }    
            
    .FreezingCol
    {
      z-index: 1;
      left: expression(
        document.getElementById("freezingDiv").scrollLeft);
      position: relative;
      background-color: white;
    }

    #freezingDiv
    {
      overflow: auto;
      width: 350px;
      height: 200px;
    }

    table.style1
    {
      border-style: none; /* 指定するとスクロールでずれる */
      text-align: center;
      border-collapse: collapse;            
    }
       
    table.style1 th
    {
      border-style: solid;
      border-width: 2px;
      border-color: #0000cc;
      background-color: #6699FF;
      color: #FFFFFF;
      padding: 5px;            
    }
        
    table.style1 td
    {
      border-style: solid;
      border-width: 2px;
      border-color: #0000cc;
      padding: 5px;
    }
  </style>
</head>
<body>
  <form id="form1" runat="server">
  <div id="freezingDiv">
    <asp:GridView ID="GridView1" 
      runat="server" 
      CssClass="style1" 
      Width="450px" 
      AutoGenerateColumns="False"             
      OnRowCreated="GridView1_RowCreated" 
      OnPreRender="GridView1_PreRender">
      <Columns>
        <asp:BoundField DataField="Code" 
          HeaderText="コード" >
          <HeaderStyle CssClass="FreezingCol" />
          <ItemStyle CssClass="FreezingCol" />
        </asp:BoundField>
        <asp:BoundField DataField="Name" 
          HeaderText="商品名" >
          <HeaderStyle CssClass="FreezingCol" />
          <ItemStyle CssClass="FreezingCol" />
        </asp:BoundField>
        <asp:BoundField DataField="Price" 
          HeaderText="単価" >
        </asp:BoundField>
        <asp:BoundField DataField="Qty" 
          HeaderText="数量" >
        </asp:BoundField>
        <asp:BoundField DataField="Amount" 
          HeaderText="合価" >
        </asp:BoundField>
        <asp:BoundField DataField="Remarks" 
          HeaderText="備考" >
        </asp:BoundField>
      </Columns>
    </asp:GridView>
  </div>
  <asp:Button ID="Button1" 
    runat="server" 
    Text="PostBack" />
  </form>
</body>
</html>

Tags: ,

ASP.NET

ビューから Entity Data Model 生成

by WebSurfer 2011年4月24日 13:12

Visual Studio のデザイナを使って、テーブルではなくビューから Entity Data Model(以下、EDM と書きます)を作成する時の話です。

ビューから EDM を作成

ビューもしくは主キーを持たないテーブルから EDM を作成しようとすると、以下のようなエラーメッセージが出て、有効な EDM が生成されないことがあります。

「テーブル/ビュー 'xxxxx' に主キーが定義されておらず、有効な主キーを推論できませんでした。このテーブル/ビューは除外されました。エンティティを使用するには、スキーマを確認し、正しいキーを追加して、コメントを解除する必要があります。」

検索して調べてみると、そのあたりのことは The table/view does not have a primary key defined というページに詳しく書いてありました。要約すると、以下のとおりです。

EDM の各 Entity は Key を持つ必要があり、ビューや主キーのないテーブルの場合は、デザイナが NULL 不許可の列を主キーとして推定して EDM を生成します。

しかしながら、ビューが取得する全列が NULL 許可の場合、デザイナは主キーを推定できず、有効な EDM を生成できないので、上記のエラーメッセージが出るということだそうです。

その場合でも、関係する SSDL, CSDL, MSL は edmx ファイルの中に生成されていますが、SSDL 部分がコメントアウトされていたり、その他 CSDL, MSL も不完全な内容となってます。

以下の例は、すべての列が NULL 許可のビューから作成した EDM の中身です(xml ファイルなのでメモ帳で開くことができます)。

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="2.0" 
  xmlns:edmx="http://schemas.microsoft.com/ado/2008/10/edmx">
  <!-- EF Runtime content -->
  <edmx:Runtime>
    <!-- SSDL content -->
    <edmx:StorageModels>
      <Schema ・・・中略・・・

  <!--生成中に見つかったエラー:
  警告 6013: テーブル/ビュー 'xxxxx' に主キーが定義されてお
  らず、有効な主キーを推論できませんでした。このテーブル/ビ
  ューは除外されました。エンティティを使用するには、スキー
  マを確認し、正しいキーを追加して、コメントを解除する必要が
  あります。
      
  <EntityType Name="ViewForEdmTest">
    <Property Name="ContactName" Type="nvarchar" MaxLength="30" />
    <Property Name="ContactTitle" Type="nvarchar" MaxLength="30" />
    <Property Name="Address" Type="nvarchar" MaxLength="60" />
    <Property Name="City" Type="nvarchar" MaxLength="15" />
    <Property Name="Region" Type="nvarchar" MaxLength="15" />
    <Property Name="PostalCode" Type="nvarchar" MaxLength="10" />
    <Property Name="Country" Type="nvarchar" MaxLength="15" />
  </EntityType>-->

      </Schema>
    </edmx:StorageModels>

    <!-- CSDL content -->
    <edmx:ConceptualModels>
      ・・・中略・・・
    </edmx:ConceptualModels>

    <!-- C-S mapping content -->
    <edmx:Mappings>
      ・・・中略・・・
    </edmx:Mappings>
  </edmx:Runtime>

  <!-- EF Designer content (DO NOT EDIT MANUALLY BELOW HERE) -->
  <Designer ・・・中略・・・
  </Designer>
</edmx:Edmx>

エラーメッセージの「正しいキーを追加して、コメントを解除・・・」というのは、それを書き直せということで、上に紹介したページの First Solution のことを言っています。

edmx ファイルをメモ帳で開いて、関係する SSDL, CSDL, MSL を書き直せば、確かに EDM 本体は有効になります。上の画像は、SSDL, CSDL, MSL を書き直したあと、edmx ファイルを Visual Studio で開いたもので、有効な EDM として表示されています(直す前は何も表示されません)。

ただし、Xxxxx.Designer.cs の定義が不完全なままなので、結局直した EDM はアプリケーションで利用できなかったのですが(自分が試した限りです)。

edmx ファイルを自力で書き直す以外の解決方法は以下の通りです。

  1. ビューが取得するフィールドに主キー列を含める。
  2. ISNULL 関数を利用する。

ビューにはもともと主キーなどはありませんが、ビューが取得するフィールドに主キー列が含まれていると、その列が NULL 不許可となり(デザイナがその列を主キーとして推定し)、EDM の生成に成功します。

2 番目の解決策は、上に紹介したページの Second Solution です。例えば、以下のように ID 列を追加してやります。なお、ROW_NUMBER() だけではダメで、ISNULL が必要ですので注意してください。

SELECT ISNULL((ROW_NUMBER() OVER (ORDER BY ContactName ASC)), 0) AS ID, ContactName, ContactTitle, Address, City, Region
FROM   dbo.Customers

なお、上記 1, 2 のいずれの場合も、EDM 生成時に以下のメッセージが出ますが、xxxxx.edmx ファイルは、xxxxx.Designer.cs を含めて、問題なく生成されているはずです。

「テーブル/ビュー 'xxxxx' には主キーが定義されていません。主キーは推論され、定義は読み取り専用のテーブル/ビューとして作成されました。」

Tags: , ,

ADO.NET

About this blog

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

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar