ASP.NET CORE: Sending Email with Gmail and Homtail Account using ASP.NET Core services

Standard

Sending email from any SMTP server from ASP.NET CORE application is pretty easy, but the flow of command is slight different in core environment.

Gmail SMTP server address is smtp.gmail.com. It requires implicit SSL or explicit SSL (TLS) connection, and you should use your Gmail email address as the user name for ESMTP authentication.

So basically we will read email smtp address, port, username and password from appsettings.json, then will inject these config to email service class, in the end we will inject email service class to controller and consumer email send operation.

Step 1: Define email specific information in appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": ""
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "EmailSettings": {
    "PrimaryDomain": "smtp.gmail.com",
    "PrimaryPort": "587",
    "SecondayDomain": "smtp.live.com",
    "SecondaryPort": "587",
    "UsernameEmail": "emailId@gmail.com",
    "UsernamePassword": "emailPassword",
    "FromEmail": "fromEmail",
    "ToEmail": "toEmail",
    "CcEmail": "ccEmail"
  }
}

SmtpServer: The name of the server that will be used to send the emails.

SmtpPort: The port, which the server will use to send SMTP transactions (emails).

EnableSsl: True, if the server should use SSL (Secure Socket Layer) encryption.

Smtp Server Address and Port #

Server Name SMTP Address Port SSL
Yahoo! smtp.mail.yahoo.com 587 Yes
GMail smtp.gmail.com 587 Yes
Hotmail smtp.live.com 587 Yes

Step 2: Create a class to encapsulate EmailSettings properties from appsettings.json

public class EmailSettings
    {
        public String PrimaryDomain { get; set; }

        public int PrimaryPort { get; set; }

        public String SecondayDomain { get; set; }

        public int SecondaryPort { get; set; }

        public String UsernameEmail { get; set; }

        public String UsernamePassword { get; set; }

        public String FromEmail { get; set; }

        public String ToEmail { get; set; }

        public String CcEmail { get; set; }
    }

Step 3: Register class in startup.cs for DI purposes

services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));

Step 4: Create an Email sender interface

public interface IEmailSender
{
    Task SendEmailAsync(string email, string subject, string message);
}

Step 5: Create a message service class which will implement this interface

Inject EmailSettings class in message service using options pattern, so that email configuration defined in appsettings.json is available in this service.

We will use SmtpClient class to allow applications to send e-mail by using the Simple Mail Transfer Protocol (SMTP).

public class AuthMessageSender : IEmailSender, ISmsSender
    {
        public AuthMessageSender(IOptions<EmailSettings> emailSettings)
        {
            _emailSettings = emailSettings.Value;
        }

        public EmailSettings _emailSettings { get; }

        public Task SendEmailAsync(string email, string subject, string message)
        {

            Execute (email, subject, message).Wait();
            return Task.FromResult(0);
        }

        public async Task Execute(string email, string subject, string message)
        {
          try
          {
            string toEmail = string.IsNullOrEmpty(email) 
                             ? _emailSettings.ToEmail 
                             : email;
            MailMessage mail = new MailMessage()
            {
                From = new MailAddress(_emailSettings.UsernameEmail, "Muhammad Hassan Tariq")
            };
            mail.To.Add(new MailAddress(toEmail));
            mail.CC.Add(new MailAddress(_emailSettings.CcEmail));

            mail.Subject = "Personal Management System - " + subject;
            mail.Body = message;
            mail.IsBodyHtml = true;
            mail.Priority = MailPriority.High;

            using (SmtpClient smtp = new SmtpClient(_emailSettings.SecondayDomain, _emailSettings.SecondaryPort))
            {
                smtp.Credentials = new NetworkCredential(_emailSettings.UsernameEmail, _emailSettings.UsernamePassword);
                smtp.EnableSsl = true;
                await smtp.SendMailAsync(mail);
            }
          }
          catch(Exception ex)
          {
             //do something here
          }
        }
    }

*exception handling is left for you to implement 🙂

  • You can attach one or several files:
mail.Attachments.Add(new Attachment(Server.MapPath("~/myimage.jpg")));
  • You can send to more than one person at the same time
mail.To.Add("test@email.com");
mail.To.Add("test2@email.com");
  • You can set a name for the sender
mail.From = new MailAddress("test@email.com", "Hello");
  • You can send HTML e-mails, instead of the default plaintext mails
mail.IsBodyHtml = true;
mail.Body = "Testing <b>123!</b>";
  • You can use the CC and BCC fields
mail.CC.Add("test@email.com");
mail.Bcc.Add("test2@email.com");
  • You can set the priority of an e-mail
mail.Priority = MailPriority.High;

Step 6: Register email sender service in startup.cs, so that it can be injected in controllers

services.AddTransient<IEmailSender, AuthMessageSender>();

Step 7: Controller code (consumer)

Inject email sender service in controller constructor and then invoke SendEmailAsync method of it

public class TestController : Controller
    {
        private readonly IEmailSender _emailSender;

        public AccountController(IEmailSender emailSender)
        {
            _emailSender = emailSender;
        }
        
        public async Task TestAction()
        {
           await _emailSender.SendEmailAsync("test@gmail.com", "subject",
                        $"Enter email body here");
        }
    }

Note:

Google may block sign in attempts from some apps or devices that do not use modern security standards. Since these apps and devices are easier to break into, blocking them helps keep your account safer.

Please make sure, in Gmail settings of your account, enable access for less secure apps to avoid below error:

The SMTP server requires a secure connection or the client was not 
authenticated. The server response was: 5.5.1 Authentication Required?

ASP.NET Core: Display more detailed information about the error after publishing project on Azure

Standard

After deploying ASP.NET CORE project on Azure, I start getting bunch of 500 internal errors for webapi’s, I investigated the failures in chrome dev tool and couldn’t find any detailed information there.

screenshot_4

The html response from server was:

screenshot_3

Solution:

So in-order to check out actual exception, I added couple of line in web.config file of project

<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false">
      <environmentVariables>
        <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
      </environmentVariables>
    </aspNetCore>

Yo can also add ASPNETCORE_ENVIRONMENT variable as App settings in Application Settings section of WebApp in Azure Portal.

screenshot_5

ASP.NET Core: Register Angular2 routes with CORE MVC routes

Standard

In order to integrate your Angular2 routes within your ASP.NET application, register all angular2 routes as unified entity within Core MVC routes configuration.

Angular2 Routes:

import { NgModule } from '@angular/core';
import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { FooComponent } from './foo.component';
import { BarComponent } from './bar.component';

@NgModule({
    imports: [
        RouterModule.forRoot([
            {
                path: '',
                redirectTo: '/foo',
                pathMatch: 'full',
                data: { title: 'Dashboard' }
            },
            {
                path: 'foo',
                component: FooComponent,
                pathMatch: 'full',
                data: { title: 'Foo' }
            },
            {
                path: 'tweet',
                component: BarComponent,
                pathMatch: 'full',
                data: { title: 'Bar' }
            }
        ])
    ],
    exports: [
        RouterModule
    ]
})

export class AppRoutingModule { }

ASP.NET Core Startup.cs Routes:

public void Configure(IApplicationBuilder app)
        {
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");

                routes.MapRoute(
                    name: "foobar",
                    template: "{*url}",
                    defaults: new { controller = "Home", action = "Index" });
            });
        }

ASP.NET Core: Step by Step Guide to Access appsettings.json in web project and class library

Standard

In ASP.NET Core configuration API provides a way of configuring an app based on a list of name-value pairs that can be read at runtime from multiple sources.Its time to get over with web.config to store and access appSettings keys. Please note that class libraries don’t have an appsettings.json by default. The solution is simple to access appsettings.json key/value pairs in your project through Dependency Injection principle in ASP.NET Core. DI has been already part of Core framework, You just have to register your dependencies in startup.cs file under ConfigureService method.

My appsettings.json

{
  "ServiceSettings": {
    "NewsMainUrl": "https://newsapi.org",
    "NewsApiKey": "abc"
  },

  "BALSettings": {
    "Source": "xyz",
    "FilterTerms": "abc;def;"
  }
}

Step 1: Create Model/Entities classes that has properties that match the settings in a section in appsettings.json

Create a class for BALSettings

namespace Tweet.Entities
{
    public class BALSettings
    {
        public string Source { get; set; }
        public string FilterTerms { get; set; }
    }
}

Create a class for ServiceSettings

namespace Tweet.Entities
{
    public class ServiceSettings
    {
        public string NewsMainUrl { get; set; }
        public string NewsApiKey { get; set; }
    }
}

Please note that in case you want to access the section of appsettings.json in class library project, then create above entities class in separate class library project in order to avoid circular dependencies conflict between projects in one solution. There is strong chance your web project might be dependent on that class library project.

screenshot_2

Step 2: Register appsettings.json section with relevant model classes in DI container

You need to get the appsettings.json section and then bind it, It is done by populating relevant model classes and adding them to the IOptions collection in the DI container and then registering them in Configure() method of the Startup class of ASP.NET Core project

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
   services.Configure<BALSettings>(Configuration.GetSection("BALSettings"));
   services.Configure<ServiceSettings>(Configuration.GetSection("ServiceSettings"));
}

Step 3: Access appsettings.json section in MVC or WebAPI controller in ASP.NET Core Project

You can access that class from any method that the framework calls by adding it as a parameter in the constructor. The framework handles finding and providing the class to the constructor. Include Microsoft.Extension.Options in controller to work with IOption collection.

using Microsoft.Extensions.Options;

public class TestController: Controller
{  
    private readonly IOptions<BALSettings> _balSettings;
    private readonly IOptions<ServiceSettings> _serviceSettings; 

    public TestController(IOptions<BALSettings> balSettings,
                          IOptions<ServiceSettings> serviceSettings)
    {
        _balSettings = balSettings;
        _serviceSettings = serviceSettings;
    }
 
    public IActionResult About()         
    {
       ViewData["Source"] = _balSettings.Value.Source;
       ViewData["NewsMainUrl"] = _serviceSettings.Value.NewsMainUrl;
    }
}

 

Step 4: Access appsettings.json section in Class Library Project

Asp.Net Core DI resolve all dependencies before creating controller. As we have already registered our model classes which are containing relevant sections of appsettings.json in startup code.

I have a class library project and I am accessing appsettings.json section in it using below code.

screenshot_4

using Microsoft.Extensions.Options;

public class NewsService : INewsService
    {
        private readonly IOptions<ServiceSettings> _serviceSettings;

        public NewsService(IOptions<ServiceSettings> serviceSettings)
        {
            _serviceSettings = serviceSettings;
        }

        public string composeUrl()
        {
            return _serviceSettings.Value.NewsMainUrl + "&apiKey=" + _serviceSettings.Value.NewsApiKey;
        }
    }

 

Please Note:
If you wan to access appsettings.json key/value data in class library project then you have to add Microsoft.Extensions.Options from NUGET to your relevant class library project, otherwise IOptions collection wouldn’t be accessible to class library project.

Nuget package manager console command:

PM> Install-Package Microsoft.Extensions.Options 

or using nuget package manager

screenshot_5

ASP.NET Core: Error – InvalidOperationException Unable to resolve service for type foo while attempting to activate bar

Standard

DI is for objects that have complex dependencies. Controllers, services, adapters, and repositories are all examples of objects that might be added to DI. In order to implement Dependency Injection by constructor in ASP.NET core. We have to use DI Containers (Autofac, Ninject, StructureMap). I was working on side project in ASP.NET core, came across this particular issue relevant to DI.

An unhandled exception occurred while processing the request.  
InvalidOperationException: Unable to resolve service for type 'Tweet.BAL.INewsData'
while attempting to activate 'Tweet.Controllers.TweetController'.

screenshot_4

Solution:

Good news is that DI has been already part of Core framework, You just have to register your dependencies in startup.cs file under ConfigureService method.

services.AddTransient<IFoo, Foo>();
services.AddSingleton<IBar, Bar>();
services.AddScoped<IHello, Hello>();

The first generic type represents the type (typically an interface) that will be requested from the container. The second generic type represents the concrete type that will be instantiated by the container and used to fulfill such requests.

ASP.NET services can be configured with the following lifetimes:

Transient

Transient objects are always different; a new instance is provided to every controller and every service.

Scoped

Scoped objects are the same within a request, but different across different requests

Singleton

Singleton objects are the same for every object and every request (regardless of whether an instance is provided in ConfigureServices)

ASP.NET Core/MVC: Error – The name ‘angular’ does not exist in the current context on Compilation

Standard

In case you are integrating Angular2 and Angular Material 2 with your ASP.NET Core and ASP.NET MVC project, you might need to include css or js files explicitly in layout.cshtml.

screenshot_5

As you can see red squiggly line on @angular, simple reason is ‘@’ character is Razor server side symbol, so Razor View Engine is throwing up exception.

screenshot_4

Solution:

Declare @lib variable in razor view to handle @angular as part of value for href.

@{ var @lib= "@angular"; }

<environment names="Development">
   <link href="~/node_modules/@lib/material/core/theming/prebuilt/indigo-pink.css" />
</environment>

ASP.NET Core: Access node_modules folder inside ASP.NET Core Project

Standard

We are not supposed to access files from outside of wwwroot. The wwwroot folder is the public folder that’s accessible from outside, when you host it.

The typical publishing process is, that you have a gulp or grunt task that runs when your ASP.NET webproject is compiled or published, it would run the tasks there and copy over the necessary files inside wwwroot.

However In order to access node_module inside your ASP.NET Core project without involving Gulp tasks is to manually register node_modules folder inside Configure() method inside Startup.cs class

Include below namespaces inside Startup.cs class

using Microsoft.Extensions.FileProviders;
using System.IO;

Serve other folders by using app.UseStaticFiles.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    //rest of the code

    ServeFromDirectory(app, env, "node_modules");
    
    app.UseStaticFiles();

    //rest of the code
}

public void ServeFromDirectory(IApplicationBuilder app, IHostingEnvironment env, string path)
{
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.ContentRootPath, path)
        ),
        RequestPath = "/" + path
    });
}

ASP.NET CORE: Error – Unable to start debugging. The startup project could not be launched

Standard

If you receiving this error “Unable to start debugging. The startup project could not be launched. Verify debug settings for the startup project” on building your first CORE project inside Visual Studio. Plus you have already marked web project as startup project. Then you need to look into couple of solutions mentioned below.

screenshot_3

Solution 1:

Make sure you’re launching Visual Studio as Administrator.

  1. Right click on the Visual Studio 2015 Shortcut
  2. Select the Shortcut tab
  3. Click on Advanced
  4. Check the box to “Run as administrator” at all times

Solution 2:

Closed Visual Studio, reopened, and the project builds and runs normally. Simple Restart serves the need.