همانطور که می دانیم، فرم های HTML از متد POST و یا GET برای ارسال اطلاعات به سمت سرور استفاده می کنند. صفت method از تگ Form این HTTP Method را مشخص می کند.
<form action="api/values" method="post">
متد پیش فرض برای فرم Get است و اگر فرم از Get استفاده کند محتویات فرم به شکل QueryString در URI به سمت سرور ارسال می شوند. و اگر فرم از Post استفاده کند، محتویات فرم در بدنه درخواست قرار خواهند گرفت. برای دیتای Post شده صفت enctype قالب و فرمت بدنه درخواست را مشخص می کند.
enctype را اگر application/x-www-form-urlencoded انتخاب کنیم، دیتای فرم به صورت یک لیست از جفت ها، شامل نام/مقدار ، مانند مقادیر موجود در QueryString ارسال خواهند شد. و این مقدار پیش فرض برای متد Post است.
و اگر enctype را multipart/form-data در نظر بگیریم، دیتای فرم در قالب multipart MIME message ارسال خواهند شد. از این قالب معمولا زمانی استفاده می کنیم که بخواهیم فایلی را سمت سرور آپلود کنیم.
در این مقاله به قالب x-www-form-urlencoded خواهیم پرداخت و در مقاله بعدی نیز در مورد multipart 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; }
}
}
حال یک کنترلر از نوع Web API را خواهیم دید که شیء Update را از طریق متدPOST دریافت می کند
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);
}
}
}
}
حال یک فرم HTML به شکل زیر را در صفحه قرار می دهیم تا کاربران بتوانند بروز رسانی وضعیت را از طریق فرم به Web API ارسال کنند.
<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 مربوط به متد داخل کنترلر است. تصویری از خروجی فرم را در زیر با مقادیر قرار داده شده داخل آن مشاهده می کنید.
وقتی کاربر کلید submit را کلیک می کند، مرورگر به درخواست 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 تبدیل می کند.
زمانی که کاربری در یک فرم کلید، Submit فرم را کلیک می کنید، مروگر از صفحه موجود عبور کرده و بدنه پیام پاسخ را تولید می کند. زمانی این کار مورد قبول است که پاسخ یک صفحه HTML باشد. با این وجود، در زمان استفاده از WEB API ، بدنه پاسخ، معمولا خالیست و یا بدنه پاسخ به شکل اطلاعات ساختیافته مانند JSON است.. در این صورت، شاید بهتر باشد، اطلاعات فرم را با استفاده از درخواست آژاکس ارسال کنیم تا صفحه ما بتواند پاسخ را به راحتی پردازش کند. کد زیر نشان می دهد که چگونه می توانیم به کمک آژاکس محتوای یک فرم را به یک Web API ارسال نماییم.
<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>
متد Submit در Jquery صفت action مربوط به فرم را با مقدار جدید جایگزین می کند. و این کار رفتار پیش فرض کلید Submit را نادیده می گیرد. متد serialize اطلاعات فرم را به جفت های نام/مقدار تبدیل می کند. برای ارسال محتوای فرم متد
$.post() را فراخوانی می کنیم.
زمانی که درخواست کامل می شود ، متد های
.success() و یا
.error() پیغام مناسب مرتبط را به کاربر نمایش می دهند.
ارسال انواع دیتای ساده
در مثال قبلی ما مجموعه هایی از اطلاعات را به WEb API ارسال کردیم و Web API هم آن اطلاعات را به یک نمونه از کلاس مدل تبدیل کرد. شما همچنین می توانید انواع دیتای ساده مانند یک string را هم به Web API ارسال نمایید.
قبل از ارسال یک نوع ساده (simple type) ، بهتر است مقدار مربوطه را داخل یک Complex Type قرار دهیم. این کار به ما این امکان را می دهد که از مزایای اعتبار سنجی مدل در سمت سرور نیز استفاده کنیم، این کار گسترش مدل را در صورت نیاز آسانتر می کند.
قدم های اولیه برای ارسال نوع ساده همانند روش قبل است با دو تفاوت.
تفاوت اول در این است که ما باید قبل از تعریف پارامتر ورودی متد ، صفت [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 می گوید که باید در بدنه درخواست دنبال این مقدار بگردد.
Web API یک بار به سراغ بدنه درخواست می رود، بنابراین تنها یک پارامتر از متد ما می تواند از بدنه درخواست استخراج شود. اگر نیاز داریم مقادیر بیشتری را از بدنه درخواست دریافت کنیم، باید از Complex Type ها استفاده کنیم.
تفاوت دوم در این است که سرویس گیرنده باید مقدار مربوط به نوع ساده را به شکل زیر ارسال کند:
=value
به طور مشخص این کار به این معنی است که بخش نام از جفت نام/مقدار باید خالی باشد. تمامی مرورگر ها از این نوع ارسال مقادیر فرم پشتیبانی نمی کنند، اما در عوض ما می توانیم در اسکریپت خود جفت بدون نام را به طریق زیر ارسال کنیم:
$.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>
و اسکریپتی که در زیر می بینید، این مقدار فرم را به سمت Web API ارسال می کند. تنها تفاوت با اسکریپت قبل در این است که آرگومان مورد نظر به متد 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"] });