Check email count on mailbox with C#

Below is an example of .Net core 3.1 Console App that is reading a mailbox on Exchange and checking the count of mails. If the mail count cross a certain threshold, it’ll check for an e-mail older than 2 hours to send an alert.

Such an example can be used to schedule alerts or log information if you’re tracking mails in a mailbox.

Install Nuget package Microsoft.Exchange.WebServices to use ExchangeService class.

using Microsoft.Exchange.WebServices.Data;

public static void Main(string[] args)
{
	string TextlogMessage;
	string Subject = "";
	string sUsername = ConfigurationManager.AppSettings.Get("UserName");
	var section = ConfigurationManager.GetSection("secureAppSettings") as NameValueCollection;
	string vCount = ConfigurationManager.AppSettings.Get("Count");
	int Count = Convert.ToInt32(vCount);
	string sPassword = ConfigurationManager.AppSettings.Get("Password");
	
	string sDomain = ConfigurationManager.AppSettings.Get("Domain");
	TimeZoneInfo INDIAN_ZONE = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time");
	DateTime indianTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, INDIAN_ZONE);
	DateTime comparedate = indianTime.AddHours(-2);
	DateTime MailDateTime = comparedate;
	ExchangeService exchange = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
	exchange.Credentials = new WebCredentials(sUsername, sPassword, sDomain);
	
	exchange.Url = new Uri(ConfigurationManager.AppSettings.Get("ExchangeUrl"));
	Folder inbox = Folder.Bind(exchange, WellKnownFolderName.Inbox);
	var oSendemail = 0;
	TextlogMessage = "Start With count:" + inbox.TotalCount;




	if (inbox.TotalCount > Count)
	{

		Console.WriteLine("Count " + inbox.TotalCount);

		ItemView view = new ItemView(1);

		view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Ascending);
		
		var findResults = exchange.FindItems(WellKnownFolderName.Inbox, view);


		foreach (Item item in findResults.Items)
		{

			Console.WriteLine("Test: " + item.DateTimeReceived + " %" + comparedate);
			DateTime newdate = TimeZoneInfo.ConvertTimeToUtc(item.DateTimeReceived);

			int Dresult = DateTime.Compare(newdate, comparedate);
			if (Dresult < 0)
			{
				Console.WriteLine("Alert " + "Sub" + item.Subject + newdate + " %" + comparedate);
				oSendemail = 1;
				MailDateTime = newdate;
				Subject = item.Subject;


			}

		}
		if (oSendemail > 0)
		{
			Program p = new Program();
			//To Do Send Email Logic..
			p.SendEmail(exchange, oSendemail, inbox.TotalCount, TextlogMessage);
			TextlogMessage = TextlogMessage + " EmailTime: " + MailDateTime + "CompareTime " + comparedate + "  Alert Sent Subject : " + Subject;

		}

	}

	//To Do logging..
	log(TextlogMessage);

}

Call .Net core API from Console with App Bearer token

In the following example, we’re using a .Net Core 3.1 Console App that will call API with POST request that requires Authentication with a bearer token in Authrorization Header. The token is generated by passing credentials to another API endpoint.

For more details on how to use appSettings.json file in Console App, check this post.

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;

namespace ConsoleApp1
{

    class Credentials
    {
        public string username { get; set; }
        public string password { get; set; }
    }

    class Token
    {
        public string token { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string ResponseString = "";
            HttpWebResponse response = null;
            HttpWebResponse response2 = null;
            IConfiguration Config = new ConfigurationBuilder()
                .AddJsonFile("appSettings.json")
                .Build();

            try
            {
                var baseURL = Config.GetSection("baseURL").Value;
                var request = (HttpWebRequest)WebRequest.Create(baseURL + "/token");
                request.Accept = "application/json"; //"application/xml";
                request.Method = "POST";

		//Get credentials from config.
                var dusername = EncryptionService.Decrypt(Config.GetSection("credentials")["username"]);
                var dpassword = EncryptionService.Decrypt(Config.GetSection("credentials")["password"]);

                Credentials cred = new Credentials()
                {
                    username = dusername,
                    password = dpassword
                };

                var myContent = JsonConvert.SerializeObject(cred);

                var data = Encoding.ASCII.GetBytes(myContent);

                request.ContentType = "application/json";
                request.ContentLength = data.Length;

                using (var stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }

                using (response = (HttpWebResponse)request.GetResponse())
                {
                    ResponseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
                }

		//Get the token from the /token end-point and call another end-point.
                Token token = JsonConvert.DeserializeObject<Token>(ResponseString);

                var request2 = (HttpWebRequest)WebRequest.Create(baseURL + "/ProcessData");
                request2.Accept = "application/json"; //"application/xml";
                request2.Method = "POST";
				
		//Pass token in Authorization Header.
                request2.Headers["Authorization"] = "Bearer " + token.token;

                using (response2 = (HttpWebResponse)request2.GetResponse())
                {
                    ResponseString = new StreamReader(response2.GetResponseStream()).ReadToEnd();
                }

                Console.WriteLine(ResponseString);
                Environment.Exit(0);
            }
            catch (WebException ex)
            {
                if (ex.Status == WebExceptionStatus.ProtocolError)
                {
                    response = (HttpWebResponse)ex.Response;
                    ResponseString = "Some error occured: " + response.StatusCode.ToString();
                }
                else
                {
                    ResponseString = "Some error occured: " + ex.Status.ToString();
                }
            }

        }
    }

}

Use config file in .Net core Console App

For this example, I’m using a Console App created in .Net Core 3.1 using Visual Studio 2019.

Add a json file to your Project and name it appSettings.json, it could like like below:

{
  "credentials": {
    "username": "xxxx",
    "password": "xxxx"
  },
  "URL": "https://workdayapipoc.egonzehnder.com"
}

Install the following Nuget packages in your Project:

<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />

The versions could vary depending on the time you’re adding these packages.

In your Program.cs file, add the namespace:

using Microsoft.Extensions.Configuration;

In the Main method, add the following code:

class Program
{
    static void Main(string[] args)
    {
		//....
		
		IConfiguration Config = new ConfigurationBuilder()
                .AddJsonFile("appSettings.json")
                .Build();
				
		var URL = Config.GetSection("URL").Value;
		
		//Assuming you're using Encrypted values in configuration.
		var dusername = EncryptionClass.Decrypt(Config.GetSection("credentials")["username"]);
        var dpassword = EncryptionClass.Decrypt(Config.GetSection("credentials")["password"]);
		
		//.....
		
    }
}

Abstract Factory pattern C#

Let’s begin with a story of 2 brothers Bill and Steve. Both love Pizza and Ice Cream. They go to a Food Court which has Pizza outlets like Pizza Hut and Dominos Pizza and Ice Cream Parlours like Baskin Robbins and Mikey.

Taking this real world pattern into our Software design by creating classes. In this context, Food Court will be our FoodFactory abstract class that creates 2 abstract Products Pizza and Ice Cream. The Food Court has 2 sections Fun and Frolic. Bill goes for Fun and Steve goes to Frolic.

public abstract class FoodFactory
{
    public abstract Pizza BakePizza();
    public abstract IceCream MakeIceCream();
}

Create an Abstract Products folder and add the following 2 classes:

public class Pizza {

}

public class IceCream {

}

Create a Products Folder and add the following classes:

public class DominosPizza: Pizza
{
    public DominosPizza()
    {
    }
}
public class PizzaHut: Pizza
{
    public PizzaHut()
    {
    }
}
public class Mikey: IceCream
{
    public Mikey()
    {
    }
}
public class BaskinRobbins: IceCream
{
    public BaskinRobbins()
    {
    }
}

Now, suppose Fun section has Pizza Hut and Mikey and Frolic has Dominos Pizza and Baskin Robbins. Create a folder Factories and under that add the following classes:

class FunFoodFactory : FoodFactory
{
    public override Pizza BakePizza()
    {
        return new PizzaHut();
    }

    public override IceCream MakeIceCream()
    {
        return new Mikey();
    }
}
public class FrolicFoodFactory : FoodFactory
{
    public override Pizza BakePizza()
    {
        return new DominosPizza();
    }

    public override IceCream MakeIceCream()
    {
        return new BaskinRobbins();
    }
}

Now the 2 Good brothers start having fun. Create a class called GoodBrothers as below:

public class GoodBrothers
{
    private readonly Pizza _pizza;
    private readonly IceCream _icecream;

    public GoodBrothers(FoodFactory factory)
    {
        _pizza = factory.BakePizza();
        _icecream = factory.MakeIceCream();
    }

    public string WhatDidYouHaveToday()
    {
        return $"Today I ate at {_pizza.GetType().Name} and {_icecream.GetType().Name}";
    }
}

From the main class we ask them What did you have today?

class Program
{
    static void Main(string[] args)
    {
        GoodBrothers Bill = new GoodBrothers(new FunFoodFactory());
        Console.WriteLine($"Bill: {Bill.WhatDidYouHaveToday()}");

        GoodBrothers Steve = new GoodBrothers(new FrolicFoodFactory());
        Console.WriteLine($"Steve: {Steve.WhatDidYouHaveToday()}");

        Console.ReadKey();
    }
}

Output:

Bill: Today I ate at PizzaHut and Mikey
Steve: Today I ate at DominosPizza and BaskinRobbins

A similar example for Abstract Factory pattern can be for a Clothes Factory abstract class which creates abstract Products like Shirts and Trousers. A Businessman may buy from ElegantFactory and a student may buy from CasualFactory. Shirts can be of types Formal and PoloTs and Trousers can be of type Suit and Jeans.

The ElegantFactory will return types Formal Shirt and Suit Trousers. CasualFactory will return types PoloTs and Jeans. We can create a Client class like GoodBrothers that receives the ClothesFactory reference in it’s constructor to create a Shirt and Trouser for the Businessman and Student and so on.

Support pre-flight OPTIONS requests in .Net WebAPI

A way to support the ‘OPTIONS’ pre-flight request in .net WebAPI is to by-pass this request with a default response and returning the required Headers.

Add the below code in your Global.asax.cs file under the Application_BeginRequest method:

protected void Application_BeginRequest()
{
	if (Request.HttpMethod == "OPTIONS")
	{
		HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
		HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, expiry, id, token, token-type");
		HttpContext.Current.Response.AddHeader("Access-Control-Allow‌​-Credentials", "true");
		HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
		HttpContext.Current.Response.End();
	}
}

So when you call the WebAPI with Javscript fetch/axios, the pre-flight request sent before the actual request would get the 200 status code.

The example above shows some sample custom headers and allowed methods that will be returned in Response Headers.

Global Exception Handling and Logging in aspnet core webapi

Create a Model for your Error details as below:

public class ErrorDetails
{
	public int StatusCode { get; set; }
	public string Message { get; set; }


	public override string ToString()
	{
		return JsonConvert.SerializeObject(this); //JsonConvert is part of Newtonsoft.Json package.
	}
}

Create the Exception Factory which will handle Exceptions globally in your Api:

public static class ExceptionFactory
{ 
    public static void ConfigureExceptionHandler(this IApplicationBuilder app, int StatusCode = 0, string message = "")
    {
        app.UseExceptionHandler(appError =>
        {
            appError.Run(async context =>
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                context.Response.ContentType = "application/json";
                
                var contextFeature = context.Features.Get<IExceptionHandlerFeature>();
                if (contextFeature != null)
                {
                    LogTraceFactory.LogError($"Something went wrong: {contextFeature.Error}");

                    await context.Response.WriteAsync(new ErrorDetails()
                    {
                        StatusCode = context.Response.StatusCode,
                        Message = "Internal Server Error."
                    }.ToString());
                }
            });
        });
    }
}

Register Exception handling in your Api:

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
	if (env.IsDevelopment())
	{
		app.UseDeveloperExceptionPage();
	}
	app.ConfigureExceptionHandler();
	.....
}

Also, you can return the error details in your Action Controllers as below:

[HttpGet]
[Route("product/getproductdetails")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public IActionResult GetproductDetails([FromQuery]int productId)
{
	LeadsProduct lead = null;
	if (productId == 0)
	{
		LogTraceFactory.LogError($"Incorrect parameters, productId: {productId}");
		return BadRequest(new ErrorDetails { StatusCode = Convert.ToInt32(HttpStatusCode.BadRequest), Message = $"Missing parameters, productId: {productId} for product Leads." });
	}

	lead = leadService.FetchProductDetails(productId);

	if (lead == null)
	{
		LogTraceFactory.LogError($"product Leads Not Found for productId: {productId}");
		return NotFound(new ErrorDetails { StatusCode = Convert.ToInt32(HttpStatusCode.NotFound), Message = $"product Leads not found for productId {productId}." });
	}

	return Ok(lead);
}

The example above uses the nlog package in the .net core Web Api. You can create LogTraceFactory class as below:

public static class LogTraceFactory
{
	private static ILogger logger = LogManager.GetCurrentClassLogger();

	public static void LogDebug(string message)
	{
		logger.Debug(message);
	}

	public static void LogError(string message)
	{
		logger.Error(message);
	}

	public static void LogInfo(string message)
	{
		logger.Info(message);
	}

	public static void LogWarn(string message)
	{
		logger.Warn(message);
	}
}

Configure nlog package as below in the nlog.config file:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      internalLogLevel="Trace"
      internalLogFile="C:\internal_logs\internallog.txt">

  <targets>
    <target name="logfile" xsi:type="File"
            fileName="C:\ProjectLogs\${shortdate}_logfile.txt"
            layout="${longdate} ${level:uppercase=true} ${message}"/>
  </targets>

  <rules>
    <logger name="*" minlevel="Debug" writeTo="logfile" />
  </rules>
</nlog>

You can modify the above configuration as required. As part of the clean architecture, it is better to setup the ExceptionFactory and LogTraceFactory in the Common Layer of your Solution.


Omg! Now you can earn a six figure income. Click here to know how.

How to serialize data using translator C# .net core webapi

Suppose you’re trying to fetch user data from your database using ado.net in you .net core webapi. You have a SQLHelper class that calls a Stored Procedure and returns data that requires to be converted to a DTO object with pre-defined properties in C#.

The SQLHelper class will have the following method to call your Stored Procedure:

public static TData ExtecuteProcedureReturnData<TData>(string connString, string procName,
	Func<SqlDataReader, TData> translator,
	params SqlParameter[] parameters)
{
	using (var sqlConnection = new SqlConnection(connString))
	{
		using (var sqlCommand = sqlConnection.CreateCommand())
		{
			sqlCommand.CommandType = System.Data.CommandType.StoredProcedure;
			sqlCommand.CommandText = procName;
			if (parameters != null)
			{
				sqlCommand.Parameters.AddRange(parameters);
			}
			sqlConnection.Open();
			using (var reader = sqlCommand.ExecuteReader())
			{
				TData elements;
				try
				{
					elements = translator(reader);
				}
				finally
				{
					while (reader.NextResult())
					{ }
				}
				return elements;
			}
		}
	}
}

What is a Translator?

A translator is a class like a DTO in C# which will serialize your data returned from the Stored Procedure into it’s properties.
This will be returned as a json object by your WebApi to your Client front-end.

You can create a Translators folder in your .net core WebApi Project to have all such classes in one place.

An example Translator is as shown below:

public static class UserTranslator
{
	public static User TranslateAsUser(this SqlDataReader reader)
	{
		if (!reader.HasRows)
			return null;
		reader.Read();

		var item = new User();

		if (reader.IsColumnExists("Username"))
			item.Username = SqlHelper.GetNullableString(reader, "Username");

		if (reader.IsColumnExists("FullName"))
			item.FullName = SqlHelper.GetNullableString(reader, "FullName");
			
		if (reader.IsColumnExists("RoleName"))
                item.RoleName = SqlHelper.GetNullableString(reader, "RoleName");

		if (reader.IsColumnExists("Email"))
			item.Email = SqlHelper.GetNullableString(reader, "Email");

		return item;
	}
}

In the above example, you data will have the following columns as Username, FullName and Email. It only returns one row and not a list.

For returning a list:

public static List<User> TranslateAsUsersList(this SqlDataReader reader)
{
	var list = new List<User>();
	while (reader.Read())
	{
		list.Add(TranslateAsUser(reader, true));
	}
	return list;
}

Make sure your reader.Read() method is not called twice.

The DTO for user is as follows:

public class User
{
	public string Username { get; set; }
	public string FullName { get; set; }
	public string RoleName { get; set; }
	public string Email { get; set; }
}

Now, you need to call your Stored Procedure from your Repository:

public User getUserDetails(string UserName)
{
	string connString = CommonUtil.ConnectionString;
	SqlParameter[] param =
	{
		new SqlParameter("@Username", UserName)
	};

	User user = SqlHelper.ExtecuteProcedureReturnData<User>(
		connString,
		"GetUserDetailsFromDB",
		r => r.TranslateAsUser(), //call TranslateAsUsersList if List of Users is required and return List<User>
		param
		);

	return user;
}

Assuming, you’re using the Repository pattern in your WebApi Data Layer. Else, you can call the above method however your Project structure works.

I’ve written another post on multiple ways to fetch data for calling StoredProcedure in your WebApi for your SQLHelper class.

Write C# method that returns DataSet from Stored Procedure

Suppose you are writing a Helper class in your .Net Project that uses ADO.Net in the Data Layer. And you need to call Stored Procedures a lot. Writing a generic Helper method that takes in an Array of SqlParameters can be used so that you don’t have re-write the same code of calling the Stored Procedure again and again.

Below is the code that I’ve used as a general approach to call Stored Procedure and return DataSet:

public static DataSet ExecuteProcedureReturnDataSet(string connString, string procName,
            params SqlParameter[] paramters)
{
	DataSet result = null;
	using (var sqlConnection = new SqlConnection(connString))
	{
		using (var command = sqlConnection.CreateCommand())
		{
			using (SqlDataAdapter sda = new SqlDataAdapter(command))
			{
				command.CommandType = System.Data.CommandType.StoredProcedure;
				command.CommandText = procName;
				if (paramters != null)
				{
					command.Parameters.AddRange(paramters);
				}
				result = new DataSet();
				sda.Fill(result);
			}
		}
	}
	return result;
}

Another way to call Stored Procedure would be to return a single value from the Stored Procedure like a string. You can use the below method to return only a String:

public static string ExecuteProcedureReturnString(string connString, string procName,
            params SqlParameter[] paramters)
{
	string result = "";
	using (var sqlConnection = new SqlConnection(connString))
	{
		using (var command = sqlConnection.CreateCommand())
		{
			command.CommandType = System.Data.CommandType.StoredProcedure;
			command.CommandText = procName;
			if (paramters != null)
			{
				command.Parameters.AddRange(paramters);
			}
			sqlConnection.Open();
			var ret = command.ExecuteScalar();
			if (ret != null)
				result = Convert.ToString(ret);
		}
	}
	return result;
}

Example of SqlParameter array to be passed to the above methods can be as follows:

SqlParameter[] params =
{
	new SqlParameter("@name", name),
	new SqlParameter("@year", year)
};

Managing Custom Errors with Asp.net

You never want your users to see that yellow screen which shows up when a run-time or design-time error occurs in Asp.Net. However, a developer might want to see the error which may help in finding out the issue.

We have the following Custom error modes in Asp.net that can be set in web.config file:

  • Off: shows the actual error on the screen for all users.
  • On: shows only the custom error page and not the error details to all users.
  • RemoteOnly: shows the error details only to the local users where the Application is running. But does not show it to the outside users.

We recently faced a scenario where one of our Asp.Net Application was returning 3xx series status code from IIS Server for non-existent pages. This was flagged as a possible Security flaw by the team.
e.g. https://abc.com/xyz.aspx

So, if the page xyz.aspx does not exist, the Server will return 404 status code by default.

The following CustomErrors setting by default will give 404 status code:

<customErrors mode="Off" defaultRedirect="Error.htm"/>

We have used CustomErrors in our Web.config file which by the default behaviour of Asp.Net will make the IIS send the following response…
• With status code 302: Found, which effectively means a redirect
• Having a Location response header where the resource should be requested (in this case, the generic error page).
In the end, because the generic error page is static and does not change, when that is requested over same session IIS may return the response 304: Not modified.

Asp.Net CustomErrors setting in Web.Config file:

<customErrors mode="On" defaultRedirect="Error.htm"/>

The below setting produces the same result:

<customErrors mode="On" defaultRedirect="Error.htm">
    <error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>

Similarly, you can manage other status codes.

The default behaviour of Asp.Net returning 3xx series status codes is by design for redirect done by Custom Errors and could be a false Security alert.

Change Javascript attribute for asp.net textbox using c#

Suppose we have the following asp.net textbox in a UserControl with the onfocusout javascript method that passes validation as 50000 characters.

<telerik:RadTextBox TextMode="MultiLine" ID="txtComments" onfocusout="return CheckLength(this, 50000);" Height="100px"  runat="server" CssClass="TextMulti" Width="99%" EnableSingleInputRendering="False">
</telerik:RadTextBox>

For a particular scenario, you may need to change the number of characters to say 6000.

This can be done dynamincally in the UserControl C# code as below:

txtComments.Attributes["onfocusout"] = "return CheckLength(this, 6000);";