jQuery (JavaScript) から C# のメソッドを呼び出す [単一レコード引数渡し編]

# はじめに
Visual Studio を使えば `Web ブラウザ`上で動作する JavaScript から `Web サーバー`上にある C# のコード(メソッド)を容易に呼び出すことができます。
実際に動作するコードを見れば、簡単にエレガントにリモート呼び出し(Ajax 呼び出し)ができることがわかるでしょう。

* jQuery から C# のメソッドを呼び出す基本的なやり方は[こちらの記事](http://qiita.com/akmiyoshi/items/16c4a65731f8ec32e233)を御覧ください。

* Ajax+JSONPでクロスドメインに外部APIと連携する方法は[こちらの記事](http://qiita.com/akmiyoshi/items/64ea9c3b7d8ed0de4eb9)を御覧ください。

* 今回から何回かにわたって、より複雑なメソッド(レコード、配列の受け渡し等)呼び出しのサンプルをご紹介します。

# テーブル定義
```sql
CREATE TABLE [Employees] (
  [Employee ID] int IDENTITY (1,1) NOT NULL
, [Last Name] nvarchar(20) NOT NULL
, [First Name] nvarchar(10) NOT NULL
, [Title] nvarchar(30) NULL
, [Birth Date] datetime NULL
, [Hire Date] datetime NULL
, [Address] nvarchar(60) NULL
, [City] nvarchar(15) NULL
, [Region] nvarchar(15) NULL
, [Postal Code] nvarchar(10) NULL
, [Country] nvarchar(15) NULL
, [Home Phone] nvarchar(24) NULL
, [Extension] nvarchar(4) NULL
, [Photo] image NULL
, [Notes] ntext NULL
, [Reports To] int NULL
);
```

# レコードオブジェクトの定義
クラス(RecEmployee)の定義です。クラス名に DataContract 属性がつけてあります。各フィールド(プロパティ)には DataMember 属性をつけています。このクラスをレコードの型としてjQuery (JavaScript) と C# の間でデータの受け渡しを行います。

```csharp:RecEmployeecs
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.Serialization;

namespace Northwind
{
    [DataContract]
    public class RecEmployee
    {
        public RecEmployee()
        {
        }
        public RecEmployee(Employee e)
        {
            PropUtil.CopyToFrom(this, e);
        }
        [DataMember]
        public int Employee_ID { get; set; }
        [DataMember]
        public string Last_Name { get; set; }
        [DataMember]
        public string First_Name { get; set; }
        [DataMember]
        public string Title { get; set; }
        [DataMember]
        public Nullable<System.DateTime> Birth_Date { get; set; }
        [DataMember]
        public Nullable<System.DateTime> Hire_Date { get; set; }
        [DataMember]
        public string Address { get; set; }
        [DataMember]
        public string City { get; set; }
        [DataMember]
        public string Region { get; set; }
        [DataMember]
        public string Postal_Code { get; set; }
        [DataMember]
        public string Country { get; set; }
        [DataMember]
        public string Home_Phone { get; set; }
        [DataMember]
        public string Extension { get; set; }
        //[DataMember]
        //public byte[] Photo { get; set; }
        [DataMember]
        public string Notes { get; set; }
        [DataMember]
        public Nullable<int> Reports_To { get; set; }
    }
    public class PropUtil
    {
        public static void CopyToFrom(object o1, object o2)
        {
            if (o1 == null) return;
            if (o2 == null) return;
            Type t1 = o1.GetType();
            Type t2 = o2.GetType();
            PropertyInfo[] members = t1.GetProperties();
            foreach (PropertyInfo p in members)
            {
                try
                {
                    t1.InvokeMember(
                        p.Name,
                        BindingFlags.SetProperty,
                        null,
                        o1,
                        new object[] {
                        t2.InvokeMember(p.Name, BindingFlags.GetProperty, null, o2, null)
                    });
                }
                catch (Exception /*ex*/)
                {
                    Debug.WriteLine(p.Name + "のコピーに失敗しました。");
                }
            }
        }
    }
}
```

# 呼び出される側(C#)のコード
呼び出されるメソッド側では(キャッシュの設定は除いて)JSONを明示的に受け取ったり、JSONを変換したりするコードは要りません。
戻り値もJSONの生成ではなく、単純に`return db.Employees.Count();`として整数値を返却しているだけです。
受け取った`RecEmployee`型のオブジェクト(レコード)を ADO.NET Entity Data Model を使ってデータベース内の`Employeesテーブル`に格納しています。この C# メソッド戻り値はレコードをINSERTした後のレコード件数です。

```csharp:Service1.svc.cs
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;

namespace Northwind
{
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    public class Service1
    {
        // 追加の操作をここに追加して、[OperationContract] とマークしてください
        [OperationContract, WebInvoke(Method = "GET")]
        public int AddEmployee(RecEmployee employee)
        {
            WebOperationContext.Current.OutgoingResponse.Headers.Add(
                "Cache-Control", "no-cache");
            using (var db = new NorthwindEntities())
            {
                var rec = new Employee();
                PropUtil.CopyToFrom(rec, employee);
                db.Employees.Add(rec);
                db.SaveChanges();
                return db.Employees.Count();
            }
        }
    }
}
```

# 呼び出す側(JavaScript/jQuery)のコード

```html:Views/Home/Index.cshtml
@{
    ViewBag.Title = "AJAX テスト";
}
<h3>@ViewBag.Title</h3>
<input id="buttonAddEmployee" type="button" value="buttonAddEmployee" />
<br />
<b>戻り値</b><div id="result"></div>
@section scripts {
<script>
    function onSuccess(data) {
        $("#result").text(JSON.stringify(data.d));
    }
    function onError(xhr) {
        alert("Error: " + xhr.responseText);
    }
    $("#buttonAddEmployee").click(function () {
        var args = {
            employee: JSON.stringify({
                First_Name: "トム", Last_Name: "クルーズ"
            })
        };
        $.ajax({
            type: "GET",
            url: '@VirtualPathUtility.ToAbsolute("~/Service1.svc/AddEmployee")',
            data: args,
            success: onSuccess,
            error: onError
        });
    });

</script>
}
```