در قسمت قبلی روش استفاده از IRequest و IRequestHandler را در MediatR که نقش پیاده سازی Command/Query را در CQRS بر عهده دارند، بررسی کردیم. کدهای این قسمت در این ریپازیتوری بهروزرسانی شده و قابل دسترسی است. با ما همراه شوید.
Command ما که نقش ایجاد یک مشتری را داشت ( CreateCustomerCommand )، هیچ Validation ای برای اعتبار سنجی مقادیر ورودی از سمت کاربر را ندارد و کاربر با هر مقادیری میتواند این Command را فراخوانی کند. در این قسمت با استفاده از کتابخانه Fluent Validation امکان اعتبار سنجی را به Commandهای خود اضافه میکنیم.
در ابتدا با استفاده از دستور زیر ، این کتابخانه را داخل پروژه خود نصب میکنیم:
بعد از افزودن این کتابخانه، باید آن را داخل DI Container خود Register کنیم:
کلاس جدیدی با نام CreateCustomerCommandValidator ایجاد میکنیم و از کلاس AbstractValidator مربوط به Fluent Validation ارث بری میکنیم تا منطق اعتبارسنجی برای CreateCustomerCommand را داخل آن تعریف نماییم :
همانطور که میبینید در اینجا خالی نبودن Firstname و Lastname ورودی از سمت کاربر را چک کردهایم. Fluent Validation دارای متدهای زیادی برای اعتبارسنجی است که لیست آنها را در اینجا میتوانید ببینید. همچنین درصورت نیاز میتوانید Validatorهای سفارشی خود را طبق نمونهها ایجاد کنید.
اگر برنامه را اجرا و CreateCustomerCommand را با مقادیر خالی فراخوانی کنیم، خواهید دید که بلافاصله با چنین خطایی مواجه خواهید شد که نشان میدهد Fluent Validation بدرستی وظیفه اعتبارسنجی ورودیها را انجام داده است:
* نکته : تمامی اعتبارسنجیهای سطحی ( Superficial Validation ) مانند خالی نبودن مقادیر، اعتبارسنجی تاریخها، اعتبارسنجی ایمیل و … باید قبل از Handle شدن Commandها صورت گیرد و در صورت ناموفق بودن اعتبارسنجی، نباید وارد متد Handle در Commandها شویم. ( Fail Fast Principle )
Events
برای حل این مشکل میتوانیم از Eventها استفاده کنیم. Eventها خبری را به Subscriber های خود میدهند. در فریمورک MediatR، ارسال و Handle کردن Eventها، با دو interface صورت میگیرد: INotification و INotificationHandler
بر خلاف Commandها که فقط یک Handler میتوانند داشته باشند، Event ها میتوانند چندین Handler داشته باشند. مزیت داشتن چند Subscriber برای Eventها این است که شما علاوه بر اینکه میتوانید Subscriber ای داشته باشید که وظیفه ارسال Email برای مشتری را بر عهده داشته باشد، Subscriber دیگری داشته باشید که اطلاعات مشتری جدید را Log کند.
ابتدا کلاس CustomerCreatedEvent را ایجاد و از INotification ارث بری میکنیم. این کلاس منتشر کننده یک اتفاق است که آن را Producer مینامند :
سپس دو Handler برای این Event مینویسیم. Handler اول وظیفه ارسال ایمیل را بر عهده خواهد داشت :
و Handler دوم، وظیفه Log کردن اطلاعات مشتری ثبت شده را بر عهده خواهد داشت:
در نهایت کافیست داخل CreateCustomerCommandHandler که در قسمت قبل آن را ایجاد کردیم، متد Handle را ویرایش و با استفاده از متد Publish موجود در اینترفیس IMediator، این Event را Raise کنیم :
برنامه را اجرا و روی دو NotificationHandler خود Breakpoint قرار دهید. اگر api/Customers را برای ایجاد یک مشتری جدید فراخوانی کنید، بعد از ثبت نام موفق مشتری، خواهید دید که هر دو Handler شما Raise میشوند و اطلاعات مشتری را که با LogHandler خود داخل Console لاگ کردیم، خواهیم دید:
* نکته : در این قسمت از آموزش برای Log کردن اطلاعات از یک Notification استفاده کردیم. اگر تعداد Commandهای ما در برنامه بیشتر شوند، به ازای هر Command مجبور به ایجاد یک Notification و NotificationHandler خواهیم بود که منطق کار آنها بسیار شبیه به یک دیگر است.
در مقاله بعدی با استفاده از Behaviors موجود در MediatR که AOP را پیاده سازی میکند، این موارد تکراری را از بین خواهیم برد.