استفاده از rabbitMQ در پروژه webapi دوره

علی شاکری
6 مهر ۱۴۰۲

سلام استاد اشرافی عزیز

برای استفاده از RabbitMq در معماری پروژه web api دوره مشکل برام پیش اومده

الان وقتی از adddomainevent که در basedomainevent هست استفاده میکنم به شکل زیر id خالی پر میشه

public static User Register(string name, string family, string nationalCode, string password, string mobile,DateTime birthDate,Gender gender, IUserDomainService userDomainService)

{

   var user= new User(name, family, nationalCode, password, mobile, null, null,

       birthDate, gender, null, null, null, null, null,

       null, null,null, userDomainService, true);



  AddDomainEventStatic(new UserRegistered

   {

       Id = user.Id,

       Name = user.Name,

       Family = user.Family,

       PhoneNumber = user.Mobile,

       Title = "",

       Message = ""

   });

   return user;

}

id در لایه application پر میشه و من اینجا نیازش دارم

چکار کنم؟

ای کاش توی همین پروژه web api روش استفاده از rabbitMq با این ساختار آموزش میدادید یه مقدار گیج شدم

330

9 پاسخ
  • محمد اشرافی6 مهر ۱۴۰۲

    سلام وقت بخیر ، توی پروژه Api ما از GUID استفاده نکردیم و id هامون وابسته به دیتابیسه ، پس طبیعتا تا وقتی که saveChagne فرخوانی نشه id پر نمیشه

    و اگر توی پیام نیاز به id باشه حتما باید بعد از SaveChanges اون Event ساخته بشه

  • محمد اشرافی6 مهر ۱۴۰۲

    کار دقیقا همون هیچ فرقی نکرده و ربطی به RabbitMq نداره مشکلی که الان هست id کاربره و تنها راه اش هم اینه بعد SaveChanges فراخوانی بشه یا اینکه از Hi/LO استفاده کنید بعد context.Add رو صدا بزنید بعد  Event رو به AggregateRoot اضافه کنید  

  • علی شاکری7 مهر ۱۴۰۲

    سلام استاد

    الان من اومدم اینکار رو کردم درسته؟

    public async Task<OperationResult<string>> Handle(ForgotPasswordCommand request, CancellationToken cancellationToken)
    {
        var user = await _userRepository.GetTracking(request.UserId);
        if (user == null)
            return OperationResult<string>.NotFound();
        
        if (user.IsActive == false)
            return OperationResult<string>.Error("حساب کاربری شما غیرفعال شده است");
    
        //var newPassword = CodeGenerator.GeneratePassword();
        const string newPassword = "12345";
        user.ChangePassword(Sha256Hasher.Hash(newPassword));
        await _userRepository.Save();
        #region Publish Send Sms or Email
    
        _eventBus.Publish(new UserForgotPasswordIntegrationEvent()
        {
            Id = user.Id,
            Mobile = user.Mobile,
            Password = newPassword,
            Message = $"آموز گرامی {user.Name} {user.Family} کلمه عبور شما به {newPassword} تغییر پیدا کرد.",
        }, "", Exchanges.UserExchange, ExchangeType.Fanout);
    
        #endregion
        return OperationResult<string>.Success(user.Mobile,$"کلمه عبور شما به {newPassword} تغییر پیدا کرد");
    }

    و بعد اومدم توی razorpage داخل فولدر infrastructure ایونت هندلر هامو گذاشتم و کانسوم کردم مثل زیر:

    public class UserForgotPasswordEventHandler : BackgroundService
    {
        private readonly IEventBus _eventBus;
        private string _queueName = "userForgotPassword";
        private readonly ILogger<UserForgotPasswordEventHandler> _logger;
        private readonly IServiceScopeFactory _serviceFactory;
        public UserForgotPasswordEventHandler(IEventBus eventBus, ILogger<UserForgotPasswordEventHandler> logger, IServiceScopeFactory serviceFactory)
        {
            _eventBus = eventBus;
            _logger = logger;
            _serviceFactory = serviceFactory;
        }
    
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            var connection = _eventBus.Connection;
            var serviceScope = _serviceFactory.CreateScope();
    
            var notificationFacade = serviceScope.ServiceProvider.GetRequiredService<INotificationFacade>();
            var smsService = serviceScope.ServiceProvider.GetRequiredService<ISmsService>();
    
            var model = connection.CreateModel();
            model.ExchangeDeclare(Exchanges.UserExchange, ExchangeType.Fanout, true, false, null);
            model.QueueDeclare(_queueName, true, false, false, null);
            model.QueueBind(_queueName, Exchanges.UserExchange, "", null);
    
            var consumer = new EventingBasicConsumer(model);
            consumer.Received += async (sender, args) =>
            {
                try
                {
                    var resultJson = Encoding.UTF8.GetString(args.Body.ToArray());
                    var result = JsonConvert.DeserializeObject<UserForgotPasswordIntegrationEvent>(resultJson);
    
                    //send notification
                    await notificationFacade.Create(new CreateNotificationCommand(result.Id, "تغییر کلمه عبور", result.Message));
                    //send sms
                    smsService.SendUserPasswordSms(result.Mobile, result.Password);
                    
                    model.BasicAck(args.DeliveryTag, false);
                }
                catch (Exception e)
                {
                    _logger.LogError(e, e.Message);
                }
            };
            model.BasicConsume(consumer, _queueName, false);
        }
    }

    که اینجا هم نوتیفی و هم sms میدم بهش

    درسته؟

  • محمد اشرافی8 مهر ۱۴۰۲

    سلام بله پیاده سازی مشکلی نداره ولی میتونید handler هاتونو ببرید توی Infrustructure

  • علی شاکری8 مهر ۱۴۰۲

    خب اونجوری به facade دسترسی نداریم استاد

  • علی شاکری8 مهر ۱۴۰۲

    راستی استاد برای ارسال ایمیل و sms توی اون handler که داریم نوتیفیکیشن میفرستیم همونجا انجام میدیم؟

  • علی شاکری8 مهر ۱۴۰۲

    ینی منظورم اینجاس

    try
                {
                    var resultJson = Encoding.UTF8.GetString(args.Body.ToArray());
                    var result = JsonConvert.DeserializeObject<UserForgotPasswordIntegrationEvent>(resultJson);
    
                    //send notification
                    await notificationFacade.Create(new CreateNotificationCommand(result.Id, "تغییر کلمه عبور", result.Message));
                    
                    
                                    //اینجا
    
    
                    //send sms
                    smsService.SendUserPasswordSms(result.Mobile, result.Password);
                    
                    //تا اینجا
    
    
                    
    
    
    
    
                    model.BasicAck(args.DeliveryTag, false);
                }
                catch (Exception e)
                {
                    _logger.LogError(e, e.Message);
                }
  • محمد اشرافی8 مهر ۱۴۰۲

    نیازی به Facade ندارین ، دسترسی به Command ها و Query ها دارید کافیه ( اینون برای این میگم توی Infrustrucure باشه که اگر جزء منطق وبسایت هست حتما اجزا بشه ولی اگر جزء منطق سیستم نیست توی همون Endpoint باشه مشکلی نداره )

    و ایکه این یک پیشنهاد بود اگر فکر میکنید برای سیستم شما لازم نیست پس اجباری وجود ندارد

     

    آره توی همین Event Handler صداش بزنید مشکلی نداره مگر اینکه خودتون بخواین Handler هاشو جدا کنید که توی پروژه شما هم احتیاجی نداره

  • علی شاکری9 مهر ۱۴۰۲

    ممنون استاد

    خیلی لطف کردید