"> انتشار پیغام با RabbitMQ در ASP.NET Core | آموزش .NET Core | ام اس پی سافت

انتشار پیغام با RabbitMQ در ASP.NET Core

انتشار پیغام با RabbitMQ

در این مقاله، میخواهیم در مورد نحوه‏ ی انتشار پیغام با RabbitMQ در ASP.NET Core را به شما نشان دهیم. تا پایان این مقاله همراه ما باشید.

RabbitMQ چیست؟

RabbitMQ یک نرم افزار صف بندی پیام به نام واسطه‌ی پیام یا مدیریت صف است.

بطور ساده، نرم افزاری است که در آن صف‌ها می‌توانند تعریف شوند، برنامه‌ها ممکن است به صف متصل شده و یک پیام به آن انتقال دهند.

انتشار پیغام با RabbitMQ

راه اندازی سریع سرویس RabbitMQ

راه اندازی سریع سرویس RabbitMQ

تنظیمات RabbitMQ

افزودن پیکربندی RabbitMQ در appsettings.json

{  
  "Logging": {  
    "LogLevel": {  
      "Default": "Warning"  
    }  
  },  
  "AllowedHosts": "*",  
  "rabbit": {  
    "UserName": "guest",  
    "Password": "guest",  
    "HostName": "localhost",  
    "VHost": "/",  
    "Port": 5672  
  }  
}  

ایجاد کلاسی که بخش rabbit در appsettings.json را ترسیم می کند.

public class RabbitOptions  
{  
    public string UserName { get; set; }  
  
    public string Password { get; set; }  
  
    public string HostName { get; set; }  
  
    public int Port { get; set; } = 5672;  
  
    public string VHost { get; set; } = "/";  
}

استفاده ی مجدد از کانال های اتصال RabbitMQ

چرا باید مجددا از کانالها استفاده کنیم؟

طبق سند رسمی .NET/C# Client API Guide، می توانیم استفاده ی مجدد از کانال ها را مد نظر قرار دهیم، چراکه عمر آن ها طولانی بوده اما از آنجایی که بسیاری از خطاهای قابل بازیابی پروتکل منجر به بسته شدن کانال خواهند شد، باز و بسته کردن کانال های جدید به ازای هر عملیات معمولا غیر الزامی است.

در اینجا، از object pool برای انجام این کار استفاده خواهیم کرد! Microsoft پکیجی به نام Microsoft.Extensions.ObjectPool ارائه می دهد که می تواند به ما در ساده سازی بخشی از کار کمک کند.

پیش از بکارگیری object pool ،در ابتدا باید سیاست کانال را اعلان کنیم.

در اینجا، کلاسی به نام RabbitModelPooledObjectPolicy ایجاد می‏کنیم که IPooledObjectPolicy<IModel> را پیاده سازی می کند.

using Microsoft.Extensions.ObjectPool;  
using Microsoft.Extensions.Options;  
using RabbitMQ.Client;  
  
public class RabbitModelPooledObjectPolicy : IPooledObjectPolicy<IModel>  
{  
    private readonly RabbitOptions _options;  
  
    private readonly IConnection _connection;  
  
    public RabbitModelPooledObjectPolicy(IOptions<RabbitOptions> optionsAccs)  
    {  
        _options = optionsAccs.Value;  
        _connection = GetConnection();  
    }  
  
    private IConnection GetConnection()  
    {  
        var factory = new ConnectionFactory()  
        {  
            HostName = _options.HostName,  
            UserName = _options.UserName,  
            Password = _options.Password,  
            Port = _options.Port,  
            VirtualHost = _options.VHost,  
        };  
  
        return factory.CreateConnection();  
    }  
  
    public IModel Create()  
    {  
        return _connection.CreateModel();  
    }  
  
    public bool Return(IModel obj)  
    {  
        if (obj.IsOpen)  
        {  
            return true;  
        }  
        else  
        {  
            obj?.Dispose();  
            return false;  
        }  
    }  
}  

دو متد مهم در آن وجود دارد، یکی Create، و دیگری Return می باشد.

متد Create نحوه ی ایجاد شیء کانال را به pool می گوید.

متد Return به pool می گوید که اگر شیء کانال هنوز در وضعیتی است که می تواند مورد استفاده قرار بگیرد، باید آن را به pool برگردانیم؛ در غیر اینصورت، نباید دفعه ی بعد از آن استفاده کنیم.

RabbitMQ Manager

یک رابط مدیریت جهت مدیریت متد Publish ایجاد می کنیم.

public interface IRabbitManager  
{  
    void Publish<T>(T message, string exchangeName, string exchangeType, string routeKey)   
        where T : class;  
}  

کد زیر، یک کلاس پیاده سازی کننده ی آن را نشان می دهد.

public class RabbitManager : IRabbitManager  
{  
    private readonly DefaultObjectPool<IModel> _objectPool;  
  
    public RabbitManager(IPooledObjectPolicy<IModel> objectPolicy)  
    {  
        _objectPool = new DefaultObjectPool<IModel>(objectPolicy, Environment.ProcessorCount * 2);  
    }  
  
    public void Publish<T>(T message, string exchangeName, string exchangeType, string routeKey)   
        where T : class  
    {  
        if (message == null)  
            return;  
  
        var channel = _objectPool.Get();  
  
        try  
        {  
            channel.ExchangeDeclare(exchangeName, exchangeType, true, false, null);  
  
            var sendBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message));  
  
            var properties = channel.CreateBasicProperties();  
            properties.Persistent = true;  
  
            channel.BasicPublish(exchangeName, routeKey, properties, sendBytes);  
        }  
        catch (Exception ex)  
        {  
            throw ex;  
        }  
        finally  
        {  
            _objectPool.Return(channel);                  
        }  
    }  
}  

یک object pool در سازنده ایجاد می کنیم.

پیش از انتشار پیغام ها در RabbitMQ، باید کلاسی از object pool بگیریم، سپس payload (بسته ی اطلاعاتی) را بسازیم.

پس از انتشار، باید این شیء کانال را، چه انتشار موفق باشد یا شکست بخورد، به object pool برگردانیم.

افزونه ی RabbitMQ

یک متد افزونه (extension) جهت ساده سازی عملیات ثبت ایجاد کنید.

public static class RabbitServiceCollectionExtensions  
{  
    public static IServiceCollection AddRabbit(this IServiceCollection services, IConfiguration configuration)  
    {  
        var rabbitConfig = configuration.GetSection("rabbit");  
        services.Configure<RabbitOptions>(rabbitConfig);  
  
        services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();  
        services.AddSingleton<IPooledObjectPolicy<IModel>, RabbitModelPooledObjectPolicy>();  
  
        services.AddSingleton<IRabbitManager, RabbitManager>();  
  
        return services;  
    }  
} 

به کلاس Startup بروید.

public void ConfigureServices(IServiceCollection services)  
{  
    services.AddRabbit(Configuration);  
  
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);  
}  

کاربرد RabbitMQ Manager

مقداری کد به ValuesController می افزاییم.

[Route("api/[controller]")]  
[ApiController]  
public class ValuesController : ControllerBase  
{  
    private IRabbitManager _manager;  
  
    public ValuesController(IRabbitManager manager)  
    {  
        _manager = manager;  
    }  
  
    // GET api/values  
    [HttpGet]  
    public ActionResult<IEnumerable<string>> Get()  
    {  
        // other opreation  
  
        // if above operation succeed, publish a message to RabbitMQ  
  
        var num = new System.Random().Next(9000);  
  
        // publish message  
        _manager.Publish(new  
        {  
            field1 = $"Hello-{num}",  
            field2 = $"rabbit-{num}"                  
        }, "demo.exchange.topic.dotnetcore", "topic", "*.queue.durable.dotnetcore.#");  
  
        return new string[] { "value1", "value2" };  
    }  
}  

در اینجا، یک نوع تبادل موضوع به نام demo.exchange.topic.dotnetcore ایجاد خواهیم کرد، و آن هم پیغام را به صف هایی که کلید مسیریابی با نام *.queue.durable.dotnetcore.# را پیوند می دهند، ارسال خواهد کرد.

نکته

یک پیغام در یک صف تنها توسط یک مصرف کننده مصرف خواهد شد.

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

انتشار پیغام با RabbitMQ

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

می توانیم برای بررسی پیغام از دکمه ی GetMessage استفاده کنیم.

انتشار پیغام با RabbitMQ

کد نویسی به کام

  • پسورد: www.mspsoft.com
زهره سلطانیان

نوشته‌های مرتبط

دیدگاه‌ها

*
*

این سایت از اکیسمت برای کاهش هرزنامه استفاده می کند. بیاموزید که چگونه اطلاعات دیدگاه های شما پردازش می‌شوند.