نحوه Handle کردن درخواست Get در ASP.NET Core Web API
شناسه پست: 2392
بازدید: 1468

از آنجایی که درخواست Get، رایجترین نوع درخواست است، از این رو نمیتوانیم هنگام ایجاد API آن را نادیده بگیریم. پس خیلی مهم است که handle کردن این نوع درخواست را یاد بگیرید.

در پست قبلی، ما یک الگوی repository برای بدست آوردن داده از دیتابیس ایجاد کردیم.

حالا زمان آن رسیده است که از این repository، برای business logic استفاده کنیم.

ما باید تمام منطق دیتابیس را داخل کلاسهای repository نگه داریم. کنترلرها، مسئول handle کردن درخواستها، اعتبارسنجی مدل و برگشت response ها به قسمت frontend اپلیکیشن خواهند بود.

با این کار ، کنترلر های ما بیش از حد درگیر کد نخواهند بود، بنابراین خواندن و نگهداری کد نیز آسان تر می شود.

این مقاله، قسمتی از مجموعه آموزشی زیر میباشد:

اگر می خواهید تمام آموزشهای لازم و پایه مربوط به این دوره آموزشی را ببینید ، لطفاً روی این لینک کلیک کنید: صفحه مقدمه برای این آموزش.

برای مطالعه قسمت قبلی، بر روی این لینک کلیک کنید: ایجاد پروژه NET Core WebApi. – الگوی Repository در NET Core.

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

کنترلرها و مسیریابی در WEB API

برای ایجاد یک کنترلر، بر روی پوشه Controllers داخل پروژه اصلی، راست کلیک کرده و Add/Controller را انتخاب کنید. سپس از منو، گزینه API Controller – Empty را انتخاب کنید و نام آن را OwnerController.cs بگذارید:

اضافه کردن کنترلر owner

کنترلر ما باید به این صورت باشد:

هر کلاس کنترلر web API از کلاس ControllerBase abstract که تمام رفتارهای لازم را برای کلاس مشتق شده در اختیار میگذارد ارث بری میکند.

همچنین، بالای کلاس controller، میتوانیم این کد را ببینیم:

این کد، ارائه دهنده مسیریابی در کنترلر میباشد و ما کمی در مورد مسیریابی در Web API ها صحبت خواهیم کرد.

مسیریابی Web API، درخواستهای ورودی HTTP را به اکشن متد صحیح در داخل کنترلر Web API هدایت میکند.

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

  1. مسیریابی بر اساس قرارداد
  2. Attribute routing

مسیریابی بر اساس قرارداد به دلیل اینکه یک قرارداد برای مسیرهای URL ایجاد میکند به این صورت نامگذاری شده است. اولین قسمت از این قانون مسیریابی، نام کنترلر و دومین قسمت، نام action method و سومین قسمت برای پارامتر اختیاری مورد استفاده قرار میگیرد. ما میتوانیم این نوع از مسیریابی را در کلاس Startup درون متد Configure پیکربندی کنیم:

قانون مسیریابی در asp.net core

Attribute routing از attribute ها برای مپ کردن مستقیم مسیرها به action method ها در کنترلر استفاده میکند. معمولا همانطور که میتوانید در کنترلر Web API مان توجه کنید، ما میتوانیم route پایه را بالای کلاس controller قرار دهیم. به طور مشابه، برای action method های مورد نظرمان نیز میتوانیم route هایشان را درست بالای خود آنها قرار دهیم.

در خواست GetAllOwners GET در NET Core.

شروع میکنیم.

اول از همه، روت پایه را از [Route(“api/[controller]”)] به [Route(“api/owner”)] تغییر میدهیم. اگرچه route اولی به خوبی کار خواهد کرد، اما با route دومی، ما دقیقا نشان میدهیم که مسیر باید به خود OwnerController اشاره کند.

حال باید اولین action method که قرار است که تمام owner ها از دیتابیس را برگرداند را ایجاد کنیم.

در اینترفیس IOwnerRepository، تعریفی برای متد GetAllOwners ایجاد کنید:

سپس این اینترفیس را داخل کلاس OwnerRepository پیاده سازی کنید:

در آخر، باید تمام owner ها را با استفاده از متد GetAllOwners داخل اکشن Web API برگردانیم.

هدف action method ها داخل کنترلرهای Web API، فقط برگرداندن نتایج نیست. برگرداندن نتایج، هدف اصلی اکشن متد است، اما فقط این نیست. بلکه شما باید به status code های response های Web API نیز توجه کنید. علاوه بر این، شما باید action هایتان را با HTTP attribute ها که نوع HTTP request آن اکشن را مشخص میکند را تعیین کنید.

در آخر، OwnerController را به این صورت تغییر میدهیم:

حالا اجازه بدید تا کمی این کد را شرح دهیم.

اول از همه، ما سرویسهای logger و repository را به داخل سازنده، تزریق میکنیم. سپس با مشخص کردن اکشن GetAllOwners با ویژگی [HttpGet]، تعیین میکنیم که این اکشن یک درخواست از نوع GET میباشد. در آخر،ما از هر دو پارامتر تزریق شده برای log کردن پیغامها و دریافت داده از کلاس repository استفاده میکنیم. اینترفیس IActionResult از نوعهای مختلفی از متدها حمایت میکند که نه تنها نتیجه، بلکه status code ها را نیز Return میکند. در اینجا، متد OK، تمام owner ها و همچنین کد وضعیت 200 که به معنی OK است را برمیگرداند. اگر یک exception رخ دهد، ما خطای internal server با کد وضعیت 500 را برمیگردانیم.

به این دلیل که هیچ route attribute بالای اکشن GetAllOwners وجود ندارد، از این جهت، Route برای این اکشن، همان api/owner (http://localhost:5000/api/owner) میباشد.

مجوزهای کد و تست نتیجه

میخواهیم به یک مورد دیگری داخل اکشن GetAllOwners اشاره کنیم. اگر به ساختار repository نگاه کنید، کلاسهای آن از کلاس abstract  RepositoryBase<T> و همچنین از اینترفیسهای مربوط به خودشان که از اینترفیس IRepositoryBase<T> مشتق میشوند، ارث بری میکنند. با استفاده از این سلسله مراتب، با تایپ کردن ،_repository.Owner. میتوانید متد سفارشی از کلاس OwnerRepository و همچنین تمام متدها از کلاس abstract RepositoryBase<T> را فراخوانی کنید.

اگر میخواهید از این نوع رفتار اجتناب کنید و اجازه دهید که اکشنهای داخل کنترلر، فقط متدها را از کلاسهای repository کاربر فراخوانی کنند، تمام کاری که باید انجام دهید این است که وراثت IRepositoryBase<T> را از IOwnerRepository حذف کنید. به این ترتیب، فقط کلاسهای repository کاربر قادر هستند که متدهای generic را از کلاس RepositoryBase<T> فراخوانی کنند. همچنین، اکشن متدها نیز فقط با کلاسهای repository کاربر ارتباط برقرار میکنند.

این دیگر بستگی به خود شما دارد که چطور می خواهید کد و مجوزهای خود را سازماندهی کنید.

برای بررسی کردن نتیجه، میخواهیم از ابزار Postman برای برای فرستادن درخواستها به سمت اپلیکیشن استفاده کنیم.

همچنین، شما میتوانید با مطالعه مقاله چند راه عالی برای استفاده از RESTful Api در #C، در مورد نحوه استفاده از web API با برنامه نویسی از طریق #C را بیشتر یاد بگیرید.

برنامه را اجرا میکنیم. ابزار Postman را باز میکنیم و یک درخواست ایجاد میکنیم:

درخواست با postman

عالی، همه چیز طبق برنامه کار میکند.

همانطور که میبینید، ما با این اکشن، تمام داده ها را از دیتابیس برگرداندیم. البته ما میتوانیم paging را به این اکشن اضافه کنیم و با برگرداندن فقط قسمتی از داده ها، آن را بهینه سازی کنیم.

قبل از اینکه ادامه دهیم، میخواهیم مورد دیگری را به شما نشان دهیم. اگر شما به  model classe ها نگاه کنید، متوجه میشوید که تمام خصوصیات، یک نام به عنوان ستون دارند که آن خصوصیات به آن مپ شده اند. اما شما میتوانید خصوصیت با نامی متفاوت از آن نامی که به آن اشاره میشود داشته باشید وآنها را به یکدیگر مپ کنید. برای این منظور، باید از ویژگی [Column] استفاده کنید.

پس اجازه دهید تا این کار را انجام دهیم.

ما میخواهیم نام خصوصیتهای AccountId و OwnerId در کلاسهای Owner و Account را به Id تغییر دهیم. همچنین میخواهیم ویژگی [Column] که ویژگی Id را به ستون مورد نظر در دیتابیس مپ میکند را اضافه کنیم:

حالا کارمان را ادامه میدهیم.

استفاده از DTO و AutoMapper

DTO یا Data Transfer Object به منظور انتقال داده ها از سرور به کلاینت به کار میرود. این دقیقا چیزی است که ما میخواهیم از آن برای انتقال داده ها از سرور به کلاینت استفاده کنیم.

اگر نگاهی به اکشن GetAllOwners بندازیم، میبینیم که ما از کلاس مدل Owner، برای واکشی داده ها از دیتابیس استفاده میکنیم (_repository.Owner.GetAllOwners() یک لیستی از آبجکتهای Owner را برمیگرداند) و همچنین آن نتیجه را به سمت کلاینت برمیگردانیم و این روش خوبی نیست. روش بهتر این است که یک model class برای واکشی داده ها از دیتابیس و یک کلاس DTO برای برگرداندن آن نتیجه به سمت کلاینت داشته باشیم. آبجکت DTO میتواند دقیقا مشابه آبجکت مدل باشد، اما با این حال، استفاده از آبجکتهای DTO خیلی بهتر است. زیرا اگر چیزی در پایگاه داده تغییر کند ، کلاس مدل باید تغییر کند اما این بدان معنا نیست که کلاینت خواهان نتایج تغییر یافته باشد. بنابراین آبجکت DTO تغییر نخواهد کرد.

به این ترتیب، یک پوشه جدید به نام DataTransferObjects در پروژه Entities ایجاد میکنیم و کلاس OwnerDto را داخل آن ایجاد میکنیم:

همانطور که میبینید، ما خصوصیت Accounts را اینجا نداریم، زیرا در حال حاضر ما قصد نداریم که اطلاعات مربوط به Account ها را به کلاینت نشان دهیم.

حالا تمام کاری که باید انجام دهیم این است که یک لیست دریافت شده از owner ها از دیتابیس را به لیست ownerDto مپ کنیم. اما، انجام دادن آن به طور دستی، کاری خسته کننده است و اگر ما بیست خصوصیت و یا حتی بیشتر در کلاس DTO داشته باشیم، در این صورت زمانبر نیز خواهد بود. خوشبختانه، یک ابزار عالی برای این کار وجود دارد که به ما در مپ کردن این فرآیند، خیلی کمک خواهد کرد. بله، این ابزار، AutoMapper میباشد.

کار با AutoMapper

AutoMapper یک کتابخانه ای است که به ما در مپ کردن آبجکتهای مختلف کمک میکند. برای نصب آن، ما باید این دستور را در پنجره Package Manager Console تایپ کنیم:

بعد از نصب، باید آن را در متد ConfigureServices درون کلاس Startup ثبت کنیم:

حال باید یک کلاس mapping profile ایجاد کنیم تا به AutoMapper بگوییم که چطور مپ کردن اکشنها را اجرا کند. پس اجازه دهید تا یک کلاس جدید به نام MappingProfile در پروژه اصلی ایجاد کنیم آن را به این صورت تغییر دهیم:

در آخر میتوانیم OwnerController را به این صورت تغییر دهیم:

ما میتوانیم درخواست قبلی را از Postman بفرستیم و همان نتیجه را دریافت کنیم (بدون account ها)، اما حالا با یک پیاده سازی بهتر. AutoMapper قابلیتهای خیلی خوبی دارد و میتوانید بیشتر در مورد آن تحقیق کنید.

درخواست GetOwnerById GET در NET Core.

در ادامه، اینترفیس IOwnerRepository را تغییر میدهیم:

سپس اینترفیس را در OwnerRepository.cs پیاده سازی میکنیم:

در آخر، OwnerController را تغییر میدهیم:

حالا میخواهیم برای بررسی نتایج، از Postman برای فرستادن درخواستهای معتبر و غیرمعتبر استفاده کنیم:

درخواست معتبر در Postman

درخواست نامعتبر:

درخواست نامعتبر در Postman

درخواست جزییات Owner

کارمان را با ایجاد logic برای برگرداندن آبجکت owner به همراه جزییات account آن ادامه میدهیم.

اول باید کلاس AccountDto را ایجاد کنیم:

سپس باید کلاس OwnerDto مان را تغییر دهیم که به ما کمک میکند تا owner را به همراه account های مرتبط به آن را برگردانیم. اگر تمایل داشته باشید میتوانید یک کلاس DTO دیگر به نام OwnerWithAccountsDto برای این کار ایجاد کنید، اما برای سادگی کار، ما میخواهیم همان کلاس DTO موجود را تغییر دهیم:

دقت کنید که اینجا ویژگی Accounts، تمام account های مربوط به owner تعیین شده را bind میکند.

در نتیجه، اجازه دهید تا اینترفیسمان را تغییر دهیم:

همچنین کلاس repository را تغییر میدهیم:

ما اینجا از متد Include برای گرفتن تمام account های مرتبط به owner کنونی استفاده میکنیم.

حالا باید یک قانون map جدید در کلاس MappingProfile اضافه کنیم:

در آخر، کنترلر را تغییر میدهیم:

نتیجه:

درخواست جزییات owner با postman

نتیجه گیری

درخواستهایی که از GET استفاده میکنند فقط داده ها را از دیتابیس دریافت میکنند و تمام اکشنهای داخل کلاس OwnerController با این نوع درخواست نوشته شده اند.

با خواندن این پست، شما موارد زیر را یاد گرفتید:

  • نحوه کار با یک کلاس controller
  • مسیریابی و نحوه استفاده از آن
  • نحوه handle کردن درخواستهای GET در یک web API
  • شیوه استفاده از DTO ها در زمان handle کردن درخواستها

از مطالعه این مقاله از شما تشکر میکنیم و امیدواریم که برای شما مفید واقع قرار گرفته باشد.

در مقاله بعدی، ما قصد داریم که این اصول یاد گرفته در اینجا را برای انجام درخواستهای POST, PUT و DELETE در اپلیکیشنمان اعمال کنیم.

نویسنده

امید عباسی
من امید عباسی هستم. سالهاست که در زمینه برنامه نویسی با تکنولوژی دات نت فعالیت میکنم و عاشق این هستم که تجربیات و دانش خودم را در این زمینه با دیگران به اشتراک بزارم. خیلی دوست دارم که نظر و انتقاد خودتون رو در مورد این نوشته برای من بنویسید تا بتونم در آینده، مطالب بهتر و ارزشمندتری را برای شما فراهم کنم. در صورت داشتن هرگونه سوال هم در قسمت دیدگاه ها میتونید با بنده در ارتباط باشید