In ASP.NET Core-6 Web API Application, I am implementing MailKit. So I have this code:
I have this in the Utilities.
EmailConfigurations:
public class EmailConfigurations
{
public string SmtpHost { get; set; }
public string SenderName { get; set; }
public string SenderEmail { get; set; }
public int SmtpPort { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
Then the Service.
MailService:
public class MailService : IMailService
{
private readonly ILogger _logger;
private readonly EmailConfigurations _emailConfig;
public MailService(
ILogger logger,
EmailConfigurations emailConfig
)
{
_logger = logger;
_emailConfig = emailConfig;
}
public async Task<bool> SendEmailAsync(MailRequest mailRequest)
{
var email = new MimeMessage { Sender = MailboxAddress.Parse(_emailConfig.SenderEmail) };
email.To.Add(MailboxAddress.Parse(mailRequest.ToEmail));
email.Subject = mailRequest.Subject;
var builder = new BodyBuilder();
if (mailRequest.Attachments != null)
{
foreach (var file in mailRequest.Attachments.Where(file => file.Length > 0))
{
byte[] fileBytes;
await using (var ms = new MemoryStream())
{
file.CopyTo(ms);
fileBytes = ms.ToArray();
}
builder.Attachments.Add((file.FileName Guid.NewGuid().ToString()), fileBytes, ContentType.Parse(file.ContentType));
}
}
builder.HtmlBody = mailRequest.Body;
email.Body = builder.ToMessageBody();
try
{
using var smtp = new SmtpClient();
smtp.Connect(_emailConfig.SmtpHost, _emailConfig.SmtpPort, MailKit.Security.SecureSocketOptions.None);
smtp.AuthenticationMechanisms.Remove("XOAUTH2");
smtp.CheckCertificateRevocation = false;
await smtp.SendAsync(email);
smtp.Disconnect(true);
return true;
}
catch (Exception e)
{
_logger.Error(e, e.Source, e.InnerException, e.Message, e.ToString());
return false;
}
}
}
EmailSender:
public class EmailSender : IEmailSender
{
private readonly EmailConfigurations _emailConfig;
private readonly ILogger _logger;
public EmailSender(
EmailConfigurations emailConfig,
ILogger logger
)
{
_emailConfig = emailConfig;
_logger = logger;
}
public void SendEmail(Message message)
{
var emailMessage = CreateEmailMessage(message);
Send(emailMessage);
}
public async Task SendEmailAsync(Message message)
{
var mailMessage = CreateEmailMessage(message);
await SendAsync(mailMessage);
}
private MimeMessage CreateEmailMessage(Message message)
{
var emailMessage = new MimeMessage();
emailMessage.From.Add(new MailboxAddress(_emailConfig.SenderEmail));
emailMessage.To.AddRange(message.To);
emailMessage.Subject = message.Subject;
var bodyBuilder = new BodyBuilder { HtmlBody = string.Format("<h2 style='color:red;'>{0}</h2>", message.Content) };
if (message.Attachments != null && message.Attachments.Any())
{
byte[] fileBytes;
foreach (var attachment in message.Attachments)
{
using (var ms = new MemoryStream())
{
attachment.CopyTo(ms);
fileBytes = ms.ToArray();
}
bodyBuilder.Attachments.Add(attachment.FileName, fileBytes, ContentType.Parse(attachment.ContentType));
}
}
emailMessage.Body = bodyBuilder.ToMessageBody();
return emailMessage;
}
private void Send(MimeMessage mailMessage)
{
using (var client = new SmtpClient())
{
try
{
client.Connect(_emailConfig.SmtpHost, _emailConfig.SmtpPort, MailKit.Security.SecureSocketOptions.None);
client.AuthenticationMechanisms.Remove("XOAUTH2");
client.CheckCertificateRevocation = false;
client.Send(mailMessage);
}
catch (Exception ex)
{
_logger.Information(JsonConvert.SerializeObject(ex));
throw;
}
finally
{
client.Disconnect(true);
client.Dispose();
}
}
}
private async Task SendAsync(MimeMessage mailMessage)
{
using (var client = new SmtpClient())
{
try
{
// client.Connect(_emailConfig.SmtpHost, _emailConfig.SmtpPort, true);
client.Connect(_emailConfig.SmtpHost, _emailConfig.SmtpPort, MailKit.Security.SecureSocketOptions.None);
client.AuthenticationMechanisms.Remove("XOAUTH2");
// client.Authenticate(_emailConfig.Username, _emailConfig.Password);
client.CheckCertificateRevocation = false;
await client.SendAsync(mailMessage);
}
catch (Exception ex)
{
_logger.Information(JsonConvert.SerializeObject(ex));
throw;
}
finally
{
await client.DisconnectAsync(true);
client.Dispose();
}
}
}
}
Then I have the Dependency Injection.
public static class DIServiceExtension
{
public static void AddDependencyInjection(this IServiceCollection services)
{
// Add Service Injections Here
services.AddScoped<IAuthService, AuthService>();
services.AddScoped<ITokenGeneratorService, TokenGeneratorService>();
services.AddScoped<ITokenRepository, TokenRepository>();
services.AddTransient<IMailService, MailService>();
services.AddScoped<IEmailSender, EmailSender>();
}
}
Program.cs:
// Register Dependency Injection Service Extension
builder.Services.AddDependencyInjection();
var app = builder.Build();
But I got this error:
System.AggregateException
HResult=0x80131500
Message=Some services are not able to be constructed (Error while validating the service descriptor
'ServiceType: Lms.Application.Services.Abstract.IEmailSender Lifetime: Scoped ImplementationType:
Lms.Application.Services.Concrete.EmailSender': Unable to resolve service for type
'Lms.Application.Utilities.v1.Common.EmailConfigurations' while attempting to activate 'Lms.Application.Services.Concrete.EmailSender'.)
Source=Microsoft.Extensions.DependencyInjection
StackTrace:
at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options)
at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)
at Microsoft.Extensions.DependencyInjection.DefaultServiceProviderFactory.CreateServiceProvider(IServiceCollection containerBuilder)
at Microsoft.Extensions.Hosting.Internal.ServiceFactoryAdapter`1.CreateServiceProvider(Object containerBuilder)
at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
at Microsoft.Extensions.Hosting.HostBuilder.Build()
at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build()
at Program.<<Main>$>d__0.MoveNext() in C:\Lms.WebApi\Program.cs:line 172
at Program.<Main>(String[] args)
This exception was originally thrown at this call stack:
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(System.Type, Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteChain, System.Reflection.ParameterInfo[], bool)
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Microsoft.Extensions.DependencyInjection.ServiceLookup.ResultCache, System.Type, System.Type, Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteChain)
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Microsoft.Extensions.DependencyInjection.ServiceDescriptor, System.Type, Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteChain, int)
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(Microsoft.Extensions.DependencyInjection.ServiceDescriptor, Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteChain)
Microsoft.Extensions.DependencyInjection.ServiceProvider.ValidateService(Microsoft.Extensions.DependencyInjection.ServiceDescriptor)
Inner Exception 1:
InvalidOperationException: Error while validating the service descriptor 'ServiceType: Lms.Application.Services.Abstract.IMailService Lifetime: Transient ImplementationType: Lms.Application.Services.Concrete.MailService': Unable to resolve service for type 'Lms.Application.Utilities.v1.Common.EmailConfigurations' while attempting to activate 'Lms.Application.Services.Concrete.MailService'.
Inner Exception 2:
InvalidOperationException: Unable to resolve service for type 'Lms.Application.Utilities.v1.Common.EmailConfigurations' while attempting to activate 'Lms.Application.Services.Concrete.MailService'.
C:\Lms.WebApi\Program.cs:line 172
is
var app = builder.Build();
Where did I get it wrong and how do I resolve this?
CodePudding user response:
As mentioned in the comment, you didn't register the EmailConfigurations
as a dependency.
Assume that you are extracting the value from appsettings.json as below:
{
"EmailConfigurations": {
"SmtpHost": "Value of SmtpHost",
"SenderName": "Value of SenderName",
// Other properties
}
}
- Bind the configuration value to
EmailConfigurations
class.
builder.Services.Configure<EmailConfigurations>(
builder.Configuration.GetSection("EmailConfigurations"));
- In
MailService
, get the injected dependency forEmailConfigurations
withIOptions<EmailConfigurations>
and its value.
public class MailService : IMailService
{
private readonly ILogger _logger;
private readonly EmailConfigurations _emailConfig;
public MailService(
ILogger logger,
IOption<EmailConfigurations> emailConfigOption
)
{
_logger = logger;
_emailConfig = emailConfigOption.Value;
}
...
}
- Sames goes to
EmailSender
, follow step 2.
public class EmailSender : IEmailSender
{
private readonly EmailConfigurations _emailConfig;
private readonly ILogger _logger;
public EmailSender(
IOption<EmailConfigurations> emailConfigOption,
ILogger logger
)
{
_emailConfig = emailConfigOption.Value;
_logger = logger;
}
...
}
Reference: Bind hierarchical configuration data using the options pattern