SendGrid

El objetivo de este escenario es tener una situación más cercana al mundo real en la que tendremos un microservicio de “Pedido” y queremos enviar correos electrónicos con cada pedido creado.

Importante

En el siguiente ejemplo se usa SendGrid, pero puede usar cualquier biblioteca que desee, el enfoque en este punto está en comprender cómo Devprime permite el uso de extensiones y cómo integrarlas en su proyecto sin dañar los principios de arquitectura establecidos, asegurando la separación de responsabilidades y el desacoplamiento.

Creación de un microservicio para usar en el ejemplo

Utilizaremos un microservicio basado en la plataforma Devprime

Escriba el siguiente comando en un directorio de su elección y, a continuación, abra el proyecto en Visual Studio, VSCODE o el IDE que prefiera:

dp new order --state mongodb --stream rabbitmq --marketplace order

Vaya a la carpeta raíz del proyecto: .\order\

Implementaciones de dominio

Vamos a incluir un campo de Email en nuestra capa aggregate root en el dominio. Abra la clase existente Order.cs en la ruta code .\src\core\domain\aggregates\order\Order.cs, agregue la propiedad como se resalta a continuación (línea 6) y guarde los cambios:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
namespace Domain.Aggregates.Order;
public class Order : AggRoot
{
    public string CustomerName { get; private set; }
    public string CustomerTaxID { get; private set; }
    public string Email { get; private set; }
    public IList<Item> Itens { get; private set; }
    public double Total { get; private set; }
    public void AddItem(Item item)
    {
        if (item != null && Itens != null)
        {
            var myItens = Itens.Where(p => p.SKU == item.SKU).FirstOrDefault();
            if (myItens != null)
                myItens.Sum(item.Amount);
            else
                Itens.Add(item);
        }
    }
}

Aceleración de las implementaciones con la CLI

El siguiente paso será usar la CLI para acelerar la mayoría de las implementaciones necesarias y para eso escriba el siguiente comando en su terminal:

dp init

La CLI solicita autorización para cambiar los archivos necesarios de la solución, en este caso escribiremos A para autorizar todos los archivos.

Iniciando la configuración de SendGrid

Cambie la configuración de la tecla “Devprime_Custom” como se muestra en el siguiente ejemplo:
code .\src\app\appsettings.json

1
2
3
4
5
6
"Devprime_Custom": {
    "sendgrid.ssettings.apikey": "API_KEY_SENDGRID",
    "sendgrid.from.email": "YOUR_EMAIL_REGISTERED_AT_SENDGRID",
    "sendgrid.from.name": "YOUR_NAME",
    "stream.orderevents": "orderevents"
}

Agregar una extensión

Ahora vamos a incluir la clase “MailService” que será nuestra extensión, a través del siguiente comando de la CLI de Devprime.

1
dp add extensions MailService

La CLI solicita otra autorización para cambiar los archivos necesarios de la solución, presione A para autorizar todos los archivos.

En la siguiente imagen se muestra la clase MailService y su interfaz IMailService, que se encargará de implementar las integraciones con la API SendGrid.

También muestra la clase Extensions y la interfaz IExtensions cuyo propósito es ser un proxy que permita que el contexto de ejecución de Devprime Pipeline acceda a todas las extensiones disponibles en la aplicación a través de la inserción de dependencias.

Clave de extensiones de Devprime

Al ejecutar el comando para incluir la extensión, tenga en cuenta que la CLI también generó su inyección en la clase “Extensiones”: code .\src\adapters\extensions\Extensions.cs

1
2
3
4
5
6
7
8
9
public class Extensions : IExtensions
{
    public Extensions(IMailService mailService)
    {
        MailService = mailService;
    }

    public IMailService MailService { get; }
}

Agregar la referencia a la biblioteca SendGrid

Vamos a incluir la biblioteca SendGrid en nuestro proyecto, recuerde establecer el destino de instalación para el proyecto “Devprime.Extensions”. code .\src\adapters\extensions\Devprime.Extensions.csproj

A través de dotnet CLI

dotnet add .\src\adapters\extensions\Devprime.Extensions.csproj package SendGrid

Ejecute también dotnet build en el proyecto. (Recuerde estar en la carpeta raíz del proyecto .\order\):

dotnet build

Implementación de la integración con SendGrid

Vamos a cambiar la interfaz “IMailService” code .\src\core\application\interfaces\adapters\extensions\IMailService.cs, incluida la siguiente firma de método:

1
2
3
bool SendMail(string subject,
              string plainText,
              string htmlMessage);

También necesitamos implementar el método en la clase “MailService”
code .\src\adapters\extensions\mailservice\MailService.cs, según el siguiente modelo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using SendGrid;
using SendGrid.Helpers.Mail;
using System.Net;

namespace Devprime.Extensions.MailService;
public class MailService : DevprimeExtensions, IMailService
{
    private string ApiKey { get; set; }
    private string FromEmail { get; set; }
    private string FromName { get; set; }

    public MailService(IDpExtensions dp) : base(dp)
    {
        ApiKey = Dp.Settings.Default("sendgrid.ssettings.apikey");
        FromEmail = Dp.Settings.Default("sendgrid.from.email");
        FromName = Dp.Settings.Default("sendgrid.from.name");
    }

    public bool SendMail(string email, string name, string plainText)
    {
        var Client = new SendGridClient(ApiKey);
        var From = new EmailAddress(FromEmail, FromName);
        var Subject = "Thank you to shopping at DpCommerce";
        var To = new EmailAddress(email, name);
        var PlainTextContent = plainText;

        var msg = MailHelper.CreateSingleEmail(From, To,
         Subject, PlainTextContent, null);
        var response = Client.SendEmailAsync(msg).Result;
        if (!response.StatusCode.Equals(HttpStatusCode.OK) &&
         !response.StatusCode.Equals(HttpStatusCode.Accepted))
        {
            Dp.Observability.Log($"[Not possible to send message.
             Details: {response.StatusCode} - 
             {response.Body.ReadAsStringAsync().Result}
             - {response.Headers}]");

            return false;
        }

        return true;
    }
}

Echemos un vistazo más de cerca a algunas de las características que existen en el código anterior:

Código Descripción
Dp.Settings.Default("…") Obtener clave en la aplicación AppSettings.json
Dp.Observability.Log("…") Imprime tronco persoanlizado

Se implementó la llamada al adaptador de extensión

Nuestro escenario implica un evento de dominio denominado “OrderCreated” y asociado a él hay un EventHandler denominado “OrderCreatedEventHandler”, que tiene una llamada al adaptador de estado de Devprime para la persistencia de datos (línea 11) y emite un evento externo a la aplicación (línea 23).
Camino: code .\src\core\application\eventhandlers\order\OrderCreatedEventHandler.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
namespace Application.EventHandlers.Order;
public class OrderCreatedEventHandler :
EventHandler<OrderCreated, IOrderState>
{
    public OrderCreatedEventHandler(IOrderState state, IDp dp) :
     base(state, dp) { }

    public override dynamic Handle(OrderCreated orderCreated)
    {
        var success = false;
        var order = orderCreated.Get<Domain.Aggregates.Order.Order>();

        Dp.State.Order.Add(order);

        var destination = Dp.Settings.Default("stream.orderevents");
        var eventName = "OrderCreated";
        var eventData = new OrderCreatedEventDTO()
        {
            ID = order.ID,
            CustomerName = order.CustomerName,
            CustomerTaxID = order.CustomerTaxID,
            Total = order.Total
        };

        Dp.Stream.Send(destination, eventName, eventData);

        success = true;
        return success;
    }
}

Cambiemos el código de nuestro EventHandler de acuerdo con el siguiente modelo (ver líneas resaltadas):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
namespace Application.EventHandlers.Order;
public class OrderCreatedEventHandler : 
EventHandlerWithStateAndExtensions<OrderCreated, IOrderState,
IExtensions>
{
    public OrderCreatedEventHandler(IOrderState state,
    IExtensions extension, IDp dp) : base(state, extension, dp) { }

    public override dynamic Handle(OrderCreated orderCreated)
    {
        var success = false;
        var order = orderCreated.Get<Domain.Aggregates.Order.Order>();

        Dp.State.Order.Add(order);

        var destination = Dp.Settings.Default("stream.orderevents");
        var eventName = "OrderCreated";
        var eventData = new OrderCreatedEventDTO()
        {
            ID = order.ID,
            CustomerName = order.CustomerName,
            CustomerTaxID = order.CustomerTaxID,
            Total = order.Total
        };
        Dp.Stream.Send(destination, eventName, eventData);

        success = Dp.Extensions.MailService.SendMail(order.Email,
         order.CustomerName, "Your content here");
        return success;
    }
}

Probando la aplicación

Ahora que tenemos las implementaciones necesarias, ejecutemos el microservicio usando el siguiente comando:

Windows

.\run.ps1

Linux/Mac

.\run.sh

En el navegador, vaya al enlace: https://localhost:5001/swagger, usaremos el método POST para crear un nuevo pedido:

Clave de extensiones de Devprime `

Utilice el cuerpo de la solicitud a continuación:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "customerName": "YOUR_NAME",
  "customerTaxID": "12345678910",
  "email": "TYPE_YOU_EMAIL",
  "itens": [
    {
      "description": "TV",
      "amount": 1,
      "sku": "TV001",
      "price": 1000.00
    }
  ]
}

Debería recibir el correo electrónico tal y como está configurado en la aplicación.

Más artículos sobre extensiones

Humanizador

Última modificación April 16, 2024 (3a53067d)