Configure Send Endpoint in MassTransit

public record SubmitOrder
{
    public string OrderId { get; init; }
}

public async Task SendOrder(ISendEndpointProvider sendEndpointProvider)
{
    var endpoint = await sendEndpointProvider.GetSendEndpoint(_serviceAddress);

    await endpoint.Send(new SubmitOrder { OrderId = "123" });
}

Endpoint Address

rabbitmq://localhost/input-queue
rabbitmq://localhost/input-queue?durable=false

Short Addresses

GetSendEndpoint(new Uri("queue:input-queue"))

Address Conventions

Using send endpoints might seem too verbose, because before sending any message, you need to get the send endpoint and to do that you need to have an endpoint address. Usually, addresses are kept in the configuration and accessing the configuration from all over the application is not a good practice.

Endpoint conventions solve this issue by allowing you to configure the mapping between message types and endpoint addresses. A potential downside here that you will not be able to send messages of the same type to different endpoints by using conventions. If you need to do this, keep using the GetSendEndpoint method.

EndpointConvention.Map<SubmitOrder>(new Uri("rabbitmq://mq.acme.com/order/order_processing"));
public async Task Post(SubmitOrderRequest request)
{
    if (AllGoodWith(request))
        await _bus.Send(ConvertToCommand(request));
}

Also, from inside the consumer, you can do the same using the ConsumeContext.Send overload:

EndpointConvention.Map<StartDelivery>(new Uri(ConfigurationManager.AppSettings["deliveryServiceQueue"]));

The EndpointConvention.Map<T> method is static, so it can be called from everywhere. It is important to remember that you cannot configure conventions for the same message twice. If you try to do this – the Map method will throw an exception. This is also important when writing tests, so you need to configure the conventions at the same time as you configure your test bus (harness).

It is better to configure send conventions before you start the bus.

References
https://masstransit.io/documentation/concepts/producers#send-endpoint
https://stackoverflow.com/questions/62713786/masstransit-endpointconvention-azure-service-bus/

Configure Receive Endpoints in MassTransit

Explicitly Configure Endpoints

services.AddMassTransit(x =>
{
    x.AddConsumer<SubmitOrderConsumer>();
    
    x.UsingRabbitMq((context, cfg) =>
    {
        cfg.ReceiveEndpoint("order-service", e =>
        {
            e.ConfigureConsumer<SubmitOrderConsumer>(context);
        });
    });
});

Temporary Endpoints

Some consumers only need to receive messages while connected, and any messages published while disconnected should be discarded. This can be achieved by using a TemporaryEndpointDefinition to configure the receive endpoint.

services.AddMassTransit(x =>
{
    x.AddConsumer<SubmitOrderConsumer>();

    x.UsingInMemory((context, cfg) =>
    {
        cfg.ReceiveEndpoint(new TemporaryEndpointDefinition(), e =>
        {
            e.ConfigureConsumer<SubmitOrderConsumer>(context);
        });

        cfg.ConfigureEndpoints(context);
    });
});

Endpoint Configuration

services.AddMassTransit(x =>
{
    x.AddConsumer<SubmitOrderConsumer>(typeof(SubmitOrderConsumerDefinition))
        .Endpoint(e =>
        {
            // override the default endpoint name
            e.Name = "order-service-extreme";

            // specify the endpoint as temporary (may be non-durable, auto-delete, etc.)
            e.Temporary = false;

            // specify an optional concurrent message limit for the consumer
            e.ConcurrentMessageLimit = 8;

            // only use if needed, a sensible default is provided, and a reasonable
            // value is automatically calculated based upon ConcurrentMessageLimit if
            // the transport supports it.
            e.PrefetchCount = 16;

            // set if each service instance should have its own endpoint for the consumer
            // so that messages fan out to each instance.
            e.InstanceId = "something-unique";
        });

    x.UsingRabbitMq((context, cfg) => cfg.ConfigureEndpoints(context));
});

References
https://masstransit.io/documentation/configuration#receive-endpoints

Install RabbitMQ on Ubuntu 22.04 using Ubuntu Repository

Install Erlang

sudo apt update
sudo apt install curl software-properties-common apt-transport-https lsb-release
curl -fsSL https://packages.erlang-solutions.com/ubuntu/erlang_solutions.asc | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/erlang.gpg
sudo apt update
sudo apt install erlang

Install RabbitMQ

sudo apt-get install rabbitmq-server -y --fix-missing

Enable the RabbitMQ Management Dashboard

sudo rabbitmq-plugins enable rabbitmq_management

References
https://computingforgeeks.com/how-to-install-latest-erlang-on-ubuntu-linux/
https://computingforgeeks.com/how-to-install-latest-rabbitmq-server-on-ubuntu-linux/

Detect Online Users using Circuit Handler in ASP.NET Blazor Server

public class UserCircuitHandler : CircuitHandler
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public UserCircuitHandler(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public override async Task OnConnectionUpAsync(Circuit circuit,
        CancellationToken cancellationToken)
    {
        var httpContext = _httpContextAccessor.HttpContext;
        var userAgent = httpContext.Request.Headers["User-Agent"];
        string uaString = userAgent.ToString();
        var uaParser = Parser.GetDefault();
        ClientInfo c = uaParser.Parse(uaString);
        Console.WriteLine(httpContext.User.Identity.Name);
    }

    public override async Task OnConnectionDownAsync(Circuit circuit,
        CancellationToken cancellationToken)
    {
        var httpContext = _httpContextAccessor.HttpContext;
        var userAgent = httpContext.Request.Headers["User-Agent"];
        string uaString = userAgent.ToString();
        var uaParser = Parser.GetDefault();
        ClientInfo c = uaParser.Parse(uaString);
        Console.WriteLine(httpContext.User.Identity.Name);
    }
}

References
https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/signalr?view=aspnetcore-7.0#blazor-server-circuit-handler
https://learn.microsoft.com/en-us/aspnet/core/blazor/security/server/additional-scenarios?view=aspnetcore-7.0#circuit-handler-to-capture-users-for-custom-services

How to Increase Maximum Upload File Size in WordPress

Edit .htaccess file

php_value upload_max_filesize 128M
php_value post_max_size 128M
php_value memory_limit 256M
php_value max_execution_time 300
php_value max_input_time 300

Or

Edit wp-config.php file

@ini_set( 'upload_max_filesize' , '128M' );
@ini_set( 'post_max_size', '128M');
@ini_set( 'memory_limit', '256M' );
@ini_set( 'max_execution_time', '300' );
@ini_set( 'max_input_time', '300' );

References
https://help.servmask.com/2018/10/27/how-to-increase-maximum-upload-file-size-in-wordpress/

Apply Authorization to All Pages in Blazor

Program.cs

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

builder.Services.ConfigureApplicationCookie(options =>
{
    options.ExpireTimeSpan=TimeSpan.FromDays(14);
    options.SlidingExpiration = true;
    options.Cookie.Name = "BI";
    options.Cookie.HttpOnly = true;
    options.LoginPath = "/Login";
    options.LogoutPath="/Logout";
});

To apply authorization to all pages in Blazor, you have to add:

@attribute [Microsoft.AspNetCore.Authorization.Authorize]

…to your _Imports.razor file.

@attribute [Microsoft.AspNetCore.Authorization.AllowAnonymous]

…on pages that don’t require authorization.

References
https://stackoverflow.com/questions/60840986/blazor-redirect-to-login-if-user-is-not-authenticated
https://stackoverflow.com/questions/71434131/blazor-allow-anonymous-for-razor-page
https://stackoverflow.com/questions/50633896/asp-net-core-identity-change-login-url
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/secure-data?view=aspnetcore-7.0

Enable RTL (right-to-left) in Ionic

Implementing RTL in Ionic 5 apps is very easy. It can be done in two ways

  • Using dir="rtl" attribute in HTML tags
  • Using direction= rtl in css

Using HTML tag

If you want to convert the complete app into RTL layout, then use dir="rtl" on <html> tag itself.

Using CSS at global level

You can also convert the complete app to RTL using CSS in global.scss

:root {
direction: rtl;
}

References
https://enappd.com/blog/how-to-use-rtl-right-to-left-in-ionic-apps-pwa/152/