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

آموزش مسیریابی (Routing) و انتخاب Action در ASP.NET WEB API

دوره های مرتبط با این مقاله

مسیریابی و انتخاب Action در ASP.NET WEB API

در این مقاله قصد داریم نشان دهیم چگونه Asp.net Web API یک درخواست HTTP را به یک Action مشخص در یک controller مسیردهی می کند و به جزئیات پردازش مسیریابی می پردازد. اگر شما یک پروژه Web API طراحی کنید و متوجه شوید برخی درخواست ها به مسیری که شما انتظار داشتید ختم نشد، خوشبختانه این مقاله می تواند به شما کمک کند.

مسیریابی 3 مرحله دارد:

  1. اتصال URI به یک قالب مسیر
  2. انتخاب کردن یک controller
  3. انتخاب کردن یک action

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

قالب های مسیر

یک قالب مسیر شبیه به مسیر URI است اما می تواند مقادیر مکان نگه دارنده (placeholder) داشته باشد که با {} نشان داده می شود.

"api/{controller}/public/{category}/{id}"

وقتی شما یک مسیر می سازید، می توانید مقدار پیش فرض را برای placeholder ها all کنید.

{ category = newdefaults: "all"} 

شما همچنین می توانید محدودیت هایی درباره اینکه چطور یک قطعه URI می تواند با یک placeholder متصل شود ایجاد کنید:

                            
                            { id = newconstraints:@"\d+" } / Only matches if "id" is one or more digits.

فریم ورک قطعات را در مسیر URI به قالب هدایت می کند. کاملا باید با هم منطبق باشند. یک placeholder هر مقداری را منطبق می کند مگر آنکه محدودیت های مشخصی برای آن اعمال کنیم. فریم ورک دیگر قسمت های URI مثل نام هاست یا پارامتر های متنی(query) را نمی تواند منطبق کند. فریم ورک اولین مسیر در جدول مسیریابی که بر URI منطبق شده را انتخاب می کند.

دو placeholder اصلی داریم، یکی {controller} و دیگری {action}:

  • {controller} نام controller را آماده می کند.
  • {action} نام action را آماده می سازد. به طور معمول {action} در Web API حذف می شود.

پیش فرض ها

اگر شما به صورت پیش فرض عمل کنید، مسیر URI را به صورت زیر مطابقت می دهد. برای مثال:

routes.MapHttpRoute(
   name: "DefaultApi",
   routeTemplate: "api/{controller}/{category}",
   defaults: new { category = "all" }

URI مربوط به http://localhost/api/products این مسیر را مطابقت می دهد. قطعه {category}به مقدار پیش فرض all اختصاص داده شده است.

واژه نامه (Dictionary) مسیر

اگر فریم ورک یک انطباق برای مسیر پیدا کند یک dictionary که شامل مقادیر هر placeholder باشد می سازد. کلید ها نام های placeholder ها بدون {} می باشند. مقادیر از مسیر URI یا به طور پیش فرض دریافت می شود. Dictionary در IHttpRouteData ذخیره شده است.

در زمان تطابق مسیر، placeholder های ویژه {controller} و {action} مثل دیگر placeholder ها رفتار می کند. این ها به سادگی با مقادیر دیگر در dictionary ذخیره می شود.

پیش فرض می تواند مقدار ویژه RouteParameter.Optional را داشته باشد. اگر به یک placeholder این مقدار اختصاص داده شود، آنگاه مقدار به دیکشنری مسیر اضافه نمی شود. برای مثال:

routes.MapHttpRoute(
   name: "DefaultApi",
   routeTemplate: "api/{controller}/{category}/{id}",
   defaults: new { category = "all", id = RouteParameter.Optional }
);

برای مسیر api/products، دیکشنری مسیر شامل مقادیر زیر خواهد بود:

  • controller: "products"
  • category: "all"

برای api/products/toys/123 نیز دیکشنری مسیر به صورت زیر خواهد بود:

  • controller: "products"
  • category: "toys"
  • id: "123"

به صورت پیش فرض می توان یک مقدار که در هیچ جای قالب مسیر نمی باشد را اضافه کنید. اگر مسیر تطابق داشته باشد آن مقدار در دیکشنری ذخیره می شود. برای مثال:

                          
routes.MapHttpRoute(
   name: "Root",
   routeTemplate: "api/root/{id}",
   defaults: new { controller = "customers", id = RouteParameter.Optional }
);

اگر مسیر api/root/8 باشد، دیکشنری شامل دو مقدار خواهد شد:

  • controller: "customers"
  • id: "8"

انتخاب کردن یک Controller

متد IHttpControllerSelector.SelectController کنترولر را انتخاب می کند. این متد یک HttpRequestMessage فوری را گرفته و یک HttpControllerDescriptor بر می گرداند. پیاده سازی پیش فرض با کلاس DefaultHttpControllerSelector صورت می گیرد. این کلاس از یک الگوریتم سر راست استفاده می کند:

  1. جستجو در دیکشنری مسیر برای کلید Controller
  2. یک مقدار برای کلید می گیرد و برای نام کنترولر، رشته Controller را به انتهای آن اضافه می کند.
  3. جستجوی کنترولر Web API با این نام

برای مثال، اگر دیکشنری مسیر شامل جفت کلید-مقدار (key-value pair) Controller=products باشد آنگاه نوع کنترولر ProductsController می شود. اگر تطابقی نباشد و یا چند نوع تطابقی وجود داشته باشد، فریم ورک به کاربر مقدار خطا بر می گرداند.

برای مرحله 3، DefaultHttpControllerSelector از رابط IHttpControllerTypeResolver برای دریافت لیست کنترولر های Web API استفاده می کند. پیاده سازی پیش فرض IHttpControllerTypeResolver شامل تمامی کلاس هایی می شود که الف) IHttpController را پیاده سازی کرده اند ب)به نامی که به کنترولر ختم می شود .

انتخاب کردن Action

بعد از انتخاب کردن کنترولر، فریم ورک با فراخوانی متد IHttpActionSelector.SelectAction، action را انتخاب می کند. این متد یک HttpControllerContext می گیرد و یک HttpActionDescriptor بر می گرداند.

به صورت پیش فرض پیاده سازی با کلاس ApiControllerActionSelector انجام می گیرد. برای انتخاب یک action مراحل زیر انجام می گیرد:

  • متد HTTP مربوط به درخواست
  • Placeholder اکشن در قالب مسیر در صورتی که وجود داشته باشد.
  • پارامترهای اکشن در کنترولر

قبل از بررسی الگوریتم انتخاب کردن، ما باید بعضی موارد درباره اکشن های کنترولر را متوجه شویم:

کدام متد های درون کنترولر ،action ها در نظر گرفته است؟ وقتی یک اکشن انتخاب می شود، فریم ورک فقط متدهای عمومی در کنترولر را در نظر می گیرد. البته باید گفت متد های خاص (constructor ها، event ها، overload های عملگر و غیره) و متد هایی که از کلاس ApiController به ارث رسیده اند شامل این نمی شود.

متد های HTTP . فریم ورک تنها اکشن هایی را انتخاب می کند که با متد های درخواست HTTP تطابق داشته باشد.

  1. شما می توانید متد HTTP را با یک اتربیوت مثل HttpPost، HttpPatch، HttpOptions، HttpHead، HttpGet، HttpDelete، AcceptVerbs و یا HttpPut مشخص سازید.
  2. در غیر این صورت، اگر نام متد کنترولر با GET، POST، PUT، DELETE، HEAD، Options و Patch شروع شود طبق قرارداد، اکشن از متد HTTP پشتیبانی می کند.
  3. اگر مقدار های بالا نباشد، از POST پشتیبانی می کند.

اتصالات(Bindings) پارامتر ها. Bind کردن پارامتر یعنی چگونه Web API یک مقدار برای پارامتر می سازد. در زیر بعضی قوانین پیش فرض برای bind کردن پارامتر ها را معرفی می کنیم:

  • نوع ساده گرفته شده از URI
  • نوع پیچیده گرفته شده از بدنه درخواست

انواع ساده شامل همه ی انواع اولیه .NET Framework به علاوه ی DateTime, Decimal, Guid, String و TimeSpan می شود. برای هر اکشن، حداکثر یک پارامتر می تواند بدنه درخواست را بخواند.

با توجه به دیدی که در بالا به دست آوردید در زیر به بررسی الگوریتم انتخاب action می پردازیم:

  1. یک لیست از همه ی اکشن های درون کنترولر که با متد درخواست HTTP تطابق دارد می سازد.
  2. اگر دیکشنری مسیر یک ورودی اکشن داشته باشد، اکشن هایی را که نام آنها با این مقدار تطابق ندارد حذف می کند.
  3. تطبیق دادن پارامتر های اکشن به URI به صورت زیر انجام می گیرد:
    • برای هر اکشن، یک لیست از پارامتر هایی که ساده هستند در زمانی که اتصالات URI پارامتر می گیرد و پارامتر های اختیاری نیستند می سازد.
    • در این لیست، سعی کنید یک تطابق برای هر نام پارامتر چه در دیکشنری مسیر یا در URI را پیدا کنید. اتصالات حساس به حروف بزرگ نیست و به درخواست پارامتر بستگی ندارد.
    • یک اکشن که هر پارامتر در لیست یک تطابق با URI داشته باشد.
    • اگر بیش از یک اکشن با این شاخص ها برخورد کند یکی را با بیشترین تطابق بر می گرداند.
  4. با اتربیوت [NonAction] از اکشن ها چشم پوشی می کند.

مرحله 3 احتمالا بسیار گیج کننده می باشد. ایده پایه این است که یک پارامتر می تواند مقدار خود را چه از URI، چه از بدنه درخواست و یا bind کردن شخصی دریافت کند. برای پارامتر هایی که از URI دریافت می شود، ما می خواهیم مطمئن شویم که URI قطعا یک مقدار برای آن پارامتر را شامل می شود حال می خواهد این مقدار در مسیر و یا در query string باشد.

برای مثال اکشن زیر را در نظر بگیرید:

public void Get(int id)

پارامتر id به URI بسط داده می شود. به همین دلیل این اکشن می تواند فقط یک URI که شامل یک مقدار برای id می باشد چه در دیکشنری مسیر باشد و یا در query string را شامل شود. البته پارامتر های اختیاری به دلیل ماهیت انتخابی مستثنی می باشند.

مقادیر پیچیده به دلایل دیگر مستثنی می باشند. یک مقدار پیچیده تنها می تواند به URI از طریق یک اتصال شخصی متصل شود. برای فهمیدن آن، لازم است bind کردن فراخوانی شود. هدف از الگوریتم انتخاب کردن این است که قبل از فراخوانی کردن هر گونه bind کردن، از توضیحات استاتیک، یک اکشن انتخاب کند. با این حال، مقادیر پیچیده از الگوریتم تطابق مستثنی می شوند.

بعد از آنکه اکشن انتخاب شد، همه ی پارامتر های bind شده فراخوانی می شود.

خلاصه:

Action حتما باید با متد HTTP درخواست تطابق داشته باشد.

نام action در صورت وجود، حتما باید با ورودی action تطابق داشته باشد.

برای تمام پارامتر های داخل اکشن، اگر پارامتر از URI گرفته شده باشد آنگاه نام پارامتر هم باید در دیکشنری مسیر و هم در query string موجود باشد (پارامترهای اختیاری و پارامتر هایی با مقادیر پیچیده از این بحث مستثنی هستند.)

مثال های اضافه:

مسیر ها:

                          
routes.MapHttpRoute(
   name: "ApiRoot",
   routeTemplate: "api/root/{id}",
   defaults: new { controller = "products", id = RouteParameter.Optional }
);
routes.MapHttpRoute(
   name: "DefaultApi",
   routeTemplate: "api/{controller}/{id}",
   defaults: new { id = RouteParameter.Optional }
);

کنترولر:

                           
public class ProductsController : ApiController
{
   public IEnumerableGetAll() { }
   public Product GetById(int id, double version = 1.0) { }
   [HttpGet]
   public void FindProductsByName(string name) { }
   public void Post(Product value) { }
   public void Put(int id, Product value) { }
}

درخواست HTTP:

                            
GET http://localhost:34701/api/products/1?version=1.5&details=1

تطبیق مسیر:

URI های منطبق بر مسیر به نام DefaultApi هستند. دیکشنری مسیر شامل ورودی های زیر می باشد:

  • controller: "products"
  • id: "1"

دیکشنری مسیر شامل پارامتر های query string ، version و details نمی شود اما همچنان در طی انتخاب کردن اکشن در نظر گرفته می شود.

انتخاب کردن کنترولر

با توجه به ورودی کنترولر در دیکشنری مسیر، کنترولر از نوع ProductsController می باشد.

انتخاب کردن اکشن

درخواست HTTP از نوع درخواست GET می باشد. نمونه اکشن های کنترولر که شامل GET می شوندGetAll, GetById و FindProductsByName می باشد. دیکشنری مسیر شامل ورودی برای اکشن نمی شود پس ما نیازی به تطبیق دادن نام اکشن نداریم.

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

پارامتر های تطبیق
Action
none
GetAll
id
GetById
name
FindProductsByName

توجه داشته باشید که پارامتر verison مربوط به GetByID در نظر گرفته نشده است زیرا یک پارامتر اختیاری می باشد.

متد GetALL بدیهی تطبیق داده می شود. متد GetById هم تطبیق داده می شود چون دیکشنری مسیر شامل id می شود. اما متد FindProductsByName تطبیق داده نمی شود.

توجه داشته باشید حتی اگر version در الگوریتم انتخاب کردن استفاده نشود مقدار پارامتر از query string دریافت می شود.

نکته های اضافی

Web API نکات اضافی برای بعضی قسمت های پردازش مسیریابی در نظر می گیرد.

توضیح
رابط
انتخاب کنترولر
IHttpControllerSelector
لیست انواع کنترولر ها را دریافت می کند. DefaultHttpControllerSelector نوع کنترولر را از این لیست انتخاب می کند.
IHttpControllerTypeResolver
لیست اسمبلی های پروژه را دریافت می کند. رابط IHttpControllerTypeResolver از این لیست برای پیدا کردن انواع کنترولر استفاده می کند.
IAssembliesResolver
ساخت کنترولر های جدید
IHttpControllerActivator
ساخت کنترولر های جدید
IHttpControllerActivator
ساخت اکشن
IHttpActionSelector
فراخوانی اکشن
IHttpActionInvoker

برای پیاده سازی هر کدام از این رابط ها برای خودتان از مجموعه services در HttpConfiguration استفاده کنید.

var config = GlobalConfiguration.Configuration;
config.Services.Replace(typeof(IHttpControllerSelector), new MyControllerSelector(config));

  • 1396
  •    1018
  • تاریخ ارسال :   1395/02/09

دانلود PDF دانلود فیلم آموزشی دانشجویان گرامی اگر این مطلب برای شما مفید بود لطفا ما را در GooglePlus محبوب کنید
رمز عبور: tahlildadeh.com یا www.tahlildadeh.com
آموزش مسیریابی (Routing) و انتخاب Action در ASP.NET WEB API
ارسال دیدگاه نظرات کاربران
شماره موبایل دیدگاه
عنوان پست الکترونیک

ارسال

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

تمامی حقوق این سایت متعلق به آموزشگاه تحلیل داده می باشد .