آموزش ASP.NET MVC & web API (بخش دوم)
بسم الله الرحمن الرحیم
این دوره آموزشی دارای پیش نیاز می باشد، برای مطالعه پیش نیاز این دوره لطفا مقاله "آموزش WebApi" مطالعه کنید.
مشاهده تمامی آموزش های دوره آموزش Web API
بخش اول این مقاله را می توانید از طریق این لینک مطالعه بفرمایید
آموزش Web API– سطح پیشرفته
بخش دوم – آموزش Web API و ASP.NET MVC و RESTfull و در نهایت backbonejs
آموزش Web API
این کد از شی های IReviewRepository و ICategoriesRepository برای انجام اقدامات مناسب بر اساس درخواست صورت گرفته استفاده می کند(برای درخواست های GET اطلاعات را دریافت می کند و برای درخواست های POST اطلاعات را اضافه می کند). این respositorie ها توسط Ninject در Constructor Injection تزریق می شوند.
توجه داشته باشید برخی از متدها data type های متفاوتی را برمی گردانند (return). WebAPI اجازه می دهد که شما نوع های داده ای non-string (مانند IEnumerable<Review>) را برگردانید، WebAPI برای ارسال، اطلاعات را به صورت اشیا serialize تبدیل خواهد کرد. شما همچنین می توانید از کلاس HttpResonseMessage بک HTTP status code مشخص، در زمان بازیابی اطلاعات بر می گرداند. یکی از روش های ایجاد یک شی از HttpResponseMessage فراخوانی Request.CreateResponse(responseCode, data) می باشد.
ما می توانیم وضعیت صحت برنامه خود را توسط ابزارهایی همچون Fiddler2 بررسی کنیم.
اگر تا کنون Fiddler را نصب نکرده اید این ابزار را نصب کنید، حتی اگر .NET developer نیستید باز این ابزار بسیار می تواند به شما کمک دهد. Fiddler یک ابزار خارق العاده برای HTTP debugging می باشد.
حال Fiddler را اجرا کنید و بر روی RequestBuilder کلیک کنید و سپس آدرس API URL ایی که می خواهید آن را تست کنید، وارد نمایید. نوع درخواست (request) خود را انتخاب کنید. اگر یک درخواست POST ایجاد می کنید، مطمئن شوید header شما Content-Type: application/json باشد سپس یک ساختار معتبر JSON درون بخش request body قرار دهید.
تصویر زیر نحوه ارسال یک درخواست POST به api/reviews را نمایش می دهد.
بسم الله الرحمن الرحیم
این دوره آموزشی دارای پیش نیاز می باشد، برای مطالعه پیش نیاز این دوره لطفا مقاله "آموزش WebApi" مطالعه کنید.
مشاهده تمامی آموزش های دوره آموزش Web API
بخش اول این مقاله را می توانید از طریق این لینک مطالعه بفرمایید
آموزش Web API– سطح پیشرفته
بخش دوم – آموزش Web API و ASP.NET MVC و RESTfull و در نهایت backbonejs
آموزش Web API
این کد از شی های IReviewRepository و ICategoriesRepository برای انجام اقدامات مناسب بر اساس درخواست صورت گرفته استفاده می کند(برای درخواست های GET اطلاعات را دریافت می کند و برای درخواست های POST اطلاعات را اضافه می کند). این respositorie ها توسط Ninject در Constructor Injection تزریق می شوند.
توجه داشته باشید برخی از متدها data type های متفاوتی را برمی گردانند (return). WebAPI اجازه می دهد که شما نوع های داده ای non-string (مانند IEnumerable<Review>) را برگردانید، WebAPI برای ارسال، اطلاعات را به صورت اشیا serialize تبدیل خواهد کرد. شما همچنین می توانید از کلاس HttpResonseMessage بک HTTP status code مشخص، در زمان بازیابی اطلاعات بر می گرداند. یکی از روش های ایجاد یک شی از HttpResponseMessage فراخوانی Request.CreateResponse(responseCode, data) می باشد.
ما می توانیم وضعیت صحت برنامه خود را توسط ابزارهایی همچون Fiddler2 بررسی کنیم.
اگر تا کنون Fiddler را نصب نکرده اید این ابزار را نصب کنید، حتی اگر .NET developer نیستید باز این ابزار بسیار می تواند به شما کمک دهد. Fiddler یک ابزار خارق العاده برای HTTP debugging می باشد.
حال Fiddler را اجرا کنید و بر روی RequestBuilder کلیک کنید و سپس آدرس API URL ایی که می خواهید آن را تست کنید، وارد نمایید. نوع درخواست (request) خود را انتخاب کنید. اگر یک درخواست POST ایجاد می کنید، مطمئن شوید header شما Content-Type: application/json باشد سپس یک ساختار معتبر JSON درون بخش request body قرار دهید.
تصویر زیر نحوه ارسال یک درخواست POST به api/reviews را نمایش می دهد.
وقتی شما درخواست خود را ارسال کردید، یک پاسخ مشابه تصویر زیر دریافت خواهید کرد.
مشاهده می کنید که کد وضعیت درخواست POST ارسالی مقدار 201 را برگردانده است. WebAPI با ارسال کد وضعیت صحت RESTfull web service کار بزرگی انجام می دهد.
با WebAPI می توانید routing را برای controller ها مشخص کنید ( این کار مشابه MVC است). در MVC4 فایل RouteConfig.cs در پوشه App_Start ایجاد شده است. می توانید با استفاده از این فایل routing برنامه خود را مشابه MVC مشخص کنید.
// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/App_Start/RouteConfig.cs
routes.MapHttpRoute(
name: "GetReviewComments",
routeTemplate: "api/reviews/comments/{id}",
defaults: new { id = RouteParameter.Optional, controller = "Reviews", action = "GetReviewComments" }
);
routes.MapHttpRoute(
name: "GetByCategories",
routeTemplate: "api/reviews/categories/{category}",
defaults: new { category = RouteParameter.Optional, controller = "Reviews", action = "GetByCategory" }
);
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
DefaultApi توسط ویژوال استادیو به صورت پیش فرض ایجاد می شود. دو routes دیگر routes های ما برای Reviews controller هستند. در مورد مباحث routing مطالب زیادی وجود دارد، اگر فرصت شود و شما دوستان مثل همیشه پیشنهاد کنید، انشالله در مورد این مبحث نیز یک آموزش کامل قرار می دهیم.
MVC 4
MVC 4 بیشتر موارد Web API را پوشش می دهد. ما چندین متد را برای نمایش اطلاعات خواهیم نوشت. ما از API ها استفاده خواهیم کرد اما فعلا از repositorie خود در HomeController استفاده می کنیم. HomeController به وسیله ویژوال استادیو ایجاد می شود، ما این متد را فقط برای نمایش اطلاعات تغییر می دهیم. در ابتدا لیست category ها را از طریق متد Index بدست می آوریم.
// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Controllers/HomeController.cs
private ICategoriesRepository _categoriesRepository { get; set; }
private IReviewRepository _reviewRepository { get; set; }
public HomeController(ICategoriesRepository categoriesRepository, IReviewRepository reviewRepository)
{
_categoriesRepository = categoriesRepository;
_reviewRepository = reviewRepository;
}
public ActionResult Index()
{
var categories = _categoriesRepository.GetAll();
return View(categories);
}
در اینجا همچنان از DI به صورت ارسال repositories به عنوان پارامتر، در تابع سازنده HomeController استفاده می کنیم. Ninject به صورت خودکار کلاس مناسب را برای ما تزریق می کند. برای نمایش category ها در متد Index، کمی کد اضافه می کنیم.
// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Views/Home/Index.cshtml
@model IEnumerable<Reviewed.Models.Category>
<h3>Pick a Category:</h3>
<ul class="round">
@foreach(var category in Model)
{
<li>
<a href="@Url.Action("Reviews", new { id = @category.Name} )">@category.Name</a>
</li>
}
</ul>
این یک لیست از category ها که کاربر می تواند بر روی آن کلیک کند، تولید می کند. یک متد جدید به HomeController اضافه می کنیمف این متد برای دریافت یک Review است. ما می توانیم متد Reviews را به صورت زیر فراخوانی کنیم.
// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Controllers/HomeController.cs
public ActionResult Reviews(string id)
{
List<Review> reviews = new List<Review>();
if (!string.IsNullOrWhiteSpace(id))
{
reviews = _reviewRepository.GetByCategory(_categoriesRepository.GetByName(id)).ToList();
}
else
{
reviews = _reviewRepository.GetAll().ToList();
}
foreach (var review in reviews)
{
var comments = _reviewRepository.GetReviewComments(review.Id);
review.Comments = comments.ToList();
}
return View(reviews);
}
چون قبلا یک route برای /{controller}/{action}/{id} تعریف شده است، شما می توانید از آدرسی شبیه Home/Reviews/Doctors استفاده کنید. routing engine مقدار Doctors را به عنوان پارامتر id به متد Reviews انتقال می دهد. ما از id برای بازیابی تمامی review هایی که به این id مرتبط هستند استفاده می کنیمف این id مشخص کننده id یک category است. اگر هیچ category با این id موجود نبود، ما به صورت خیلی ساده تمامی review های موجود در دیتابیس را بازیابی می کنیم. حال ما تمامی review ها را داریم و لیست review خود را به view انتقال می دهیم.
کد view ما در بخش زیر نمایش داده شده است.
// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Views/Home/Reviews.cshtml <div class="reviews"> @foreach(var review in Model) { <h3>@review.Topic</h3> <p> @review.Content </p> var hasComments = review.Comments.Count > 0 ? "is-comments" : null; <ul class="@hasComments"> @foreach(var comment in review.Comments) { <li> <strong>@(!comment.IsAnonymous ? string.Format("{0} says,", comment.Email) : "")</strong> <blockquote>@comment.Content</blockquote> </li> } </ul> } </div>
این کد از ویژگی جدید MVC 4 استفاده می کنید. خصوصیت کلاس عناصر <ul/> نمایش داده نخواهد شد اگر hasComments عنصر null باشد.
JavaScript
صفحات وب مدرن بدون JavaScript کامل نمی شوند. ما برای فراخوانی سرویس Web API از JavaScript استفاده خواهیم کرد. ما از Backbone.js برای اینکار استفاده خواهیم کرد، پس باید Backbone را به همراه dependency Underscore آن دانلود کنید. فایل های JavaScript را در پوشه Scripts قرار دهید.
در این بخش می خواهیم با یکی دیگر از ویژگی های MVC 4 به نام script bundling آشنا شویم. در پوشه App_Start فایل BundleConfig.cs را پیدا کنید. در این فایل شما می توانید فایل های JavaScript را با هم bundle (بسته) کنید. فایل را باز کند تا یک bundle جدید به صورت زیر اضافه کنیم.
bundles.Add(new ScriptBundle("~/bundles/backbone").Include(
"~/Scripts/underscore*",
"~/Scripts/backbone*"));
سپس در فایل /Views/Shared/_Layout.cshtml، کد زیر را به انتهای body صفحه خود اضافه کنید.
@Scripts.Render("~/bundles/backbone")
اگر برنامه در حالت debug اجرا شود، این کد scripts شما را bundle خواهد کرد در غیر این صورت این کد اجرا نخواهد شد.
ما با استفاده از MVC 4 یک کد برای بازیابی اطلاعات review و نمایش آنها نوشیم که این روش خوبی است اما یک روش محبوب تر استفاده Ajax است. پس اجازه دهید کد خود را refactor کنیم و از Backbone.js استفاده کنیم.
به وسیله JavaScript ما view های خود را به صورت غیرهمزمان (asynchronously) پس از لود شدن صفحه بازیابی خواهیم کرد. یک فایل در پوشه Scripts با نام home.js ایجاد کنید و کد زیر را در آن قرار دهید.
var Review = Backbone.Model.extend();
var Reviews = Backbone.Collection.extend({
model: Review,
url: '/api/reviews'
});
var Comment = Backbone.Model.extend({});
var Comments = Backbone.Collection.extend({
model: Comment,
url: '/api/reviews/comments/'
});
این ها مدل های داده ای JavaScript هستند. مطابق با URL ارسالی سرویس Web API مربوطه برای بازیابی اطلاعات فراخوانی می شود.
حال می خواهیم کد view خود را بنویسیم.
var ListReviews = Backbone.View.extend({
el: '.reviews',
initialize: function() {
this.collection.on('reset', this.render, this);
this.collection.fetch();
},
render: function() {
this.collection.each(this.renderItem, this);
},
renderItem: function(model) {
var view = new ReviewItem({
model: model
});
this.$el.append(view.el);
}
});
این view برای لیست کامل review ها می باشد. هنگامی که متد fetch() مربوط به collection فراخوانی می شود،
رویداد reset اجرا و سپس render() فراخوانی می شود. پارامتر سوم انتقال داده شده به متد on() مشخص کننده scope یا چیزی که در callback متد render() خواهد آمد، می باشد. در متدrender()، متدeach() مربوط به collection، متد renderItem() انتقال داده می شود. متدrenderItem() به ازای هر آیتم در collection فراخوانی خواهد شد و به ازای هر review یک ReviewItem جدید ایجاد خواهد شد.
var ReviewItem = Backbone.View.extend({
events: {
'click a': 'getComments'
},
tagName: 'li',
initialize: function () {
this.template = _.template($('#reviewsTemplate').html());
this.collection = new Comments();
this.collection.on('reset', this.loadComments, this);
this.render();
},
render: function () {
var html = this.template(this.model.toJSON());
this.$el.append(html);
},
getComments: function () {
this.collection.fetch({
data: {
Id: this.model.get('Id')
}
});
},
loadComments: function () {
var self = this,
item;
this.comments = this.$el.find('ul');
this.collection.each(function (comment) {
item = new CommentItem({
model: comment
});
self.comments.append(item.el);
});
this.$el.find('a').hide();
}
});
Web API یکی از بخش های خارق العاده ASP.NET stack می باشد. این یک ویژگی غنی REST بر اساس API است که هرگز کار با آن ساده نبود.
ReviewItem view مسئول تفسیر هر review منحصر به فرد است. متد initialize() قالب(template)استفاده شده در هر review را کامپایل می کند.این template در عنصر <script/> قرار می گیرد. Backbone قالب (template) را از <script/> خارج می کند و آن را با review ترکیب می کند.
click event handler توضیحات را برای هر review لود ومقداردهی می کند. هنگامی که لینک کلیک شود، متد getComments() فراخوانی شده و توضیحات مربوطه به وسیله ارسال یک Id به Web API service بازیابی می شود.
متد fetch() تنها یک انتزاع از متد $.ajax جی کوئری (jQuery) است، پس پارامترهای معمولی Ajax (مانند data) می توانند در فراخوانی fetch() می توانند ارسال شوند. در نهایت متد loadComments() اجرا خواهد شد و یک view CommentItem جدید برای هر توضیح (comment) بازیابی شده ایجاد خواهد شد. tagName در این view اطمینان ایجاد می کند که view با یک <li/> به عنوان پراپرتی $el ساخته شده است.
var CommentItem = Backbone.View.extend({
tagName: 'li',
initialize: function () {
this.template = _.template($('#commentsTemplate').html());
this.render();
},
render: function () {
var html = this.template(this.model.toJSON());
this.$el.html(html);
}
});
این یک view ساده می باشد که هر عنصر comment را render می کند. حال view Review.cshtml را تغییر خواهیم داد.
@model IEnumerable<Reviewed.Models.Review>
@section scripts {
<script type="text/javascript" src="/Scripts/home.js"></script>
}
<div class="reviews">
<ul></ul>
</div>
<script type="text/html" id="reviewsTemplate">
<h3><%= Topic %></h3>
<p>
<%= Content %>
</p>
<a href="#comments">Load Comments</a>
<ul></ul>
</script>
<script type="text/html" id="commentsTemplate">
<li>
<strong><%= !IsAnonymous ? Email + " says," : "" %></strong>
<blockquote><%= Content %></blockquote>
</li>
</script>
@section scripts را در کد بالا در نظر بگیرید. این یک ویژگی جدید از MVC 4 نیست اما یک ابزار بسیار خوب برای render کردن یک بخش خاص از JavaScript است. در فایل _layout.cshtml، نیز یک @RenderSection("scripts", required: false) وجود دارد کهبخش تعریف شده در view را render می کند. عنصرهای <script/>، Underscore template هستند تا محتوا بر اساس آن ها render شود. آنها به دنبال دستور Ruby-esque هستند و هر چیزی که درون <% %> باشد به عنوان یک دستور ارزیابی می شود. هر چیزی که درون <%= %> باشد در قالب HTML نمایش داده خواهد شد. شرطها، دستورات و حلقه ها می توانند به این صورت استفاده شوند.
<ul>
<script type="text/html" id="template">
<% for (var i = 0; i < list.length; i++) { %>
<li><%= list[i] %></li>
<% } %>
</ul>
<% if (someCondition) { %>
<%= output %>
<% } %>
</script>
این یک template بود که می تواند به صورت زیر مورد استفاده قرار گیرد.
var template = _.template($('#template').html());
var html = template({
someCondition: true,
output: 'hello world',
list: ['foo', 'bar', 'bam']
});
در وب JavaScript templating frameworks زیادی وجود دارد مانند :
Handlebars.js, mustache.js, و Hogan.js این موارد محبوبترین ها هستند.
این گزینه ها را بررسی کنید و پس از اطمینان یکی از آنها را برای کارهای خود انتخاب کنید.