ASP.NET MVCはじめました~データの新規登録
概要
環境
Visual Studio 2010
ASP.NET MVC2
SQLServer2008 R2
今回の要件は
- ブラウザより値を入力
- データベースに入力値を登録
として、サンプルコードを書いてみました。
実装
コントローラーの用意
入力の検証のために、属性を指定したクラスを受け取るコントローラーメソッドを用意します。
using System; using System.Web.Mvc; using Mvc2App.Models; using Mvc2App.Services; using Mvc2App.Services.Abstractions; using Mvc2App.ViewModels.Peple; using System.Data; using Mvc2App.Common; namespace Mvc2App.Controllers { [Authorize] public class PepleController : Controller { IPepleService _service; public PepleController() : this(new PepleService()) { } public PepleController(IPepleService service) { _service = service; } ... public ActionResult Create() { return View(); } [HttpPost] public ActionResult Create(PepleViewModel inputModel) { try { var person = new Person() { Name = inputModel.Name, Address = inputModel.Address, PhoneNumber = inputModel.PhoneNumber, UpdatedBy = Session["LogOnUser"].ToString(), UpdateDate = DateTime.Now }; _service.Insert(person); return RedirectToAction("Index"); } catch(ConstraintException) { inputModel.SysMessage = Resource.GetValue("ERR_002"); return View(inputModel); } catch (UpdateException) { inputModel.SysMessage = Resource.GetValue("ERR_002"); return View(inputModel); } } } }
サービスインタフェースとサービスクラスの用意
using System; using System.Collections.Generic; using System.Web.Mvc; using Mvc2App.Models; using Mvc2App.ViewModels.Peple; namespace Mvc2App.Services.Abstractions { public interface IPepleService { ... void Insert(Person p); } }
using System; using System.Collections.Generic; using System.Web.Mvc; using Mvc2App.Models; using Mvc2App.Repositories; using Mvc2App.Repositories.Abstractions; using Mvc2App.Services.Abstractions; using Mvc2App.ViewModels.Peple; using Mvc2App.Common; namespace Mvc2App.Services { public class PepleService : IPepleService { private IPepleRepository _repository; public PepleService() : this(new PepleRepository()) { } public PepleService(IPepleRepository repository) { _repository = repository; } ... public void Insert(Person p) { _repository.Insert(p); } } }
リポジトリインタフェースとリポジトリクラスの用意
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Mvc2App.Models; namespace Mvc2App.Repositories.Abstractions { public interface IPepleRepository { ... void Insert(Person p); } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Mvc2App.Repositories.Abstractions; using Mvc2App.Models; namespace Mvc2App.Repositories { public class PepleRepository : IPepleRepository { DevEntities dbContext = new DevEntities(); ... public void Insert(Person p) { dbContext.Peple.AddObject(p); dbContext.SaveChanges(); } } }
ビューモデルの用意
入力の検証を行うためにビューモデル*1にデータアノテーション属性を指定します。また、共通のシステムメッセージを保持するためにViewModelBaseクラスを継承するようにPepleViewModelクラスを変更しました。
namespace Mvc2App.ViewModels { public class ViewModelBase { public string SysMessage { get; set; } } }
using System; using System.ComponentModel.DataAnnotations; using Mvc2App.Content; namespace Mvc2App.ViewModels.Peple { public class PepleViewModel : ViewModelBase { public int ID { get; set; } [Required(ErrorMessageResourceName = "VALID_001", ErrorMessageResourceType = typeof(Strings))] [StringLength(20, ErrorMessageResourceName = "VALID_002", ErrorMessageResourceType = typeof(Strings))] public string Name { get; set; } [StringLength(50, ErrorMessageResourceName = "VALID_002", ErrorMessageResourceType = typeof(Strings))] public string Address { get; set; } [StringLength(15, ErrorMessageResourceName = "VALID_002", ErrorMessageResourceType = typeof(Strings))] public string PhoneNumber { get; set; } public string UpdatedBy { get; set; } public DateTime UpdateDate { get; set; } } }
テーブル定義もNameとUpdateDateをNot Nullに修正しました。
CREATE TABLE [dbo].[Peple]( [ID] [int] IDENTITY(1,1) NOT NULL, [Name] [nvarchar](20) NOT NULL, [Address] [nvarchar](50) NULL, [PhoneNumber] [nvarchar](15) NULL, [UpdatedBy] [nvarchar](20) NULL, [UpdateDate] [datetime] NOT NULL, CONSTRAINT [PK_Peple] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
これに伴い、NameとUpdateDateのエンティティもNull許容プロパティをFalseへ変更。
ビューの用意
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Mvc2App.ViewModels.Peple.PepleViewModel>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Create </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>Create</h2> <div id="sysMessage"><%: Html.DisplayFor(model => model.SysMessage) %></div> <% using (Html.BeginForm()) {%> <%: Html.ValidationSummary(true) %> <fieldset> <legend>Fields</legend> <div> <label>Name</label> </div> <div> <%: Html.TextBoxFor(model => model.Name) %> <%: Html.ValidationMessageFor(model => model.Name) %> </div> <div> <label>Address</label> </div> <div> <%: Html.TextBoxFor(model => model.Address) %> <%: Html.ValidationMessageFor(model => model.Address)%> </div> <div> <label>PhoneNumber</label> </div> <div> <%: Html.TextBoxFor(model => model.PhoneNumber) %> <%: Html.ValidationMessageFor(model => model.PhoneNumber)%> </div> <p> <input type="submit" value="Create" /> </p> </fieldset> <% } %> <div> <%: Html.ActionLink("Back to List", "Index") %> </div> </asp:Content>
システムメッセージは赤で表示させるようにCSSも追記。
#sysMessage { color: #ff0000; }
リソースの用意
メッセージはリソースファイルより取得するように変更します。
プロジェクトにリソースファイル(ファイル名はStrings.resx)を追加し、メッセージを整備します。
ユーティリティクラスも用意し、こちらからメッセージを取得するようにしました。
using System; namespace Mvc2App.Common { public class Resource { public static string GetValue(string name) { return Strings.ResourceManager.GetString(name); } } }
ログオンユーザのセッション管理
データベースにデータを登録する際の登録者はセッションより取得しています。
セッションをセットするタイミングはGlobal.asaxファイルのSession_Startメソッドに記述しました。
using System.Web.Mvc; using System.Web.Routing; namespace Mvc2App { public class MvcApplication : System.Web.HttpApplication { ... protected void Session_Start() { if (Session["LogOnUser"] == null) { if (User.Identity.IsAuthenticated) { Session["LogOnUser"] = HttpContext.Current.User.Identity.Name.Split('\\')[1]; } } } } }
User.Identity.Nameよりユーザ名を取得しています。
デフォルトのWeb.configではフォーム認証になっているのでUser.Identity.Nameが取得できません。
Windows認証に変更してあげると、User.Identity.Nameが取得できるようになります。
HttpContext.User プロパティ (System.Web)
<authentication mode="Windows"></authentication>
実行結果
/Peple/Createにアクセスします。
ASP.NET MVCはじめました~データベースより値を取得し一覧表示する - 1.21 jigowatts
ASP.NET MVCはじめました~データベースより値を取得し詳細を表示する - 1.21 jigowatts
*1:入力モデル用のクラスを用意したほうがよさそう?