第4回 ASP.NETによるWebアプリ開発(アプリケーションの開発)連載:ASP.NETによる軽量業務アプリ開発

コマンドラインとエディターのみでWeb開発する方法を説明。今回は慶弔金などの集金とそのための名簿管理に使用するデータベースをPowerShellで作成する。

» 2014年06月27日 16時54分 公開
[arton ]
連載:ASP.NETによる軽量業務アプリ開発
業務アプリInsider/Insider.NET

powered by Insider.NET

「連載:ASP.NETによる軽量業務アプリ開発」のインデックス

連載目次

本連載の目的

 本連載では、部門コンピューティング(=Excel+VBAで簡単な業務アプリを開発するようなこと)レベルの開発手法として、ASP.NETを利用した軽量Webアプリ開発を説明する。タブレットを利用した業務アプリのプロタトタイプ実装や、Excel+VBAの業務アプリのWebアプリへの移行などの参考にしていただきたい。

 なお本連載では、最小限のセットアップでWindowsを活用できるよう、可能な限りGUIツールを利用することなくコマンドラインとエディターのみで開発する方法を説明している。また、本連載では個別のファイルの拡張子には小文字の「.aspx」を利用するが、ASP.NETの埋め込みHTMLファイルを示す場合は「ASPX」(ASPXファイル)と大文字で記述する。

はじめに

 今回は、前回までに説明した埋め込みHTMLでのASPXの利用から一歩進めた開発手法について説明する。

 ここでの主眼は、アプリケーションを構成するモジュールの分離と、分離されたモジュール間のインターフェースのベストプラクティスを説明することにある。このため、これまでの記事と同様に、Webアプリとしての機能はともかくとして、見た目については全く考慮しない。

 結論を先に書くと、リクエストにはURLエンコードしたフォーム形式(具体的には、キーと値を「=」で結合し、各ペアを「&」で分離する)がよく、レスポンスにはJSONがよい。この方法が最も楽に記述でき、かつ汎用性がある。

 今回は、作成するWebアプリの背景説明から実行環境の設定までを扱う。

ストーリー

 サンプルとして取り上げるWebアプリは、以下のストーリーを持つ。

 A社のB部では、慶弔の都度、以下の手順で慶弔金の処理を行っている。

  • 対象者が所属する営業事務の担当(主に弔事の場合)や同期あるいは同じ課の後輩(主にお祝い事の場合)が幹事となる
  • 幹事は、対象者の他の同期および部内の全課長(配送リストがある)にお祝い金やお見舞金の集金についてのメールを送る。このとき、氏名、住所と口数を記入するためのExcelブックを添付する
  • 課長は、対象者が過去のプロジェクトに参加していたなど、課員に関連がありそうだと判断した場合に受信したメールを部下にブロードキャストする。また賛同する場合は、自分の住所と口数を添付されたExcelブックに記入して幹事に返送する
  • メールを受信した各自は、賛同する場合は、添付されているExcelブックに自分の住所と口数を記述して元の発信者(幹事)に送信する
  • 幹事は、集まったExcelブックの内容を1つのExcelブックに転記する
  • 幹事は、転記したExcelブックから、各自の口数を削除した新たなExcelブックを作成し対象者へ送る。対象者は受け取ったExcelブックをお礼状や年賀状などに利用する
  • 幹事は、元の転記後のExcelブックを元に、集金する

 この処理をWebアプリ化することを考える。

 この場合、重要なことは、現状の処理手順にとらわれずに必要なものだけを残すことだ。ほとんどの場合、現状の手続きは、要件として必要なものではなく、機能を実現するために必要なものにすぎない。

 例えば、現状のルールとして以下にリストするようなものがある。これらはルールであるが、その一方で問題点でもある。これらのルールが必要とされているのは、それらが現状において要件を実現するために必要だからだ。つまり、過去に発生した問題を解決するために自然と上記の手順に落ち着いたのであって、手順を構成している個々のルールが要件を構成しているわけではない。従って、Webアプリ化するに当たって、これらのルールは必要に応じて取捨すべき対象であり、要件としては考慮する必要はない。

処理上のルール

  • 各自は個別にExcelブックに住所と氏名、口数を記入して幹事へ送る
     − これは最初のうちはメールにフリーフォーマットで記載していたのだが、誤って課長へ返信してしまう事例が多発したことや、幹事がリスト化するときの負担が大きいということから、一度添付のExcelブックを利用することに落ち着いたという経緯がある
  • 幹事は全員から届くExcelブックから元帳へ転記する
     − 最初は共有フォルダーへExcelブックを配置し、各自が記入するようにしていたのだが、人によってはメールは受信できるが共有フォルダーへはアクセスできない環境(客先など)にいるなどの理由で、各自が個別のブックに記入する方法に変わったという経緯がある
  • 各課の課長は対象者ごとに部下への転送の可否を決め、部下へ転送する。また、課員から誤って課長に返送されたメールを幹事へ転送する
     − 最初は部全体への配送リストを利用したが、部全体を配送対象とすると、頻繁に対象者と関連がない部員にもメールが送られることになるので利用をやめたという経緯がある
     − その一方で、課長が部下へ転送しなかったため、知っていれば賛同したのに転送されてこなかったなどの不満がある
     − 近年は課横断的なプロジェクトの増加に伴って、異なる課間の交流が以前より拡大しているが、上記のように部全体への送信を取りやめた経緯があるため、そのままとなっている

 結局、上記のルールは、メールとExcelブックを利用していることから生じるのであり、必須な要件だけを取り出せば、以下の3点である。

  • 慶弔金の募集が行われていることを明示する
  • メンバーはそれぞれの募集に対して賛同してもよいし賛同しなくてもよい
  • 賛同するメンバーは期限内に自分の住所と氏名を対象者へ、氏名と口数を幹事に明らかにする
     − →対象者は賛同者の名前と住所を参照する
     − →幹事は賛同者の名前と口数を参照する

 すると、求められるWebアプリの機能は以下のユースケースとして規定できる。

  • メンバーは自分を幹事とする募集を作成し掲載する
  • メンバーは全ての慶弔金の募集を一覧表示する
  • メンバーは賛同する募集に対して口数を設定する
  • 幹事は自分が掲載した募集に賛同したメンバーの氏名と設定した口数のリストを参照する
  • 対象者は自分が対象の募集に賛同したメンバーの氏名と住所のリストを参照する

データベース設計

 上で求めたユースケースに従って、データモデルを決定する。

 まず、メンバーのテーブルが必要である。

 メンバーのテーブルには、氏名と住所を登録する。個々の募集に対してメンバーが登録すれば、住所はメンバーのテーブルから取得できるため、募集に対して住所の記入を不要とできる。

 なお、住所の更新や募集への賛同は各メンバー自らが行うことを前提とするため、ログイン処理も必要となる。ここでは、ログイン処理用に簡易であり安易なパスワード管理を行うことにする。

 次に、募集を登録するためのテーブルが必要となる。このテーブルは募集要項(目的、幹事、対象者、一口あたりの金額、最大口数、掲載期限など)を持つ。

 最後に、各募集とメンバーの口数を持つテーブルが必要となる。このテーブルによって、各募集と賛同したメンバーと設定した口数が保持される。

 上記をまとめたものが下図である。

データベースの構成 データベースの構成
  • membersテーブルは、メンバー表である
  • rostersテーブルは、募集表である
  • entriesテーブルは、募集表とメンバーの対応表である

環境の作成

 テーブルとWebアプリのためのディレクトリなどを用意する。

 前回までは、ディレクトリの作成についてはExplorerなどを利用したが、ここでは全てPowerShellで行う方法を示す。

$domoPath = "c:\inetpub\wwwroot\domo"      (1)
mkdir $domoPath
$domo = Get-Acl $domoPath                  (2)
$ruleDeveloper = New-Object System.Security.AccessControl.FileSystemAccessRule "ユーザー名",FullControl,"objectInherit,containerInherit",non,allow  (3)
$ruleIIS = New-Object System.Security.AccessControl.FileSystemAccessRule "BUILTIN\IIS_IUSRS",ReadAndExecute,"objectInherit,containerInherit",non,allow (4)
$domo.SetAccessRule($ruleDeveloper)        (5)
$domo.SetAccessRule($ruleIIS)              (5)
$domo | Set-Acl $domoPath                  (6)

$appDataPath = $domoPath + "\App_Data"
mkdir $appDataPath

$conn = New-Object System.Data.SqlClient.SqlConnection("Data Source=.\SQLEXPRESS;Integrated Security=SSPI;User Instance=true")
$conn.Open()
$cmd = $conn.CreateCommand()
$cmd.CommandText = "create database domodb on (name=domodb,filename='c:\inetpub\wwwroot\domo\App_Data\domodb.mdf')"                       (7)
$cmd.ExecuteNonQuery()
$cmd.CommandText = @"
use domodb
create table members                         (8)
(
  id int identity primary key
,name varchar(128) not null
,zip varchar(7)
,address varchar(128)
,password varchar(128)
,administrator tinyint
)
insert into members values ('管理者', null, null, null, 1)  (9)
insert into members values ('鈴木一郎', '1000999', '東京都千代田区', null, 0)
insert into members values ('鈴木二郎', '2000999', '東京都中央区', null, 0)
insert into members values ('鈴木三郎', '3000999', '東京都港区', null, 0)
insert into members values ('鈴木四郎', '3000999', '東京都港区', null, 0)
"@
$cmd.ExecuteNonQuery()
$cmd.CommandText = @"
create table rosters                     (10)
(
  id int identity primary key
,subject varchar(128) not null
,creator int not null
,owner int
,amount_per_unit int
,maxunit int
,location varchar(128)
,expire_date smalldatetime
,create_date datetime
)
"@
$cmd.ExecuteNonQuery()
$cmd.CommandText = @"
create table entries                    (11)
(
  roster_id int
,member_id int
,unit int not null
,create_date datetime
,primary key (roster_id, member_id)
)
"@
$cmd.ExecuteNonQuery()
$cmd.CommandText = "use master"
$cmd.ExecuteNonQuery()
$cmd.CommandText = "sp_detach_db domodb"
$cmd.ExecuteNonQuery()
$cmd.Dispose()
$conn.Close()

$ruleIIS = New-Object System.Security.AccessControl.FileSystemAccessRule "BUILTIN\IIS_IUSRS",Modify,allow            (12)
Get-ChildItem -path $appDataPath | % {
  $db = Get-Acl $_.FullName
  $db.SetAccessRule($ruleIIS)
  $db | Set-Acl $_.FullName
}

C:\Windows\System32\inetsrv\appcmd add app /site.name:"Default Web Site" /path:/domo /physicalPath:$domoPath


集金名簿用データベースを作成するためのスクリプト(PowerShell)
(1)ここでは「domo」というディレクトリ名(アプリ名)とする。
  (2)
アクセス制御リストを取得する。
  (3) ユーザー名で指定したユーザーのフルコントロール権限ルールを作成する。ユーザー名は適宜実際のユーザー名で置き換える。
  (4) IIS用に読み込みと実行権限を与える権限ルールを作成する。
  (5) (2)で取得したアクセス制御リストに、(3)および(4)のルールを追加する。
  (6) 変更したアクセス制御リストをdomoディレクトリに適用する。
  (7) データベース(ここでは「domodb」という名前)を作成する。
  (8) メンバー用テーブルを作成する。
  (9) テスト用に初期ユーザーを作成する*1
  (10) 募集表を作成する。なお、ストーリーとして、慶弔金募集以外に、忘年会や新年会などの出席連絡にも利用できるように、開催地を格納するためのカラム(location)を追加している。
  (11) 募集表とメンバーの対応表を作成する。ここではroster_idとmember_idの複合主キーを利用している。複合主キーを設定する場合は、ここで示したように、「primary key (カラムリスト)」の形式を使う*2
  (12) (4)によってdomo以下のディレクトリは読み込みと実行権限をIISに設定してある。しかしApp_Data以下のディレクトリはIISからの更新権限が必要である。このため更新権限をIISに対して与える。

*1 管理者ユーザーはadministraotrというカラムに「1」を設定することでログイン後に管理ページの表示などの処理を可能としているが、本記事ではこれらの処理は含まない。

*2 外部キーの設定はしていない。プログラム的に制約をチェックできるため特に用意する必要がないことが理由だが、カスケード削除をするのであれば設定してもよい。ただ、筆者の実感として、カスケード削除や外部キーは論理的には意味があるが、実運用、特にソフトウェアで管理する場合は実装に対する無駄な制約となるため避けた方が無難である。


 なお、署名無しのPowerShellスクリプト(拡張子「.ps1」)をPowerShell内から実行するには、以下のコマンドを実行して、実行制限を解除する必要がある。

Set-ExecutionPolicy RemoteSigned                        (1)
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned     (2)


実行制限を解除するコマンド
  (1)実行ポリシーを『リモートについては署名が必要』に変更し、ローカルに配置したPS1の署名は不要とする。
  (2)(1)の設定はPowerShell全体の設定である。現在のユーザーに関する権限設定が優先されるため、現在のユーザーの実行ポリシーも同様に変更する。

 以上で、集金名簿用データベースの作成は終了だ。次回は、このデータベースを利用するWebアプリの作成について見ていくことにしよう。

「連載:ASP.NETによる軽量業務アプリ開発」のインデックス

連載:ASP.NETによる軽量業務アプリ開発

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。