■Webサービスでマスタメンテナンス機能を実装する(1)

今回は「ClickOnceアプリ-Webサービス」という構成で簡単なマスタメンテナンス画面を作成してみます。 実際にDBに接続し、データの取得等も行ってみたいと思います。オラクルのインストール時にデフォルトで Scottスキーマに入っている「EMP」表を使用します。EMP表のカラム構成は以下ですが、今回は 「EMPNO」、「ENAME」、「JOB」の3つのカラムのみを使用します。プライマリキーは「EMPNO」です。

EMPNO      NOT NULL NUMBER(4)
ENAME      VARCHAR2(10)
JOB        VARCHAR2(9)
MGR        NUMBER(4)
HIREDATE   DATE
SAL        NUMBER(7,2)
COMM       NUMBER(7,2)
DEPTNO     NUMBER(2)

作成するClickOnceアプリの画面は以下です。入力された「従業員No(EMPNO)」の従業員が既に存在する場合、 「従業員名(ENAME)」と「職種(JOB)」を表示し、「登録」ボタンが「更新」ボタンに切り替わります。 「従業員No」からフォーカスが外れた時点で、Webサービスに問い合わせを行い、「従業員名」と「職種」を 取得してきます。もちろん、従来のWebシステムのようにその度に画面が再表示される事はありません。 今回は従業員Noから従業員情報を取得するところまでをご紹介し、次回、従業員情報を登録するところ をご紹介します。

では、Webサービス側のソースから見ていきたいと思います。Webサービス側で作成したクラスは WebServiceクラスを継承し、[WebMethod]を持つ「EmployeeService」クラスとクライアントとの間で 従業員情報をやり取りするために従業員情報を格納する「Employee」クラスです。Webサービスと クライアント間のデータのやり取りには「DataSet」クラス等を使用する方法も有りますが、 今回は「Employee」クラスというEntityを使用します。以下が「Employee」クラスのソースです。

「EmployeeService.asmx」

	public class Employee
	{
		private int empNo;

		private string empName;

		private string job;

		public int EmpNo
		{
			set { empNo = value; }
			get { return empNo; }
		}

		public string EmpName
		{
			set { empName = value ;}
			get { return empName; }
		}

		public string Job
		{
			set { job = value; }
			get { return job; }
		}
	}

次に[WebMethod]を持つクラスの「EmployeeService」クラスのソースです。

「EmployeeService.asmx」

		[WebMethod]
		public Employee GetEmployee(int empNo)
		{
			Employee emp = null;

			OracleConnection connect = null;
			OracleDataReader reader = null;
			//従業員情報を取得するSQL
			const String query = "select EMPNO,ENAME,JOB from EMP where EMPNO = :pEmpNo";

			try{
				connect = new OracleConnection("Data Source=X40;User ID=scott;Password=tiger");

				OracleCommand command = new OracleCommand(query,connect);
				//従業員Noをパラメータに設定する
				command.Parameters.Add("pEmpNo", OracleType.Int32).Value = empNo;

				connect.Open();

				reader = command.ExecuteReader();

				if(reader.Read()){
					emp = new Employee();
					emp.EmpNo = reader.GetInt32(0);
					emp.EmpName = reader.GetString(1);
					emp.Job = reader.GetString(2);
				}

			}catch(OracleException e){
				emp.EmpName = e.Message;
			}catch(Exception e){
				emp.EmpName = e.ToString();
			}finally{

				try{
					if(reader != null){
						reader.Close();
					}
				}catch(Exception e){}

				try{
					if(connect != null)
						connect.Close();
				}catch(Exception e){}
			}

			return emp;
		}

このソースのポイントは、EMP表から取得したレコードを「Employee」クラスに格納して、クライアントに 返している点です。何か特別な事をする事なく、このように簡単なコードで従業員情報をクライアントに 戻す事ができるのです。

「MainForm.cs」

1:     partial class MainForm : Form
2:     {
3:           public delegate void SetEmployeeInfo(Employee emp); //従業員情報をセットする時に使用するデリゲート
4:
5:           public MainForm()
6:         {
7:             InitializeComponent();
8: 	      //従業員No.フィールドがフォーカスを失った場合のイベントハンドラ
9:             tb_EmpNo.LostFocus += new EventHandler(tb_EmpNo_LostFocus);
10:        }
11:
12:        void tb_EmpNo_LostFocus(object sender, EventArgs e)
13:        {
14:            try
15:            {
16:                String value = tb_EmpNo.Text;
17:
18:		   //従業員Noに入力が無かった場合
19:                if (!notNullCheck(value))
20:                    return;
21:
22:		   //従業員Noがアルファベットか数字で無かった場合
23:                if (!isAlphabetNum(value))
24:                {
25:                    tb_EmpNo.BackColor = Color.DeepPink;
26:                    return;
27:                }
28:
29:                tb_EmpNo.BackColor = Color.White;
30:		   //Webサービスを非同期で呼び出す
31:                EmployeeService service = new EmployeeService();
32:                service.BeginGetEmployee(Int32.Parse(tb_EmpNo.Text), new AsyncCallback(serviceCallBack), service);
33:            }
34:            catch (System.Web.Services.Protocols.SoapException ex)
35:            {
36:                MessageBox.Show("サーバーとの通信に失敗しました。");
37:            }
38:
39:        }
40:
41:        private void serviceCallBack(IAsyncResult ar)
42:        {
43:            EmployeeService service = (EmployeeService)ar.AsyncState;
44:            Employee emp = service.EndGetEmployee(ar);
45:	       //従業員情報をセットするメソッドを呼び出す
46:            Invoke(new SetEmployeeInfo(setEmployeeInfo),new Object[]{emp});
47:
48:        }
49:
50:        private void setEmployeeInfo(Employee emp)
51:        {
52:	       //従業員が既に存在する場合
52:            if (emp != null)
53:            {
54:                tb_EmpName.Text = emp.EmpName;
55:                tb_job.Text = emp.Job;
56:                b_ok.Text = "更新";
57:            }
58:	       //従業員が存在しない場合
59:            else
60:            {
61:                b_ok.Text = "登録";
62:           }
63:
64:        }
65:
66:        private bool notNullCheck(String value)
67:        {
68:            if (value == null)
69:                return false;
70:            if (value.Length == 0)
71:                return false;
72:
73:            return true;
74:        }
75:
76:        private bool isAlphabetNum(String value)
77:        {
78:            if(value != null)
79:            {
80:                char[] inputChars = new char[value.Length];
81:                value.CopyTo(0,inputChars,0,inputChars.Length);
82:
83:                foreach (char c in inputChars)
84:                {
85:                    if (c < '0' || c > '9')
86:                    {
87:                        return false;
88:                    }
89:                }
90:            }
91:
92:            return true;
93:        }
94:   }

12行目から始まる「tb_EmpNo_LostFocus」メソッドで従業員Noがフォーカスを失った場合のイベントを処理します。 まず、入力された従業員Noの半角英数チェック等の基本的なチェックを行い、従業員情報を取得するために 「EmployeeService」を呼び出します。呼び出しは前回の 「Webサービスを非同期で呼び出す」で扱ったように 非同期で行います。Webサービスの処理が終了すると、41行目から始まる「serviceCallBack」 メソッドが呼び出されます。「EmployeeService」から従業員情報が格納された Employeeクラスのインスタンスが返されます。46行目では、従業員情報を各フィールドに設定するために さらに「setEmployeeInfo」メソッドを呼び出しています。これはFormのイベントを処理するための スレッド以外が、Formに置かれている各コントロールにアクセスする事が出来ないため、 (アクセスしようとするとExceptionが発生する)Formのイベントを処理するスレッドから 「setEmployeeInfo」を呼び出させているのです。

次回は従業員情報を登録する部分をご紹介します。

HOMEへ