Home > Enterprise >  ASP.NET Core Web API - Some services are not able to be constructed (Error while validating the serv
ASP.NET Core Web API - Some services are not able to be constructed (Error while validating the serv

Time:02-03

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
  }
}
  1. Bind the configuration value to EmailConfigurations class.
builder.Services.Configure<EmailConfigurations>(
    builder.Configuration.GetSection("EmailConfigurations"));
  1. In MailService, get the injected dependency for EmailConfigurations with IOptions<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;
    }

    ...

}
  1. 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

  • Related