معرفی سرویس IActionDescriptorCollectionProvider در ASP.NET Core
فرض کنید میخواهیم لیست تمام کنترلرهای یک برنامهی ASP.NET Core را با ساختار ذیل تهیه کنیم که شامل نام کنترلر، نام اکشن متد و نام ناحیهی متناظر با آن (در صورت تنظیم) میباشد:
public class MvcActionViewModel { public string ControllerName { get; set; } public string ActionName { get; set; } public string AreaName { get; set; } }
public interface IMvcActionsDiscoveryService { ICollection<MvcActionViewModel> MvcActions { get; } } public class MvcActionsDiscoveryService : IMvcActionsDiscoveryService { public MvcActionsDiscoveryService(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider) { var actionDescriptors = actionDescriptorCollectionProvider.ActionDescriptors.Items; foreach (var actionDescriptor in actionDescriptors) { var descriptor = actionDescriptor as ControllerActionDescriptor; if (descriptor == null) { continue; } var controllerTypeInfo = descriptor.ControllerTypeInfo; var actionMethodInfo = descriptor.MethodInfo; MvcActions.Add(new MvcActionViewModel { ControllerName = descriptor.ControllerName, ActionName = descriptor.ActionName, AreaName = controllerTypeInfo.GetCustomAttribute<AreaAttribute>()?.RouteValue }); } } public ICollection<MvcActionViewModel> MvcActions { get; } = new HashSet<MvcActionViewModel>(); }
- در کلاس آغازین برنامه نیازی به ثبت سرویس IActionDescriptorCollectionProvider نیست و اینکار پیشتر توسط خود ASP.NET Core انجام شدهاست.
- این provider حاوی لیست اطلاعات تمام اکشن متدهای ثبت شدهی توسط ASP.NET Core است. در اینجا تنها کافی است حلقهای را بر روی لیست آیتمهای آن تشکیل داده و سپس مقادیر ControllerName و یا ActionName را بدست بیاوریم.
- اگر نیاز به اطلاعات بیشتری از کنترلر و اکشن متد جاری در حال بررسی توسط حلقهی تهیه شده بود، میتوان از ControllerTypeInfo و MethodInfo آن استفاده کرد. این TypeInfoها با استفاده از Reflection، امکان دسترسی به اطلاعاتی مانند ویژگیهای اعمال شدهی به کنترلر یا اکشنی خاص را میسر میکنند. برای مثال در اینجا توسط اطلاعات نوع یک کنترلر در حال بررسی توانستهایم متد GetCustomAttribute را فراخوانی کرده و سپس بررسی کنیم که آیا دارای ویژگی جدید Area هست یا خیر؟ و اگر بله، مقدار RouteValue آن را که در حقیقت مقدار یا نام Area آن کنترلر است، بازگشت میدهیم.
نحوهی استفاده از سرویس IMvcActionsDiscoveryService تهیه شده
اگر دقت کرده باشید اطلاعات لیست MvcActions، در سازندهی این کلاس مقدار دهی شدهاند. علت اینجا است که اگر این کلاس را به صورت singleton ثبت کنیم، تنها یکبار در طول عمر برنامه و در همان آغاز کار، این لیست پر شده و سپس کش خواهد شد. بنابراین دسترسیهای بعدی به MvcActions، شامل فراخوانی سازندهی این کلاس نخواهند بود:
public static class MvcActionsDiscoveryServiceExtensions { public static IServiceCollection AddMvcActionsDiscoveryService(this IServiceCollection services) { services.AddSingleton<IMvcActionsDiscoveryService, MvcActionsDiscoveryService>(); return services; } }
public void ConfigureServices(IServiceCollection services) { services.AddMvcActionsDiscoveryService(); }