ASP.NET Web API での HTML フォーム データの送信: フォーム urlencoded データ
パート 1: フォーム urlencoded データ
この記事では、フォーム urlencoded データを Web API コントローラーに投稿する方法を説明します。
Note
HTML フォームの概要
HTML フォームでは、GET または POST を使用してサーバーにデータを送信します。 form 要素の method 属性は、HTTP メソッドを提供します。
<form action="api/values" method="post">
既定のメソッドは GET です。 フォームで GET を使用する場合、フォーム データはクエリ文字列として URI でエンコードされます。 フォームで POST を使用する場合、フォーム データは要求本文に配置されます。 POSTed データの場合、enctype 属性は要求本文の形式を指定します。
enctype | 説明 |
---|---|
application/x-www-form-urlencoded | フォーム データは、URI クエリ文字列と同様に、名前と値のペアとしてエンコードされます。 これは POST の既定の形式です。 |
multipart/form-data | フォーム データは、マルチパート MIME メッセージとしてエンコードされます。 ファイルをサーバーにアップロードする場合は、この形式を使用します。 |
この記事のパート 1 では、x-www-form-urlencoded 形式について説明します。 パート 2 では、マルチパート MIME について説明します。
複合型の送信
通常は、複数のフォーム コントロールから取得した値で構成される複合型を送信します。 状態の更新を表す次のモデルについて考えてみましょう。
namespace FormEncode.Models
{
using System;
using System.ComponentModel.DataAnnotations;
public class Update
{
[Required]
[MaxLength(140)]
public string Status { get; set; }
public DateTime Date { get; set; }
}
}
POST を介して Update
オブジェクトを受け入れる Web API コントローラーを次に示します。
namespace FormEncode.Controllers
{
using FormEncode.Models;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
public class UpdatesController : ApiController
{
static readonly Dictionary<Guid, Update> updates = new Dictionary<Guid, Update>();
[HttpPost]
[ActionName("Complex")]
public HttpResponseMessage PostComplex(Update update)
{
if (ModelState.IsValid && update != null)
{
// Convert any HTML markup in the status text.
update.Status = HttpUtility.HtmlEncode(update.Status);
// Assign a new ID.
var id = Guid.NewGuid();
updates[id] = update;
// Create a 201 response.
var response = new HttpResponseMessage(HttpStatusCode.Created)
{
Content = new StringContent(update.Status)
};
response.Headers.Location =
new Uri(Url.Link("DefaultApi", new { action = "status", id = id }));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
[HttpGet]
public Update Status(Guid id)
{
Update update;
if (updates.TryGetValue(id, out update))
{
return update;
}
else
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
}
}
Note
このコントローラーはアクション ベースのルーティングを使用するため、ルート テンプレートは "api/{controller}/{action}/{id}" です。 クライアントはデータを "/api/updates/complex" に投稿します。
次に、ユーザーが状態の更新を送信するための HTML フォームを作成しましょう。
<h1>Complex Type</h1>
<form id="form1" method="post" action="api/updates/complex"
enctype="application/x-www-form-urlencoded">
<div>
<label for="status">Status</label>
</div>
<div>
<input name="status" type="text" />
</div>
<div>
<label for="date">Date</label>
</div>
<div>
<input name="date" type="text" />
</div>
<div>
<input type="submit" value="Submit" />
</div>
</form>
フォームの action 属性がコントローラー アクションの URI であることに注意してください。 いくつかの値が入力されたフォームを次に示します。
ユーザーが [送信] をクリックすると、ブラウザーは次のような HTTP 要求を送信します。
POST http://localhost:38899/api/updates/complex HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Content-Type: application/x-www-form-urlencoded
Content-Length: 47
status=Shopping+at+the+mall.&date=6%2F15%2F2012
要求本文には、名前と値のペアとして書式設定されたフォーム データが含まれていることに注意してください。 Web API は、名前と値のペアを自動的に Update
クラスのインスタンスに変換します。
AJAX を使用したフォーム データの送信
ユーザーがフォームを送信すると、ブラウザーは現在のページから移動し、応答メッセージの本文をレンダリングします。 応答が HTML ページの場合は問題ありません。 ただし、Web API では、通常、応答本文は空であるか、JSON などの構造化データが含まれます。 その場合、ページが応答を処理できるように、AJAX 要求を使用してフォーム データを送信する方が理にかなっています。
次のコードは、jQuery を使用してフォーム データを投稿する方法を示しています。
<script type="text/javascript">
$("#form1").submit(function () {
var jqxhr = $.post('api/updates/complex', $('#form1').serialize())
.success(function () {
var loc = jqxhr.getResponseHeader('Location');
var a = $('<a/>', { href: loc, text: loc });
$('#message').html(a);
})
.error(function () {
$('#message').html("Error posting the update.");
});
return false;
});
</script>
jQuery submit 関数は、フォーム アクションを新しい関数に置き換えます。 これにより、[送信] ボタンの既定の動作がオーバーライドされます。 serialize 関数は、フォーム データを名前と値のペアにシリアル化します。 フォーム データをサーバーに送信するには、$.post()
を呼び出します。
要求が完了すると、.success()
または .error()
ハンドラーはユーザーに適切なメッセージを表示します。
単純型の送信
前のセクションでは、複合型を送信しました。この複合型は、Web API によってモデル クラスのインスタンスに逆シリアル化されました。 文字列などの単純型を送信することもできます。
Note
単純型を送信する前に、代わりに複合型で値をラップすることを検討してください。 これにより、サーバー側でのモデル検証の利点が得られ、必要に応じてモデルを簡単に拡張できます。
単純型を送信する基本的な手順は同じですが、2 つの微妙な違いがあります。 まず、コントローラーで、パラメーター名を FromBody 属性で装飾する必要があります。
[HttpPost]
[ActionName("Simple")]
public HttpResponseMessage PostSimple([FromBody] string value)
{
if (value != null)
{
Update update = new Update()
{
Status = HttpUtility.HtmlEncode(value),
Date = DateTime.UtcNow
};
var id = Guid.NewGuid();
updates[id] = update;
var response = new HttpResponseMessage(HttpStatusCode.Created)
{
Content = new StringContent(update.Status)
};
response.Headers.Location =
new Uri(Url.Link("DefaultApi", new { action = "status", id = id }));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
既定では、Web API は要求 URI から単純型を取得しようとします。 FromBody 属性は、要求本文から値を読み取るように Web API に指示します。
Note
Web API は応答本文を最大 1 回読み取ります。そのため、要求本文から取得できるアクションのパラメーターは 1 つだけです。 要求本文から複数の値を取得する必要がある場合は、複合型を定義します。
次に、クライアントは次の形式で値を送信する必要があります。
=value
具体的には、単純型の名前と値のペアの名前部分は空である必要があります。 すべてのブラウザーで HTML フォームに対してこれをサポートしているわけではありませんが、次のようにスクリプトでこの形式を作成します。
$.post('api/updates/simple', { "": $('#status1').val() });
フォームの例を次に示します。
<h1>Simple Type</h1>
<form id="form2">
<div>
<label for="status">Status</label>
</div>
<div>
<input id="status1" type="text" />
</div>
<div>
<input type="submit" value="Submit" />
</div>
</form>
フォーム値を送信するスクリプトを次に示します。 前のスクリプトとの唯一の違いは、post 関数に渡される引数です。
$('#form2').submit(function () {
var jqxhr = $.post('api/updates/simple', { "": $('#status1').val() })
.success(function () {
var loc = jqxhr.getResponseHeader('Location');
var a = $('<a/>', { href: loc, text: loc });
$('#message').html(a);
})
.error(function () {
$('#message').html("Error posting the update.");
});
return false;
});
同じ方法を使用して、単純型の配列を送信できます。
$.post('api/updates/postlist', { "": ["update one", "update two", "update three"] });