ساخت REST Backend برای Angular با ASP.NET Core

دوشنبه 2 بهمن 1396

آیا با وجود پیش‌زمینه قدرتمندی که در #C دارید، به انگولار علاقه‌مندید؟ فقط node.js را دوست ندارید؟ آیا می‌خواهید در زمینه backend مطالب جدیدی را بیاموزید؟هر دلیلی که شما را اکنون به اینجا آورده است، جای درستی آمده‌اید!

ساخت REST Backend برای Angular با ASP.NET Core

در این آموزش، نگاهی دقیق به نحوه ساخت REST-API با فریم ورک ASP.NET Core خواهیمم داشت. شما نه تنها شیوه ایجاد برنامه سرور ASP Core را از ابتدا یاد می‌گیرید، بلکه نحوه ایجاد REST-Endpoint را فقط در چند مرحله ساده می‌آموزید.

اگرچه این آموزش بر روی "backend-stuff" تمرکز دارد، اما کار با انگولار را هم فراموش نخواهیم کرد. اگر این آموزش را تا انتها همراه ما باشید، نحوه درست کردن یک API جدید را در برنامه انگولار جدید خواهید آموخت.

آماده‌اید؟ پس بریم!

راه‌اندازی پروژه ASP.NET Core 2.0

اول از همه، باید dotnet sdk را دانلود و نصب کنیم. می‌توانید آن را از صفحه رسمی آن دانلود کنید.

سپس می‌توانیم یک پروژه جدید ایجاد کنیم. ما می‌خواهیم در این آموزش از dotnet-cli (رابط خط فرمان) استفاده کنیم. اگر از ویژوال استودیو استفاده می‌کنید، الگویی وجود دارد که دقیقا همین کار را انجام می‌دهد.

برای ایجاد پروژه جدید کنسولی را در محل دلخواه پروژه خود باز کنید. سپس دستور زیر را تایپ کنید:

dotnet new webapi -o {name-of-your-project}

البته باید  {} را جایگزین کنید مانند زیر:

dotnet new webapi -o myFirstProject

با این دستور، dotnet-cli را فراخوانی کردیم تا پروژه جدیدی را طبق الگوی "webapi" ایجاد کند. پروژه ساخته شده شامل یک برنامه سرور پایه با یک  REST-API پایه است و هیچ اجزای نمایشی ندارد، چرا که می‌خواهیم برنامه انگولارمان بخش‌ها را ایجاد کند.

الگوهای دیگری نیز وجود دارند. لیست کامل آن‌ها را می‌توانید با دستور زیرمشاهده کنید:

dotnet new help

همچنین الگویی به نام angular نیز وجود دارد که یک dotnet server-application و برنامه انگولار فقط در یک پوشه پروژه ایجاد می‌کند. همچنین ویژگی‌هایی مانند رندر کردن سمت سرور و فایل‌های ساخته شده در آن را دارد. اگر بخواهید می‌توانید از این الگو هم استفاده کنید. اما این الگو موارد زیادی (تا حدی حساس) دارد که شاید برای شروع کار مناسب نباشد.

در حال حاضر، ما روی اصول تمرکز می‌کنیم تا در حد امکان برنامه را ساده پیش بریم.

فایل‌ها

در مقایسه با یک برنامه خام node.js، متوجه خواهید شد که مجموعه‌ای از فولدرها و فایل‌ها در پوشه جدید ما وجود دارد.

بیایید نگاهی به کارکرد آن‌ها بیندازیم.

Program.cs

این فایل حاوی نقطه ورود برنامه ماست. هر برنامه سی‌ شارپی با یک متد استاتیک به نام Main شروع می‌شود. می‌توانیم این متد را در کلاس Program در این فایل بیابیم. کار تمام آن‌ها،‌ فراخوانی متد BuildWebHost است.

این فایل مسئول راه‌اندازی و پیکربندی server-app است. کاملا شبیه به متد bootstrap انگولار است.

Program.cs

public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }

تاکنون برخی تنظیمات در اینجا وجود داشتند. همان‌طور که می‌بینید، کلاس Startup فراخوانی شده است تا برنامه را پیکربندی کند. حالا نگاهی به کلاس بعدی بیندازیم.

Startup.cs

کلاس Startup.cs فایل اصلی پیکربندی کلاس شماست. در اینجا ما ویژگی‌ها و سرویس‌ها را به سرورمان اضافه می‌کنیم.

این کلاس دارای دو متد است. اولی ConfigureServices نامیده می‌شود.

Startup.cs

 public void ConfigureServices(IServiceCollection services)
{
      services.AddMvc();
}

این متد توسط زمان اجرا فراخوانی می‌شود. درون این متد، سرویس‌های معینی را به مجموعه سرویس‌های پاس داده شده به این متد، اضافه می‌کنیم.

این متدها می‌توانند از طریق تزریق وابستگی درون سازنده کلاس‌هایمان درخواست داده شوند.

به این ترتیب، این کلاس خیلی شبیه به انگولار است، زیرا هر دو از تزریق وابستگی استفاده می‌کنند. به جای افزودن سرویس‌هایمان به ارائه‌دهنده ویژگی‌های (provider-property) ماژول، آن‌ها را به ارائه‌دهنده مجموعه سرویس‌ها اضافه می‌کنیم.

به طور پیش‌فرض، سرویس MVC (مدل-ویو-کنترلر) اضافه شده است. این سرویس مسئول مسیریابی درخواست‌های http برای کنترلرهاست. گرچه نیازی به view نداریم، باید از این سرویس‌ها برای کنترلرهایمان استفاده کنیم تا آن‌ها کار کنند.

متد دوم Configure نامیده می‌شود. این متد یک نمونه از IApplicationBuilder و environment جاری را فراهم می‌کند.

Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseMvc();
}

با استفاده از سازنده برنامه می‌توانیم میان‌افزارهایی را به درخواست‌های خط لوله (pipeline) HTTP اضافه کنیم. هر درخواستی از این pipeline عبور می‌کند. مثلا می‌خواهیم اگر در هر درخواست خطایی وجود داشت، یک صفحه exception را نشان دهیم. ما فقط می‌خواهیم نشان دهیم که وقتی در حالت توسعه است، هیچ اطلاعات محسوسی در آن نفوذ نکند.

در نهایت، آخرین عنصر HTTP-pipeline ما،‌ میان افزار MVC (MVC-middleware) است که مسئول ارسال درخواست‌ها به کنترلر مربوطه است.

Controllers

فولدر "Controllers" شامل تمام کنترلرهای سرور ماست. حیرت انگیز است!

این فولدر باید دقیقا به همین نام باشد، زیرا MVC-middleware دقیقا به دنبال فولدری با همین نام می‌گردد.

کنترلر چیست؟

کنترلر کلاسی است که از کلاس Controller ارث‌بری می‌کند. مسئول مدیریت درخواست‌هایی از مسیرهای معین می‌باشد. به طور معمول یک کنترلر برای هر REST-endpoint ای که می‌خواهیم بسازیم، وجود دارد.

برای مثال، اگر شما یک "Cat"-endpoint بخواهید، ما باید یک Cat-controller ایجاد کنیم که مسئول مسیر "api/cat" می‌باشد.

dotnet-cli پیش از این برای ما کنترلری به نام "ValuesController" ایجاد می‌کرد. کاری که در پروژه جدید انجام می‌شود، حذف این کنترلر است. اما وقتی شروع به کار می‌کنید، می‌تواند برای نگهداری آن به عنوان یک مرجع سودمند باشد.

ایجاد اولین Controller

برای ایجاد cat-endpoint، باید اولین کنترلر خود را بسازیم. برای انجام این کار، یک فایل جدید درون پوشه کنترلر به نام "CatController.cs" ایجاد می‌کنیم. اگر از ویژوال استودیو استفاده می‌کنید، یک قالب فانتزی برای آن وجود دارد.

کنترلر ما شامل کلاسی به نام CatController می‌باشد که از اتربیوتی(attribute) به نام Rout استفاده می‌کند که به فریم‌ورک مسیر این کنترلر را می‌دهد. اتربیوت‌ها شبیه decorator‌ها در angular/TypeScript هستند، زیرا آن‌ها اطلاعات متا را به کلاس اضافه می‌کنند.

Controllers/CatController.cs

using Microsoft.AspNetCore.Mvc;

namespace firstProjectWebApi.Controllers
{
    [Route("api/[controller]")]
    public class CatController : Controller
    {

    }
}

در این مثال، کنترلر باید به درخواستی از مسیر "api/cat" گوش دهد. قسمت "[controller]" با نام کنترلر پر می‌شود. این درصورتی کار می‌کند که شما قرارداد نام‌گذاری را ({name}Controller) را رعایت کنید.

اتربیوتی معادل با این مثال:

Controllers/CatController.cs

[Route("api/cat")]

کنترلر به اتربیوت‌ها کاملا متکی است.

"REST-API"؟ آیا می‌توانید این را تحلیل کنید؟

همان‌طور که قبلا گفتیم، قصد داریم یک REST-API ایجاد کنیم. اما این دقیقا چیست؟ بیاید ببینیم.

REST شیوه‌ای استاندارد برای ساخت http-endpoints است.

این شیوه از استاندارد http-verbs استفاده می‌کند، مثل get، post، put و delete برای عملیات read، create، update و delete (CRUD).

همه این متدها (verbs) برای یک endpoint کاربردی هستند که نشان‌دهنده شیءای است که می‌خواهد تغییر کند. (شیءگرایی)

مثلا اگر می‌خواستیم یک cat را با هر شیوه‌ای تغییر دهیم، endpoint باید "cat" نامیده می‌شد.

در اینجا شیوه عملیات CRUD را می‌بینید.

عملیات CRUD

Create: برای ایجاد یک شیء جدید تحت یک Endpoint، یک درخواست post به REST-Endpoint که شامل شیء جدیدی است که در بدنه post ساخته می‌شود.

Read: برای خواندن همه اشیاء از یک endpoint، مثلا اگر شما بخواهید همه cats را بشناسید، یک درخواست get به "cat" endpoint ارسال می‌کنید. اگر به یک cat خاص علاقه‌مند باشید، id/name آن را به مسیر "cat/cat1" اضافه می‌کنید.

Update: برای به روز رسانی یک شیء، درخواست put به endpoint ارسال می‌شود. شناسه مورد نظر به مسیر اضافه می‌شود مثل "cat/cat1". اطلاعات شیء به بدنه put اضافه می‌شود.

Delete: برای حذف یک شیء، درخواست delete  به endpoint با شناسه شیء مورد نظر اضافه شده به مسیر ارسال می‌شود.

ایجاد REST-Endpoint

یک REST-Endpoint معمولی تمام عملیات CRUD که در بالا ذکر شد را اجرا می‌کند. برای انجام این کار، یک فولدر جدید به نام "Models" درون روت پروژه می‌سازیم. داخل آن یک فایل کلاس جدید به نام "Cat.cs" درست می‌کنیم.

داخل آن یک کلاس به نام Cat ایجاد می کنیم. سپس یک ویژگی به نام Name به آن اضافه می‌کنیم. البته اگر بخواهید می‌توانید ویژگی‌های بیشتری را به cat بدهید.

Models/Cat.cs

namespace firstProjectWebApi.Models
{
    public class Cat
    {
        public string Name { get; set; }
    }
}

حالا آماده‌ایم تا endpoint خود را با افزودن متدهای REST ارتقا دهیم.

پس بیایید آن‌ها را یک به یک اجرا کنیم.

گرفتن تمام عناصر (Cats)

همانطور که در بالا گفته شد، وقتی درخواست get برای endpoint بدون هیچ پارامتری برای مسیر ارسال می‌شود، سرور باید تمام عناصر را از endpoint برگرداند.

برای مدیریت این مورد، باید یک متد جدید برای کلاس‌مان ایجاد کنیم. همه متدهای REST یک متد C# دارند.

پس بیایید یک متد جدید بسازیم. اسم این متد مهم نیست. می‌توانیم با توجه به کاری که انجام می‌دهیم، آن را "GetAll" بنامیم.

Controllers/CatController.cs

[HttpGet]
public IEnumerable<Cat> GetAll()
{
    var list = new List<Cat>();
    list.Add(new Cat() { Name = "Lilly" });
    list.Add(new Cat() { Name = "Lucy" });
    return list;
}

این متد با اتربیوت "HttpGet" به فریم‌ورک می‌گوید باید درخواست‌های دریافت شده را مدیریت کند. همچنین IEnumerable ای از Catها بازمی‌گردانیم.

همچنین خروجی‌هایی را می‌سازیم. در یک برنامه واقعی این خروجی‌ها باید یا محاسبه شوند یا از پایگاه داده خوانده شوند.

گرفتن یک عنصر خاص (Cat)

حالا برای گرفتن یک cat خاص کوئری می‌زنیم. ما به id/name آن cat مورد نظر نیاز داریم. در REST افزودن شناسه و نام به مسیر انجام می‌شود، مثلا "api/cat/Lilly".

برای پیاده‌سازی داینامیک مسیر، پارامتر مسیری به اتربیوت "HttpGet" اضافه می‌کنیم. این پارامتر را درون براکت می گذاریم.

Controllers/CatController.cs

[HttpGet("{name}")]
public Cat Get(string name)
{
    return new Cat() { Name = name };
}

باز هم خروجی ها را در اینجا می‌سازیم.

درج یک عنصر جدید (Cat)

برای قرار دادن یک عنصر جدید در endpoint، متد http-post استفاده می‌شود. به همین دلیل باید از اتربیوت "HttpPost" استفاده کنیم.

علاوه‌براین ما باید cat را دریافت کنیم، پس باید از بدنه درخواست استفاده کنیم. برای اینکه پارامتری به نام cat را به متد اضافه کنیم از "FromBody" استفاده می‌کنیم. بدنه درخواست به صورت اتوماتیک به‌عنوان پارامتر، استخراج، تحلیل و تحویل داده می‌شود به متد.

وگرنه متد به درستی کار نمی‌کند.

Controllers/Controller.cs

[HttpPost]
public Cat Insert([FromBody]Cat cat)
{
    // write the new cat to database
    return cat;
}

آپدیت عنصر موجود (Cat)

برای آپدیت عنصر موجود در endpoint، از متد http-put استفاده می‌کنیم. باز هم اتربیوتی متفاوت برای آن وجود دارد. همچنین به پارامترها نیاز داریم،  نام cat ای است که قرار است آپدیت شود و شیءای که قرار است به آن تغییر یابد. این مسأله در اینجا خیلی حساس نیست، چون cat ما فقط نام دارد، اما به طور معمول اشیاء دارای ویژگی‌های بیشتری هستند.

name/id شیء بخشی از مسیر است، درست مانند گرفتن یک عنصر خاص. از سوی دیگر شیء cat در بدنه درخواست قرار می‌گیرد.

Controllers/CatController.cs

[HttpPut("{name}")]
public Cat Update(string name, [FromBody]Cat cat)
{
    cat.Name = name;
    // write the updated cat to database
    return cat;
}

حذف یک عنصر (Cat)

آخرین مورد حذف یک عنصر است. برای این کار از http-delete استفاده می‌کنیم. بنابراین اتربیوت مربوط به آن را انتخاب می‌کنیم. همچنین به نام cat نیاز داریم. این اطلاعات به عنوان پارامتر مسیر ارسال می‌شود.

Controllers/CatController.cs

[HttpDelete("{name}")]
public void Delete(string name)
{
    // delete the cat from the database

}

تحلیل ASP.NET Core REST-API در برنامه Angular

حالا سریعا به شما نشان می دهیم که چگونه API خود را با برنامه انگولار ادغام کنید. بنابراین می‌گذاریم که شما نحوه راه‌اندازی برنامه پایه angular-cli را بلد هستید.

پس یک برنامه پایه angular-cli را می‌سازیم. ما می خواهیم سرویس انگولاری بسازیم که REST-API جدید ما را مورد استفاده قرار دهد.

برای این کار از HttpClient انگولار استفاده می‌کنیم. بنابراین باید HttpClientModule را به یک ماژولی به انتخاب خود، به جز App-Module، ایمپورت کنید.

سپس سرویس جدیدی ایجاد کنید. ما آن را CatService می‌نامیم.

در اینجا این سرویس را می‌بینید:

cat.service.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';

export interface Cat {
  name: string;
}

@Injectable()
export class CatService {
  constructor(private http: HttpClient) {}

  getAllCats(): Observable<Cat[]> {
    return this.http.get<Cat[]>('http://localhost:8000/api/cats');
  }

  getCat(name: string): Observable<Cat> {
    return this.http.get<Cat>('http://localhost:8000/api/cats/' + name);
  }

  insertCat(cat: Cat): Observable<Cat> {
    return this.http.post<Cat>('http://localhost:8000/api/cats/', cat);
  }

  updateCat(cat: Cat): Observable<void> {
    return this.http.put<void>('http://localhost:8000/api/cats/' + cat.name, cat);
  }

  deleteCat(name: string) {
    return this.http.delete('http://localhost:8000/api/cats/' + name);
  }
}

نتیجه گیری

در این آموزش شیوه راه‌اندازی برنامه سرور را با ASP.NET Core  از ابتدا آموختیم و یک REST-API ساده اما کاربردی را با استفاده از ساخت میان‌افزارهای MVC ایجاد کردیم.

امیدواریم که این آموزش برای شما مفید بوده باشد.

موفق باشید. 

آموزش angular

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید