Tuesday, August 19, 2025

Send emails using SendGrid using C#

 public static bool SendMail(EmailDTO emailDTO, bool showOEEFooter, bool isSCECHSponsor = false)
        {
            try
            {
                var apiKey = Utility.GetAppSettingsValue(MOECSAppSettings.SENDGRID_APIKEY);
                var sendGridClient = new SendGridClient(apiKey);

                var mailMessage = new SendGridMessage();

                string fromAddress = Utility.GetAppSettingsValue(MOECSAppSettings.SENDGRID_FROM_ADDRESS);
                mailMessage.From = new EmailAddress(fromAddress, fromAddress);

                string environment = Utility.GetAppSettingsValue(MOECSAppSettings.ENVIRONMENT)?.ToLower();

                if (isSCECHSponsor)
                {
                    mailMessage.AddReplyTo(Utility.GetAppSettingsValue(MOECSAppSettings.SCECH_FROM_ADDRESS));
                }

                List<EmailAddress> toEmails;
                if (environment == ApplicationSettings.MOECS_PRODUCTION)
                {
                    mailMessage.AddTo(new EmailAddress(emailDTO.ToAddress));
                    mailMessage.Subject = emailDTO.Subject;

                    toEmails = new List<EmailAddress> { new EmailAddress(emailDTO.ToAddress) };
                }
                else
                {
                    string fallbackToAddress = Utility.GetAppSettingsValue(MOECSAppSettings.TO_ADDRESS);

                    var fallbackEmails = new List<EmailAddress>();
                    if (emailDTO.ToAddress.Contains(";"))
                    {
                        fallbackEmails = emailDTO.ToAddress.Split(';').Select(_ => new EmailAddress(fallbackToAddress)).ToList();
                    }
                    else if (emailDTO.ToAddress.Contains(","))
                    {
                        fallbackEmails = emailDTO.ToAddress.Split(',').Select(_ => new EmailAddress(fallbackToAddress)).ToList();
                    }
                    else
                    {
                        fallbackEmails.Add(new EmailAddress(fallbackToAddress));
                    }

                    mailMessage.AddTos(fallbackEmails);
                    mailMessage.Subject = $"{environment.ToUpper()} - {emailDTO.Subject}";

                    toEmails = fallbackEmails;
                }

                //string bcc = Utility.GetAppSettingsValue(MOECSAppSettings.BCC_ADDRESS)?.Trim();
                //if (!string.IsNullOrEmpty(bcc))
                //{
                //    mailMessage.AddBcc(new EmailAddress(bcc));
                //}

                var ccEmails = !string.IsNullOrEmpty(emailDTO.CCAddress)
                   ? emailDTO.CCAddress.Split(new[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries)
                   .Select(e => new EmailAddress(e.Trim())).ToList() : new List<EmailAddress>();

                var bccEmails = !string.IsNullOrEmpty(Utility.GetAppSettingsValue(MOECSAppSettings.BCC_ADDRESS))
                    ? Utility.GetAppSettingsValue(MOECSAppSettings.BCC_ADDRESS)
                    .Split(new[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries)
                    .Select(e => new EmailAddress(e.Trim())).ToList() : new List<EmailAddress>();

                ccEmails = ccEmails.Where(cc => !toEmails.Any(to => to.Email.Equals(cc.Email, StringComparison.OrdinalIgnoreCase))).ToList();

                bccEmails = bccEmails.Where(bcc => !toEmails.Any(to => to.Email.Equals(bcc.Email, StringComparison.OrdinalIgnoreCase)) &&
                                                   !ccEmails.Any(cc => cc.Email.Equals(bcc.Email, StringComparison.OrdinalIgnoreCase))).ToList();

                if (ccEmails.Any())
                {
                    mailMessage.AddCcs(ccEmails);
                }

                if (bccEmails.Any())
                {
                    mailMessage.AddBccs(bccEmails);
                }

                string bodyContent = formatMessage(emailDTO.FullName, emailDTO.Body, showOEEFooter, emailDTO.TemplateID, isSCECHSponsor);
                mailMessage.PlainTextContent = bodyContent;
                mailMessage.HtmlContent = bodyContent;

                if (emailDTO.Attachment != null)
                {
                    using (var memoryStream = new MemoryStream())
                    {
                        emailDTO.Attachment.CopyTo(memoryStream);
                        byte[] fileBytes = memoryStream.ToArray();
                        string base64File = Convert.ToBase64String(fileBytes);

                        mailMessage.AddAttachment(new Attachment
                        {
                            Content = base64File,
                            Filename = emailDTO.AttachmentFileName,
                            Type = MediaTypeNames.Application.Octet,
                            Disposition = "attachment"
                        });
                    }
                }

                var response = sendGridClient.SendEmailAsync(mailMessage).GetAwaiter().GetResult();

                if (!response.IsSuccessStatusCode)
                {
                    string errorBody = response.Body.ReadAsStringAsync().GetAwaiter().GetResult();
                    LoggerUtility.WriteLog($"SendGrid Error: {response.StatusCode} - {errorBody}", System.Diagnostics.TraceEventType.Error);
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                LoggerUtility.WriteLog($"Exception: {ex.Message}", System.Diagnostics.TraceEventType.Error);
                return false;
            }
        }


  public static bool SendMail(EmailDTO emailDTO)
        {
            return SendMail(emailDTO, true);
        }

  private static string formatMessage(string fullName, string messageBody, bool showOEEFooter, int templateID, bool isSCECHSponsor)
        {
            string content = string.Empty;
            TextInfo txtInfo = new CultureInfo("en-US", false).TextInfo;

            string footer = string.Empty;

            if (showOEEFooter == true)
            {
                footer = CacheUtil.GetMessageDescription(MOECSMessage.OEE_ADDRESS_CONTACT_HTML);
            }

            if (isSCECHSponsor)
            {
                footer = CacheUtil.GetMessageDescription(MOECSMessage.SCECH_EMAIL_FOOTER);
            }
            else
            {
                //attach no reply message to the footer
                footer = footer + CacheUtil.GetMessageDescription(MOECSMessage.NOREPLY_EMAIL_FOOTER);
            }

            if (templateID > 0)
            {
                footer = footer + "<br/><br/>EmailID: " + templateID;
            }

            if (!string.IsNullOrEmpty(fullName))
            { content = string.Format("Dear {0}<br/><br/>{1}", txtInfo.ToTitleCase(fullName.ToLower()+":"), messageBody); }
            else
            { content = messageBody; }

            content = string.Format("{0} {1}", content, footer);

            return content;
        }

 public static string GetAppSettingsValue(String key)
        {
            return ConfigurationManager.AppSettings.Get(key);
        }

Saturday, January 6, 2024

Query to get the Employee name and their Manager name from the same table in SQL Server

Query to get the Employee name and their manager's name from the same table in SQL Server
 
Below is Employee Table 

SELECT e.employeename, m.employeename AS ManagerName FROM Employee e JOIN Employee m ON e.ManagerId = m.EmployeeId 





Tuesday, December 13, 2022

Angular - ng.ps1 cannot be loaded because running scripts is disabled on this system. ng server is not working, ng is not recognized.

 ng server is not working (ng is not recognized):


If ng serve is not recognized or not worked in out angular application we will get below error message in Terminal window.

Execute below command in Terminal.

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted


Thursday, December 1, 2022

How to move item in an array to last position in javascript.

const arrayList = ['1', '2', '3', '5', '0'];
const moveThreeToEnd = (arrayList) => {
return arrayList.filter(item => item !== '3').concat(arrayList.filter(item => item === '3'))

}

console.log(array list); //['1', '2', '3', '5', '0' ];
console.log(moveThreeToEnd(array list)); // ['1', '2', '5', '0', '3'];

Monday, January 24, 2022

How to disable mat text box filed in angular

 How to disable mat form filed in angular.


isDisableField: boolean = true;

In html need add [readonly] = "isDisableField"

in CSS: 

.disable-field {

pointer-events: none;

.mat-form-field-flex {
background--color: gray;
}
.mat-form-field-outline {
display : none;
}

}

Get Local Date format without time in angular.

Get Local Date format without time in angular. 


getLocalDateWithOutTime(dateValue: string | Date): string {
        const localDateTime = dateValue instanceof Date ? dateValue : new Date(dateValue);
        const dateString = localDateTime.getFullYear() + '-' +
            (localDateTime.getMonth() > 8 ? localDateTime.getMonth() + 1 :
             '0' + (localDateTime.getMonth() + 1)) + '-' +
            (localDateTime.getDate() > 9 ? localDateTime.getDate() :
             '0' + localDateTime.getDate());
        return dateString;
    }



Thursday, January 6, 2022

How to group an array of objects through a key using reduce in angular

How reduce works


Lets see an usual example of array reduce,



// Person array with name and Age
const person = [
  {
    name: 'Jim',
    color: 'blue',
    age: 22,
  },
  {
    name: 'Sam',
    color: 'blue',
    age: 33,
  },
  {
    name: 'Eddie',
    color: 'green',
    age: 77,
  },
];

// Add their sum of ages
const sumOfAges = person.reduce((sum, currentValue) => {
  return sum + currentValue.age;
}, 0);

console.log(sumOfAges); // 132


  • reduce accept initial value, here in our sum of ages, we pass 0 as the initial value
  • reduce iterate over each value and add the sum each time with their previous sum value. Thus we return the sum at each step and that sum get added with the next age value.
  • the final sum value will be returned at the end of iteration.

  // Accepts the array and key
const groupBy = (array, key) => {
  // Return the end result
  return array.reduce((result, currentValue) => {
    // If an array already present for key, push it to the array. Else create an array and push the object
    (result[currentValue[key]] = result[currentValue[key]] || []).push(
      currentValue
    );
    // Return the current iteration `result` value, this will be taken as next iteration `result` value and accumulate
    return result;
  }, {}); // empty object is the initial value for result object
};

// Group by color as key to the person array
const personGroupedByColor = groupBy(person, 'color');


How to groupBy using reduce in Javascript

For the person array, lets group the objects using the color value. In our object, there are two blue color object and one green color object.

Steps to create the groupBy function,

  • create an object as initial value for our result object
  • inside the array reduce, create an array for each distinct key value and push the currentValue if the key value present in the currentValue
// this step of code can be restructured to multiple lines, see below for the multi line code
(result[currentValue[key]] = result[currentValue[key]] || []).push(
  currentValue
);

// This is how the above code in multiple line
if (!result[currentValue[key]]) {
  result[currentValue[key]] = [];
}
result[currentValue[key]].push(currentValue);

the end result after grouping will look like this,

{
  "blue": [
    {
      "name": "Jim",
      "color": "blue",
      "age": 22
    },
    {
      "name": "Sam",
      "color": "blue",
      "age": 33
    }
  ],
  "green": [
    {
      "name": "Eddie",
      "color": "green",
      "age": 77
    }
  ]
}

Reference:
https://learnwithparam.com/blog/how-to-group-by-array-of-objects-using-a-key/


Wednesday, August 19, 2020

What is COALESCE(), IFNULL, ISNULL in sql server ?

 

SQL Server COALESCE() Function


Return the first non-null value in a list:

SELECT COALESCE(NULL, NULL, NULL, 'Vijay', NULL, 'Kumar');

Output : Vijay.

MySQL COALESCE vs. IFNULL

The IFNULL function takes two arguments and returns the first argument if it is not NULL, otherwise, it returns the second argument.

The IFNULL function works great with two arguments whereas the COALESCE function works with n arguments. In case the number of arguments is two, both functions are the same.

P_IdProductNameUnitPriceUnitsInStockUnitsOnOrder
1Jarlsberg10.451615
2Mascarpone32.5623 
3Gorgonzola15.67920

Suppose that the "UnitsOnOrder" column is optional, and may contain NULL values.

Look at the following SELECT statement:

SELECT ProductName, UnitPrice * (UnitsInStock + UnitsOnOrder)
FROM Products;

In the example above, if any of the "UnitsOnOrder" values are NULL, the result will be NULL.


Solutions

MySQL

The MySQL IFNULL() function lets you return an alternative value if an expression is NULL:

SELECT ProductName, UnitPrice * (UnitsInStock + IFNULL(UnitsOnOrder, 0))
FROM Products;

or we can use the COALESCE() function, like this:

SELECT ProductName, UnitPrice * (UnitsInStock + COALESCE(UnitsOnOrder, 0))
FROM Products;

SQL Server

The SQL Server ISNULL() function lets you return an alternative value when an expression is NULL:

SELECT ProductName, UnitPrice * (UnitsInStock + ISNULL(UnitsOnOrder, 0))
FROM Products;




Sunday, August 16, 2020

Tree Shakeable and Tree Shakeable providers in Angular

Tree Shakeable:

Angular version 6 introduced a new feature, Tree Shakeable Providers. Tree Shakeable Providers are a way to define services and other things to be used by Angular’s dependency injection system in a way that can improve the performance of an Angular application.

First, let’s define tree shaking before we dig too deep. Tree shaking is a step in a build process that removes unused code from a code base. Removing unused code can be thought as “tree shaking,” or you can visualize the physical shaking of a tree and the remaining dead leaves falling off of the tree. By using tree shaking, we can make sure our application only includes the code that is needed for our application to run.

For example, say we have a utility library that has functions a(), b() and c(). In our app we import and use function a() and c() but do not use b(). We would expect that the code for b() to not be bundled and deployed to our users. Tree shaking is the mechanism to remove function b() from our deployed production code we send to our user’s browsers.

Why were Services in Angular not tree shakable already? Well, it comes back to how we registered Service in prior versions of Angular. Let’s look at an example of how we would have registered a Service in previous Angular versions to be used for dependency injection.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { SharedService } from './shared.service';

@NgModule({
  imports: [BrowserModule, FormsModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  providers: [SharedService]
})
export class AppModule {}

As you can see we import the Service and add it to our Angular AppModule. This registers the Service to Angular’s Dependency Injection system. Whenever a component requests to use this service, Angular’s DI will make sure that Service and any of its dependencies are created and passed onto the component’s constructor. The issue with this registration system is it is challenging for the build tools and compilers to determine if this code is used in our application.

One of the primary ways a tree shaking system removes code is looking at the import paths we define. If a class or function is not imported it is not included in the production code bundles we ship to our users. If it’s imported, the tree shaker assumes that it is being used in the application. In our example above we are importing and referencing our Service in the AppModule causing an explicit dependency that cannot be tree shaken.

Angular Tree Shaking Providers

With Tree Shaking Providers (TSP) we can use a different mechanism to register our services. Using this new TSP mechanism will provide the benefits of both tree shaking performance and dependency injection. We have a demo application with specific code to demonstrate the different performance characteristics of how we register these services. Let’s take a look at what the new TSP syntax looks like.

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class SharedService {
  constructor() {}
}

In the @Injectable decorator we have a new property called providedIn. With this property we can tell Angular which module to register our service to instead of having to import the module and register it to the providers of a NgModule. By default, this syntax registers it to the root injector which will make our service an application wide singleton. The root provider is a reasonable default for most use cases. If you still need to control the number of instance of a Service the regular providers API is still available on Angular Modules and Components.

With this new API, you can see since we did not have to import the service into a NgModule for registration that we did not make an explicit dependency. Because there is no import statement, the build tools can ensure that this service is only bundled in our application if a component uses it. Let’s take a look at an example application.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
import { Shared3Service } from './shared3.service';

@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    RouterModule.forRoot([
      { path: '', component: HelloComponent },
      {
        path: 'feature-1',
        loadChildren: () => import('./feature-1/feature-1.module').then(m => m.Feature1Module)
      },
      {
        path: 'feature-2',
        loadChildren: () => import('./feature-2/feature-2.module').then(m => m.Feature2Module) }
      }
    ])
  ],
  declarations: [AppComponent, HelloComponent],
  bootstrap: [AppComponent],
  providers: [Shared3Service]
})
export class AppModule {}

In this example app, we have three components; two are lazily loaded modules while one is our landing home component. We also have three different services we will use in the application. Let’s start with the first service and see how it is used.

import { Injectable } from '@angular/core';

console.log('SharedService bundled because two components use it');

@Injectable({
  providedIn: 'root'
})
export class SharedService {
  constructor() {
    console.log('SharedService instantiated');
  }
}

Our first service uses the tree shakable providers API. We import this service twice once in each of our lazy loaded feature modules like below.

import { Component, OnInit } from '@angular/core';
import { SharedService } from './../shared.service';

@Component({
  selector: 'app-feature-1',
  templateUrl: './feature-1.component.html',
  styleUrls: ['./feature-1.component.css']
})
export class Feature1Component implements OnInit {
  constructor(private sharedService: SharedService) {}
  ngOnInit() {}
}

Because Service 1 is used in both of our components, the code is loaded and bundled into our app. If we inspect the console we see the following message:

SharedService bundled because two components use it

Our second service in our application Service 2 looks like this:

import { Injectable } from '@angular/core';

console.log('Shared2Service is not bundled because it not used');

@Injectable({
  providedIn: 'root'
})
export class Shared2Service {
  constructor() {}
}

If we inspect the console, we do not see the log message. That is because this service is not used in either of our feature modules or components. Since it’s not used the code is not bundled and loaded.

Lastly our third service similar to the previous two looks like the following:

import { Injectable } from '@angular/core';

console.log('Shared3Service bundled even though not used');

@Injectable()
export class Shared3Service {
  constructor() {}
}

If we look at the console we see the following message:

Shared3Service bundled even though not used

Because Shared3Service is registered with the older providers API, it creates an explicit dependency because of the import statement needed to register. The import statement causes the build system to include and load this code even though no component uses it.

Between these three services, we can see the characteristics of how the tree shaking systems include or remove code in our applications. With the TSP API, our services are still singletons even for services used in lazily loaded modules like in our example. If we load our example app, we will notice that if we route between feature one and feature two the console log in the SharedService is only called once. Once a module is requested Angular will instantiate and ensure that instance is used for the rest of the life of the application.

Angular Tree Shakeable Providers give us better performance in our applications as well as reducing the amount of boilerplate code needed to create injectable services. Check out the full working demo application in the link below!


Happy Coding.. 

Below link is for view code demo.

https://stackblitz.com/edit/angular-mgba8n


References:

1. https://coryrylan.com/blog/tree-shakeable-providers-and-services-in-angular#:~:text=Angular%20version%206%20introduced%20a,before%20we%20dig%20too%20deep.