اندازهی قلم متن
تخمین مدت زمان مطالعهی مطلب:
سه دقیقه
معادل مطلب جاری را برای ASP.NET MVC 5.x در مطلب «یکدست کردن "ی" و "ک" در ASP.NET MVC با پیادهسازی یک Model Binder» میتوانید مطالعه کنید. در اینجا قصد داریم یک چنین قابلیتی را با توجه به تغییرات ASP.NET Core نیز تهیه کنیم.
تهیه یک binder provider پردازش رشتهها
کار model binding، تطابق اطلاعات رسیدهی از درخواست جاری، با پارامترهای اکشن متد یک کنترلر است. هر مقدار رسیده، به یک binder متناسب ارسال میشود تا پردازش آن مدیریت گردد. به صورت پیش فرض در ASP.NET Core، تعدد 14 عدد binder providers که اینترفیس IModelBinderProvider را پیاده سازی میکنند، در این بین جهت یافتن یک binder مناسب، بررسی خواهند شد. برای مثال کار یک binder، پردازش نوعهای پیچیدهاست (complex types) و دیگری نوعهای ساده (simple types) مانند int و string را پردازش میکند.
بنابراین اولین قدم تهیهی یک model binder سفارشی، تهیهی یک تامین کنندهی سفارشی است که با پیاده سازی اینترفیس IModelBinderProvider ارائه میشود. در اینجا چون میخواهیم نوعهای سادهی رشتهای را پردازش کنیم، اگر نوع جاری رسیده، یک نوع پیچیده بود (context.Metadata.IsComplexType) نال را بازگشت میدهیم تا model binder بعدی ثبت شدهی در لیست تامین کنندههای مرتبط، مورد آزمایش قرار گیرد.
سپس اگر نوع مدل جاری رشتهای بود، وهلهای از CustomStringModelBinder را بازگشت میدهیم (کلاسی است که آنرا در ادامه تهیه خواهیم کرد). درغیراینصورت همان SimpleTypeModelBinder توکار این فریمورک را بازگشت خواهیم داد.
تهیهی یک model binder سفارشی پردازش رشتهها
تا اینجا تامین کنندهای را که مشخص میکند چه model binder ایی قرار است بازگشت داده شود، تهیه کردیم. مرحلهی بعد، پیاده سازی CustomStringModelBinder با پیاده سازی اینترفیس IModelBinder است:
عملیات اصلی پردازشی یک Model binder در متد BindModelAsync آن صورت میگیرد. ابتدا مقداری را که در حال پردازش است دریافت میکنیم (توسط ValueProvider.GetValue). سپس ی و ک آنرا یکدست کرده و به عنوان نتیجهی عملیات تنظیم خواهیم کرد. این کار سبب خواهد شد تا هر مقداری را که کاربر وارد و ارسال کند، پیش از رسیدن به اکشن متد و پارامترهای آن، مورد پردازش و یکدست سازی قرار گیرد.
در اینجا تمام مواردی را که نمیخواهیم پردازش کنیم، به همان SimpleTypeModelBinder که از طریق سازندهی کلاس دریافت میکنیم، واگذار خواهیم کرد.
معرفی به binder provider سفارشی به سیستم
مرحلهی آخر این عملیات، معرفی binder تهیه شده به سیستم است که روش آن را در ذیل مشاهده میکنید:
در اینجا ابتدا به دنبال SimpleTypeModelBinderProvider توکار گشته و سپس آنرا با CustomStringModelBinderProvider خود جایگزین میکنیم. اگر این model binder سفارشی ما در ایندکس نامناسبی در لیست options.ModelBinderProviders قرارگیرد، هیچگاه فراخوانی نخواهد شد؛ برای مثال اگر پس از SimpleTypeModelBinderProvider قرارگیرد.
در آخر تنها کافی است در کلاس آغازین برنامه، متد الحاقی UseCustomStringModelBinder فوق را به تنظیمات Mvc اضافه کنیم:
تهیه یک binder provider پردازش رشتهها
کار model binding، تطابق اطلاعات رسیدهی از درخواست جاری، با پارامترهای اکشن متد یک کنترلر است. هر مقدار رسیده، به یک binder متناسب ارسال میشود تا پردازش آن مدیریت گردد. به صورت پیش فرض در ASP.NET Core، تعدد 14 عدد binder providers که اینترفیس IModelBinderProvider را پیاده سازی میکنند، در این بین جهت یافتن یک binder مناسب، بررسی خواهند شد. برای مثال کار یک binder، پردازش نوعهای پیچیدهاست (complex types) و دیگری نوعهای ساده (simple types) مانند int و string را پردازش میکند.
public class CustomStringModelBinderProvider : IModelBinderProvider { public IModelBinder GetBinder(ModelBinderProviderContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (context.Metadata.IsComplexType) { return null; } var fallbackBinder = new SimpleTypeModelBinder(context.Metadata.ModelType); if (context.Metadata.ModelType == typeof(string)) { return new CustomStringModelBinder(fallbackBinder); } return fallbackBinder; } }
سپس اگر نوع مدل جاری رشتهای بود، وهلهای از CustomStringModelBinder را بازگشت میدهیم (کلاسی است که آنرا در ادامه تهیه خواهیم کرد). درغیراینصورت همان SimpleTypeModelBinder توکار این فریمورک را بازگشت خواهیم داد.
تهیهی یک model binder سفارشی پردازش رشتهها
تا اینجا تامین کنندهای را که مشخص میکند چه model binder ایی قرار است بازگشت داده شود، تهیه کردیم. مرحلهی بعد، پیاده سازی CustomStringModelBinder با پیاده سازی اینترفیس IModelBinder است:
public class CustomStringModelBinder : IModelBinder { private readonly IModelBinder _fallbackBinder; public CustomStringModelBinder(IModelBinder fallbackBinder) { if (fallbackBinder == null) { throw new ArgumentNullException(nameof(fallbackBinder)); } _fallbackBinder = fallbackBinder; } public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); } var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (valueProviderResult != ValueProviderResult.None) { bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); var valueAsString = valueProviderResult.FirstValue; if (string.IsNullOrWhiteSpace(valueAsString)) { return _fallbackBinder.BindModelAsync(bindingContext); } var model = valueAsString.Replace((char)1610, (char)1740).Replace((char)1603, (char)1705); bindingContext.Result = ModelBindingResult.Success(model); return Task.CompletedTask; } return _fallbackBinder.BindModelAsync(bindingContext); } }
در اینجا تمام مواردی را که نمیخواهیم پردازش کنیم، به همان SimpleTypeModelBinder که از طریق سازندهی کلاس دریافت میکنیم، واگذار خواهیم کرد.
معرفی به binder provider سفارشی به سیستم
مرحلهی آخر این عملیات، معرفی binder تهیه شده به سیستم است که روش آن را در ذیل مشاهده میکنید:
public static class CustomStringModelBinderExtensions { public static MvcOptions UseCustomStringModelBinder(this MvcOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } var simpleTypeModelBinder = options.ModelBinderProviders.FirstOrDefault(x => x.GetType() == typeof(SimpleTypeModelBinderProvider)); if (simpleTypeModelBinder == null) { return options; } var simpleTypeModelBinderIndex = options.ModelBinderProviders.IndexOf(simpleTypeModelBinder); options.ModelBinderProviders.Insert(simpleTypeModelBinderIndex, new CustomStringModelBinderProvider()); return options; } }
در آخر تنها کافی است در کلاس آغازین برنامه، متد الحاقی UseCustomStringModelBinder فوق را به تنظیمات Mvc اضافه کنیم:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { options.UseCustomStringModelBinder(); });