喜帳面の日記

50歳越えおやじのASP.NET MVC への挑戦日記です。

Visual Studio Express 2012 for Web でいってみる 29.アクションメソッドに入ってくれない

久しぶりの書き込みになってしまいました。。

今回は、失敗談です。

Formでsubmitしたんだけど、コントローラーのアクションメソッドに入ってくれないって現象に数時間悩んでしまったので、二度と無駄な時間を消費しないようメモを残しておきます。

尚、初心者が行き当たりばったりにいろいろ動かしてみたときのメモなので、記載内容には勝手な解釈や誤りもあるかと思います。お気づきの点がありましたら、ご指摘よろしくお願いします。

さて、現象は、

Formで入力した内容をデータベースに書き込む処理です。

で,Formでsubmitボタンを押しました。画面上変化はありません。あれ?ってことでデバッグでステップ実行をすると、どうやら、コントローラのコンストラクターまでは来てるが、コンストラクタ抜けたところで終わってしまってます。

何が起きているんでしょう?アクションメソッドの引数が不正?modelがおかしい?

などなど悩みまくってしまったのですが、

IEのF12でネットワークのキャプチャーを見てやっとエラーの原因が判明しました。

f:id:SannomiyaNotes:20130906122640p:plain

タイトル部分に「ローカライズに失敗したため、プロパティ'Name'を取得できません。。。。

て記述が。これでやっと気づきました。

modelのclassのDisplay属性の記述部分で

 [Display(ResourceType = typeof(rsGlobal), Name = "ResFieldMKKKSystemKBN1")]

 public int MKKKSystemKBN1 { get; set; }

ってリソースの指定をしていたのですが、リソースファイルには登録漏れしてました。

cshtmlでのリソース指定

<button id="btnCreate" type="button"  >@rsGlobal.Res作成</button>

この記述の場合、未登録だとエラーの波線を付けてくれますが、

コントローラーやクラスなど.csコードの場合、ビルド時にもチェックされないんですね。

今回は、F12でやっと原因がつかめました。ローカルに「発行」して実行してみたんですが、しれっと、何のエラーも出てくれません。私のエラーハンドリング、何かが不足してるんでしょうか?そんな気がします。

 

・リソースファイルへの登録漏れに注意。エラーに気づきにくい。

・原因不明?。F12ネットワークのキャプチャーも確認しよう。

 

今回は以上です。

 

 

 

Visual Studio Express 2012 for Web でいってみる 28.javascriptでResourceObjectを使う方法

以前 .Net MVC4 + Razor の環境で「多言語化」にチャレンジしたとき

 Visual Studio Express 2012 for Web でいってみる 22.多言語対応をやってみた。

こんなメモをのこしてます。
このとき、リソースオブジェクトの取得方法について、クラスファイルやビューでの記述例をいくつか書いてますが、javascript で扱う方法については書いてませんでした。
あのメモを書いた時点では気にしていなかったのですが、今般、javascriptでResourceObjectから文字列を取り出す必要がでてきて、再度チャレンジしました。
他力本願志向の私はさっそく、ネットでサンプル探しを始め、あれこれコード見てるうちにいつのまにか、思わぬ思い込みをして。。。。。
きっと
var hoge = '@(HttpContext.GetGlobalResourceObject("rsGlobal","ResMSG").ToString())';
こんな風にGetGlobalResourceObjectを使わないといけないと勝手に思い込んでしまった。実際のところ上記のコードはエラーになって動かないです。
(※"rsGlobal"はResourceファイル名、"ResMSG"は「名前」です )
正解は、
var hoge = '@rsGlobal.ResMSG';
これだけです。すごくシンプルでした。そういえばすぐ近くのボタンのキャプションの部分については
<button type="button" name="Button" value="create">@rsGlobal.Res作成</button>
こう記述してますね。
javascriptだからってことですごーく遠回りしてしまいました。ネットからはこんなサンプル見つけられなかったから「常識」の範疇なんでしょうか。。。
まあ、ASP.NET、Razorがまだちゃんと理解できていないからこんなことになるんでしょう。
今回は以上です。
 
 

Visual Studio Express 2012 for Web でいってみる 27.Ignite UIのGridを使ってみた。画像編

前回の記事、

Visual Studio Express 2012 for Web でいってみる 26.Ignite UIのGridを使ってみた。DataSource編

で、Ignite UI のGrid について紹介しましたが、今回はその続編です。

MVC4+Razorの環境で Ignite UIのGridを使用し画像を表示する方法についてメモを残しておきます。igGrid(Ignite UIのGrid)のHelpやサンプル等には、画像をグリッド
上に表示する方法がいくつか用意されていますが、MVC4 + Razor のHelperを使った階層のあるGridで画像を表示してるやつが見つけられなかったので、サンプルとしてメモを残しておきます。
今回の出来上がりイメージは以下のグリッドです。

f:id:SannomiyaNotes:20130429105729p:plain

前回、紹介した階層Gridに①、②などの画像を追加してみました。この画像は、Visual Studio Express 2012 for Web でMVC のプロジェクトを作成したとき、Imagesフォルダに配置される標準のpngファイルです。

 

ソースですが、前回も紹介した階層のあるGridのcshtmlにテンプレート指定をすればOKです。それだけなんですが。。一応ソース張り付けておきます。

※2015/07/16 追記 以下の「rowTemplateオプションを使って画像を表示する方法」については、「IgniteUI 2014.1 リリースより rowTemplateオプションは非推奨」と

なっています。 rowTemplateオプションではなく個々のColumnsの「.Template」を使って画像表示が可能です。「.Template」を使ってください。この記事も参考にしてください。

 

sannomiyanotes.hatenablog.com

  

 <Model>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Mvc4ApplicationR.Models
{
    // 商品区分
    public class KubunMS
    {
        public int KubunCD { get; set; }
        public string Kubunmei { get; set; }
        public string ImageFile { get; set; }
    }
    
    // 商品
    public class Shouhin
    {
        public int ShouhinCD { get; set; }
        public string ShouhinName { get; set; }
        public int KubunCD { get; set; }
        public string ImageFile { get; set; }
    }

    //商品区分別商品データGrid用
    public class HierShouhin
    {
        public HierShouhin()
        {
            this.Shouhins = new HashSet();
        }
        public int KubunCD { get; set; }
        public string Kubunmei { get; set; }
        public string ImageUrl { get; set; }
        public virtual ICollection Shouhins { get; set; }
    }

    // 商品ImgGrid用
    public class ShouhinImg
    {
        public int ShouhinCD { get; set; }
        public string ShouhinName { get; set; }
        public int KubunCD { get; set; }
        public string ImageUrl { get; set; }
    }

    public class ShouhinData
    {
        public static IQueryable GetKubunCDList()
        {
            List ItemList = new List();
            ItemList.Add(new KubunMS { KubunCD = 1, Kubunmei = "飲料", ImageFile = "orderedList1.png" });
            ItemList.Add(new KubunMS { KubunCD = 2, Kubunmei = "調味料", ImageFile = "orderedList2.png" });
            ItemList.Add(new KubunMS { KubunCD = 3, Kubunmei = "菓子類", ImageFile = "orderedList3.png" });
            ItemList.Add(new KubunMS { KubunCD = 4, Kubunmei = "乳製品", ImageFile = "orderedList4.png" });
            ItemList.Add(new KubunMS { KubunCD = 5, Kubunmei = "穀類、シリアル", ImageFile = "orderedList5.png" });
            ItemList.Add(new KubunMS { KubunCD = 6, Kubunmei = "肉類", ImageFile = "orderedList6.png" });
            ItemList.Add(new KubunMS { KubunCD = 7, Kubunmei = "加工食品", ImageFile = "orderedList7.png" });
            ItemList.Add(new KubunMS { KubunCD = 8, Kubunmei = "魚介類", ImageFile = "orderedList8.png" });
            return ItemList.AsQueryable();
        }

        public static IQueryable GetShouhinList(Nullable KubunCD)
        {
            List shouhinList = new List();
            shouhinList.Add(new Shouhin { ShouhinCD = 1, ImageFile = "orderedList1.png", ShouhinName = "果汁100% オレンジ", KubunCD = 1 });
            shouhinList.Add(new Shouhin { ShouhinCD = 2, ImageFile = "orderedList2.png", ShouhinName = "果汁100% グレープ", KubunCD = 1 });
    		//省略
            shouhinList.Add(new Shouhin { ShouhinCD = 41, ImageFile = "orderedList1.png", ShouhinName = "モーニングブレッド", KubunCD = 5 });
            shouhinList.Add(new Shouhin { ShouhinCD = 42, ImageFile = "orderedList2.png", ShouhinName = "バタートースト", KubunCD = 5 });
            shouhinList.Add(new Shouhin { ShouhinCD = 43, ImageFile = "orderedList3.png", ShouhinName = "バケットフランス", KubunCD = 5 });

            IEnumerable source =
                     from s in shouhinList
                     where s.KubunCD == KubunCD
                     orderby s.ShouhinCD
                     select s;
            return source.AsQueryable();
        }
    }
}

画像用の項目を追加していますが、modelは特に注意点はありません。

<Controller>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Mvc4ApplicationR.Models;
using Infragistics.Web.Mvc;

namespace Mvc4ApplicationR.Controllers
{
    public class TestController : Controller
    {
        public ActionResult Index()
        {
            return View("GridTest");
        }

    //階層化化グリッド

        //Viewで商品区分別商品データを渡します。
        [GridDataSourceAction]
        public ActionResult GetViewDataHierShouhin()
        {
            IQueryable model = GetHierShouhin();
            return View(model);  //return PartialView(model);でもOK
        }

        //商品区分別商品データをセットし返します
        public IQueryable GetHierShouhin()
        {
            List ItemList = new List();
            var kubunData = ShouhinData.GetKubunCDList();
            foreach (var KBNitems in kubunData)
            {
                var hierShouhin = new HierShouhin();
                hierShouhin.KubunCD = KBNitems.KubunCD;
                hierShouhin.Kubunmei = KBNitems.Kubunmei;
                hierShouhin.ImageUrl = UrlHelper.GenerateContentUrl("~/Images/" + KBNitems.ImageFile, HttpContext); 
                hierShouhin.Shouhins = GetShouhinList(hierShouhin.KubunCD);
                ItemList.Add(hierShouhin);
            }
            return ItemList.AsQueryable();
        }

        //商品データの取得
        public List GetShouhinList(int KubunCD)
        {
            List ItemList = new List();
            var shouhins = ShouhinData.GetShouhinList(KubunCD);
            foreach (var SHNitems in shouhins)
            {
                var shouhin = new ShouhinImg();
                shouhin.ShouhinCD = SHNitems.ShouhinCD;
                shouhin.ShouhinName = SHNitems.ShouhinName;
                shouhin.KubunCD = SHNitems.KubunCD;
                shouhin.ImageUrl = UrlHelper.GenerateContentUrl("~/Images/" + SHNitems.ImageFile, HttpContext);
                ItemList.Add(shouhin);
            }
            return ItemList;
        }
    }
}
 

画像用の項目を追加しています。

画像ファイルのURLについては、UrlHelper.GenerateContentUrl(パス, HttpContext)を使ってます。デバッグ時は、"../Images/" + SHNitems.ImageFileでも表示されますが、発行すると、画像が表示されなかったりします。

 

<Cshtml>

@using Mvc4ApplicationR.Models;

@using Infragistics.Web.Mvc
@Scripts.Render("~/bundles/infragistics.loader")
@(Html.Infragistics().Loader()
                .ScriptPath(Url.Content("~/Scripts/IG/js/"))
                .CssPath(Url.Content("~/Content/IG/css/"))
                .Resources("igShared,igDialog")
                .Render()
)
 @(Html.Infragistics().Grid<HierShouhin>()
 .ID("ShouhinGrid")
 .InitialExpandDepth(-1)
 .LoadOnDemand(false)
 .AutoGenerateColumns(false)
 .AutoGenerateLayouts(false)
 .PrimaryKey("KubunCD")
 .RowTemplate
  (
   "<tr>" +
     "<td ><IMG SRC=${ImageUrl} style = 'width:20px;height:20px'></IMG></td>" +
     "<td>${KubunCD}</td>" +
     "<td>${Kubunmei}</td>" +
   "</tr>"
   )

 .Columns(column => {
     column.For(x => x.ImageUrl).HeaderText(" ").Width("40px").DataType("string");
     column.For(x => x.KubunCD).HeaderText("CD").Width("60px");
     column.For(x => x.Kubunmei).HeaderText("区分名").Width("200px");
     })
 .ColumnLayouts(layouts =>
         {
             layouts.For(x => x.Shouhins)
                 .PrimaryKey("ShouhinCD")
                 .ForeignKey("KubunCD")
                 .AutoGenerateColumns(false)
                 .AutoGenerateLayouts(false)
                 .RowTemplate
                 (
                  "<tr>" +
                     "<td ><IMG SRC=${ImageUrl} style = 'width:20px;height:20px'></IMG></td>" +
                     "<td>${ShouhinCD}</td>" +
                     "<td>${ShouhinName}</td>" +
                     "<td>${KubunCD}</td>" +
                  "</tr>"
                 )

                 .Columns(childcolumn =>
                 {
                     childcolumn.For(x => x.ImageUrl).HeaderText(" ").Width("40px").DataType("string");
                     childcolumn.For(x => x.ShouhinCD).HeaderText("CD").Width("60px");
                     childcolumn.For(x => x.ShouhinName).HeaderText("商品名").Width("200px");
                     childcolumn.For(x => x.KubunCD).HeaderText("区分").Width("50px");
                 });
         })
 .Features(features =>
 {
     features.Selection().Mode(SelectionMode.Row).MultipleSelection(false);//.WrapAround(true).Activation(true);
     features.Paging().Type(OpType.Local);
 })
 .DataSourceUrl(Url.Action("GetViewDataHierShouhin","Test")) //Return View 
 .LoadOnDemand(false)
 .Width("400px").Height("450px")
 .DataBind()
 .Render())

(注):'<'および'>'を全角に変換しています。

ポイントは「.RowTemplate」の部分です。親階層、子階層の双方に追加していますが、テンプレートでイメージを含むテーブルの定義を行っています。これで任意の列に画像を表示することができます。

 

今回は以上です。

 

Visual Studio Express 2012 for Web でいってみる 26.Ignite UIのGridを使ってみた。DataSource編

 

以前の記事、
Visual Studio Express 2012 for Web でいってみる 21.Ignite UIを使ってみた。
で、Ignite UI について紹介しましたが、今回はその続編です。
MVC4+Razorの環境で Ignite UIのGridを使用する場合の、DataSource指定についてメモを残しておきます。
 
今回の出来上がりイメージは以下の2つのグリッドです。

f:id:SannomiyaNotes:20130427073523p:plain

 左の「商品区分一覧」は階層を持たないグリッドで、右の「商品区分別商品一覧」は1層目が「商品区分」2層目が「商品」となる階層化グリッドです。

 さて、igGridのデータの取得方法は何通りかありますが、今回は、Viewを使う方法とjsonを使う方法を紹介します。

 
まず、階層なしのgridの場合について。
■DataSourceにViewを使用する場合
<Controller>
        //Viewで商品区分データを渡します。
        [GridDataSourceAction]
        public ActionResult GetViewDataShouhinKBN()
        {
            IQueryable model = ShouhinData.GetKubunCDList();
            return View(model); //PartialView(model)でもOK
        }
属性[GridDataSourceAction]を記述します。これを忘れると
Microsoft JScript 実行時エラー: データを取得するリモート要求に失敗しました。
が発生するようです。尚、[GridDataSourceAction]を使うためには、
using Infragistics.Web.Mvc;の記述が必要です。
<cshtml>のGrid部分の記述
 @(Html.Infragistics().Grid()
     .ID("ShouhinKBNGrid")
     .AutoGenerateColumns(false)
     .AutoGenerateLayouts(false)
     .PrimaryKey("KubunCD")
     .Columns(column => {
         column.For(x => x.KubunCD).HeaderText("CD").Width("100px");
         column.For(x => x.Kubunmei).HeaderText("区分名").Width("200px");
     })
             .Features(features =>
             {
                 features.Selection().Mode(SelectionMode.Row).MultipleSelection(false);
                 features.Paging().Type(OpType.Local);
             })
     //DataSourceがViewの場合
     .DataSourceUrl(Url.Action("GetViewDataShouhinKBN")) 

     .LoadOnDemand(false)
     .Width("400px")
     .Height("450px")
     .DataBind()
     .Render()
   )
 
■DataSourceにJsonを使用する場合
<Controller>
   public JsonResult GetJsonDataShouhinKBN()
   {
        IQueryable model = ShouhinData.GetKubunCDList();
        return Json(model, JsonRequestBehavior.AllowGet);
    }
属性[GridDataSourceAction]は記述しません。書くと、
Microsoft JScript 実行時エラー: データを取得するリモート要求に失敗しました。
が発生するようです。
 <cshtml>のGrid部分の記述
 @(Html.Infragistics().Grid()
     .ID("ShouhinKBNGrid")
     .AutoGenerateColumns(false)
     .AutoGenerateLayouts(false)
     .PrimaryKey("KubunCD")
     .Columns(column => {
         column.For(x => x.KubunCD).HeaderText("CD").Width("100px");
         column.For(x => x.Kubunmei).HeaderText("区分名").Width("200px");
     })
             .Features(features =>
             {
                 features.Selection().Mode(SelectionMode.Row).MultipleSelection(false);
                 features.Paging().Type(OpType.Local);
             })
     //DataSourceがJsonの場合
     .DataSourceUrl(Url.Action("GetJsonDataShouhinKBN")) 
     .LocalSchemaTransform(true)

     .LoadOnDemand(false)
     .Width("400px")
     .Height("450px")
     .DataBind()
     .Render()
   )
  .LocalSchemaTransform(true)の記述を入れます。
これが無いと、
実行時エラー: プロパティ 'length' の値を取得できません: オブジェクトは Null または未定義です。
が発生します
 

 次に階層化グリッドの場合
ちなみにModel classは、こんなかんじです。
    // 商品区分
    public class KubunMS
    {
        public int KubunCD { get; set; }
        public string Kubunmei { get; set; }
    }
    
    // 商品
    public class Shouhin
    {
        public int ShouhinCD { get; set; }
        public string ShouhinName { get; set; }
        public int KubunCD { get; set; }
    }

    //商品区分別商品データ
    public class HierShouhin
    {
        public HierShouhin()
        {
            this.Shouhins = new HashSet();
        }
        public int KubunCD { get; set; }
        public string Kubunmei { get; set; }
        public virtual ICollection Shouhins { get; set; }
    }
 
 ■DataSourceにViewを使用する場合(というかJsonではできなかった)
 <Controller>
 //Viewで商品区分別商品データを渡します。
 [GridDataSourceAction]
 public ActionResult GetViewDataHierShouhin()
 {
     IQueryable model = GetHierShouhin();
     return View(model);  //return PartialView(model);でもOK
 }

 //商品区分別商品データをセットし返します
 public IQueryable GetHierShouhin()
 {
     List ItemList = new List();
     var kubunData = ShouhinData.GetKubunCDList();
     foreach (var KBNitems in kubunData)
     {
         var hierShouhin = new HierShouhin();
         hierShouhin.KubunCD = KBNitems.KubunCD;
         hierShouhin.Kubunmei = KBNitems.Kubunmei;
         hierShouhin.Shouhins = GetShouhinList(hierShouhin.KubunCD);
         ItemList.Add(hierShouhin);
     }
     return ItemList.AsQueryable();
 }

 //商品データの取得
 public List GetShouhinList(int KubunCD)
 {
     List ItemList = new List();
     var shouhins = ShouhinData.GetShouhinList(KubunCD);
     foreach (var SHNitems in shouhins)
     {
         var shouhin = new Shouhin();
         shouhin.ShouhinCD = SHNitems.ShouhinCD;
         shouhin.ShouhinName = SHNitems.ShouhinName;
         shouhin.KubunCD = SHNitems.KubunCD;
         ItemList.Add(shouhin);
     }
     return ItemList;
 }
属性[GridDataSourceAction]を記述します。
using Infragistics.Web.Mvc;の記述が必要です。
 
 <cshtml>のGrid部分の記述
 @(Html.Infragistics().Grid()
 .ID("ShouhinGrid")
 .InitialExpandDepth(-1)
 .LoadOnDemand(false)
 .AutoGenerateColumns(false)
 .AutoGenerateLayouts(false)
 .PrimaryKey("KubunCD")
 .Columns(column => {
     column.For(x => x.KubunCD).HeaderText("CD").Width("60px");
     column.For(x => x.Kubunmei).HeaderText("区分名").Width("200px");
     })
 .ColumnLayouts(layouts =>
         {
             layouts.For(x => x.Shouhins)
                 .PrimaryKey("ShouhinCD")
                 .ForeignKey("KubunCD")
                 .AutoGenerateColumns(false)
                 .AutoGenerateLayouts(false)
                 .Columns(childcolumn =>
                 {
                     childcolumn.For(x => x.ShouhinCD).HeaderText("CD").Width("60px");
                     childcolumn.For(x => x.ShouhinName).HeaderText("商品名").Width("200px");
                     childcolumn.For(x => x.KubunCD).HeaderText("区分").Width("50px");
                 });
         })
 .Features(features =>
 {
     features.Selection().Mode(SelectionMode.Row).MultipleSelection(false);//.WrapAround(true).Activation(true);
     features.Paging().Type(OpType.Local);
 })
 //DataSourceがViewの場合
 .DataSourceUrl(Url.Action("GetViewDataHierShouhin","Test")) 

 .LoadOnDemand(false)
 .Width("400px")
 .Height("450px")
 .DataBind()
 .Render())
 こんな風になりました。 .ColumnLayouts 以降の部分が2層目の定義で
 .ForeignKeyで第1階層とリレーションします。
一方、階層グリッドをjsonで行う方法ですが、現時点ではまだ実現できていません。
何がいけないのか、どうやってもエラーになっている状況です。
 igGridは非常に多機能すぎるが故にパラメータ設定で混乱している状況なのかも。
私の場合、グリッドについてはViewでデータを渡す手法に統一しようと思います。
 
参考URL