简体   繁体   English

Blazor 中的 SendGrid email 服务 - 依赖注入或 Static 方法

[英]SendGrid email service in Blazor - Dependency Injection or Static method

I am setting up a SendGrid email sender in a Blazor app (.NET 5).我正在 Blazor 应用程序(.NET 5)中设置 SendGrid email 发件人。

Per the SendGrid docs and examples, they are writing a method signed as static async Task and then they await the response from their api.根据 SendGrid 文档和示例,他们正在编写一个签名为static async Task的方法,然后他们await api 的响应。 Their example code just runs immediately from Main() and doesn't show any method calls.他们的示例代码只是从Main()立即运行并且不显示任何方法调用。

Does using this as a static method violate how I should be using Dependency Injenction?将其用作 static 方法是否违反了我应该如何使用依赖注入? Shouldn't I register this EmailSender class as a service with Dependency Injection and then inject it in my components that need to send emails?我不应该将此 EmailSender class 注册为具有依赖注入的服务,然后将其注入需要发送电子邮件的组件中吗?

Code from SendGrid example: SendGrid 示例中的代码:

private static void Main()
{
    Execute().Wait();
}

static async Task Execute()
{
    //Boilerplate code setting up email from/to/apiKey etc removed
    var response = await client.SendEmailAsync(msg);
}

With this setup, I could make the Execute() method public and then call it directly as a static method.通过此设置,我可以公开 Execute() 方法,然后将其作为 static 方法直接调用。

Would it be more appropriate to make something like the following:做如下内容是否更合适:

public class EmailService
{
    public async Task SendEmail(string to, string subject, string message)
    {
        //Boilerplate code setting up email from/to/apiKey etc removed
        var response = await client.SendEmailAsync(msg);
    }
}

Then I could inject and use the service via DI, like:然后我可以通过 DI 注入和使用该服务,例如:

@inject EmailService emailService

@code {
    //Calling line below in the appropriate spot
    await emailService.SendEmail(to, subject, message);
}

A generalized implementation in .NET Core: .NET Core 中的通用实现:

Startup.cs启动.cs

using SendGrid.Extensions.DependencyInjection; // nuget package

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // sendgrid
        services.AddSendGrid(options =>
        {
            options.ApiKey = Environment.GetEnvironmentVariable("SENDGRID_API_KEY");
        });
    }
}

EmailController.cs电子邮件控制器.cs

using SendGrid; // nuget package

public class EmailController : ControllerBase
{
    private ISendGridClient = sendGridClient;
    
    public EmailController(ISendGridClient sendGridClient)
    {
        _sendGridClient = sendGridClient;
    }
    
    public IActionResult SendEmail(Email email)
    {
        var emailManager = new EmailManager(_sendGridClient);
        return emailManager.SendEmail(email);
    }
}

EmailManager.cs电子邮件管理器.cs

using SendGrid;

public class EmailManager
{
    private ISendGridClient = _sendGridClient;
    
    public EmailManager(ISendGridClient sendGridClient)
    {
        _sendGridClient = sendGridClient;
    }
    
    public bool SendEmail(Email email)
    {
        ...
        var response = await _sendGridClient.SendEmailAsync(msg);
        ...
    }
}

An example for NET 6 Web API with Controllers带有控制器的 NET 6 Web API 的示例

https://github.com/Davidmendoza1987/dotnet-sendgrid-exampleshttps://github.com/Davidmendoza1987/dotnet-sendgrid-examples

You will need the following nuget packages installed您将需要安装以下 nuget 软件包

  • SendGrid发送网格
  • SendGrid.Extensions.DependencyInjection SendGrid.Extensions.DependencyInjection

Program.cs程序.cs

using SendGridExample.Net6.V1.Extensions;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Custom Code
builder.Services.AddThirdPartyServices();
builder.Services.AddRepositories();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();    
app.UseAuthorization();    
app.MapControllers();

app.Run();

ServiceCollectionExtensions.cs ServiceCollectionExtensions.cs

using SendGrid;
using SendGrid.Extensions.DependencyInjection;
using SendGridExample.Net6.V1.Repositories;

namespace SendGridExample.Net6.V1.Extensions;

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddThirdPartyServices(this IServiceCollection servicesCollection)
    {
        var sendGridApiKey = Environment.GetEnvironmentVariable("SENDGRID_API_KEY");
        if (sendGridApiKey is null)
        {
            throw new ArgumentNullException(sendGridApiKey, "SendGrid API key has not been configured"); 
        }

        servicesCollection.AddSendGrid(options => options.ApiKey = sendGridApiKey);

        return servicesCollection;
    }

    public static IServiceCollection AddRepositories(this IServiceCollection servicesCollection)
    {
        servicesCollection.AddTransient<ISendGridRepository, SendGridRepository>(x =>
            new SendGridRepository(x.GetRequiredService<ISendGridClient>()));

        return servicesCollection;
    }    
}

SendEmailRequest.cs发送电子邮件请求.cs

using System.ComponentModel.DataAnnotations;

namespace SendGridExample.Net6.V1.Models;

public class SendEmailRequest
{
    [Required]
    public List<string> To { get; set; } = new List<string>();

    [Required]
    public string From { get; set; } = string.Empty;

    [Required]
    public string FromName { get; set; } = string.Empty;

    [Required]
    public string Subject { get; set; } = string.Empty;

    public string? PlainTextContent { get; set; }

    public string? HtmlContent { get; set; }

    public bool? ShowAllRecipients { get; set; } = false;
}

SendGridController.cs发送网格控制器.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using SendGrid;
using SendGridExample.Net6.V1.Models;
using SendGridExample.Net6.V1.Repositories;

namespace SendGridExample.Net6.Controllers;

[ApiController]
[Route("[controller]")]
public class SendGridController : ControllerBase
{
    private readonly ISendGridRepository sendGridRepository;

    public SendGridController(ISendGridRepository sendGridRepository) => this.sendGridRepository = sendGridRepository;

    [HttpPost("send-email")]
    [ProducesResponseType(typeof(Response), StatusCodes.Status200OK)]
    public async Task<ActionResult<Response>> SendEmail([FromBody, BindRequired] SendEmailRequest request)
    {
        if (string.IsNullOrWhiteSpace(request.PlainTextContent) &&
            string.IsNullOrWhiteSpace(request.HtmlContent))
        {
            return BadRequest("Either PlainTextContent or HtmlContent must be provided.");
        }

        var response = await sendGridRepository.SendTransactionEmailAsync(request);
        return StatusCode((int)response.StatusCode, response);
    }
}

SendGridRepository.cs SendGridRepository.cs

using SendGrid;
using SendGrid.Helpers.Mail;
using SendGridExample.Net6.V1.Models;

namespace SendGridExample.Net6.V1.Repositories;

public interface ISendGridRepository
{
    Task<Response> SendTransactionEmailAsync(SendEmailRequest request);
}

public class SendGridRepository : ISendGridRepository
{
    private readonly ISendGridClient sendGridClient;

    public SendGridRepository(ISendGridClient sendGridClient) => this.sendGridClient = sendGridClient;

    public async Task<Response> SendTransactionEmailAsync(SendEmailRequest request)
    {
        var toAddresses = request.To.Select(n => new EmailAddress(n)).ToList();
        var fromAddress = new EmailAddress(request.From, request.FromName);
        var msg = MailHelper.CreateSingleEmailToMultipleRecipients(fromAddress, toAddresses, request.Subject, request.PlainTextContent, request.HtmlContent, request.ShowAllRecipients!.Value);

        return await sendGridClient.SendEmailAsync(msg);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM