Using iText7 to Generate Pdf in Asp.net Core

iText7 is a powerful library to create customized pdfs. In this article, we will discuss generating pdf using some of the cool features of this library. The main advantage of itext7 is that, it gives fine grain control in the pdf document creation and lot of customization options.

Note: The main idea of this post is to make you familiar with the different usage scenarios of the iText7, so we will not discuss much on the dot net core project creation and solution structure. In this solution, we are using the Dependency injection concept, so you are assumed to be familiar with those concepts in advance.

We have created a simple web api project in dot net core. Below are the classes and objects used in the project to demonstrate pdf generation.

  • Service Method class (PdfGenerateService.cs)
  • Utility Class (Utility.cs)
  • FileDownload DTO (FileDownloadDto.cs)

Prerequisite:

We have to add itext7 package from Nuget

Once the package is added we can see it below in the packages section.

In the service class, we have added three methods for various types of customization.

//Customize a text cell
private static Cell CreateTextCellCustom(
        string text,
        TextAlignment textAlignment,
        VerticalAlignment cellVerticalAlignment,
        float fontsize,
        Color fontColor,
        PdfFont fontType,
        bool isBold = false,
        bool isCellBorder = false,
        bool isCellBackgroundColor = false,
        int rowSpan = 0,
        int colSpan = 0,
        float commonCellPadding = 0,
        float multipliedLeading = 1)
        {

            Cell cell = new Cell(rowSpan, colSpan);
            Paragraph p = new Paragraph();
            p.SetTextAlignment(textAlignment);

            p.Add(new Text(text).SetFont(fontType));
            p.SetFontColor(fontColor).SetFontSize(fontsize);
            p.SetMultipliedLeading(multipliedLeading);
            if (isBold)
                p.SetBold();
            cell.Add(p).SetVerticalAlignment(cellVerticalAlignment).SetPadding(commonCellPadding);
            if (!isCellBorder)
                cell.SetBorder(Border.NO_BORDER);
            if (isCellBackgroundColor)
            {
                Color customColor = new DeviceRgb(221, 235, 247);
                cell.SetBackgroundColor(customColor);
            }
            return cell;
        }

//Cutomize an image cell
private static Cell CreateImageCell(
        string path,
        VerticalAlignment cellVerticalAlignment,
        int rowSpan = 0,
        int colSpan = 0,
        float percentageImageWidth = 100)
        {
            Image img = new Image(ImageDataFactory.Create(path));
            img.SetWidth(UnitValue.CreatePercentValue(percentageImageWidth));
            Cell cell = new Cell(rowSpan, colSpan).Add(img).SetVerticalAlignment(cellVerticalAlignment);
            cell.SetBorder(Border.NO_BORDER);
            return cell;
        }

//Customize an empty cell
  public static Cell FormattedEmptyCell(
        Color cellBackgroudColor,
        Color cellBorderColor,
        float cellBorderWidth = 0.6f,
        int rowSpan = 0,
        int colSpan = 0,
        float opacity = 1f)
        {

            Cell cellFirst = new Cell(rowSpan, colSpan);
            cellFirst.SetBorder(Border.NO_BORDER);
            cellFirst.SetBorderLeft(new SolidBorder(cellBorderColor, cellBorderWidth));
            cellFirst.SetBorderBottom(new SolidBorder(cellBorderColor, cellBorderWidth));
            cellFirst.SetBorderTop(new SolidBorder(cellBorderColor, cellBorderWidth));
            cellFirst.SetBorderRight(new SolidBorder(cellBorderColor, cellBorderWidth));
            cellFirst.SetBackgroundColor(cellBackgroudColor, opacity);
            return cellFirst;
        }

 

Let us discuss different customizations:

  1. Usage of rowspan and colspan
    This is similar to rowspan and colspan concept in HTML tables, the way we do it is based on the rows or columns values pass as parameters to the method when creating a cell.
       Cell cell = new Cell(rowSpan, colSpan);
  2. Using an image inside a cell
    In the createImageCell method, we add functionality to add an image to a cell. We have to pass the file path and cell customization values including rowspan, collspan, vertical alignment, and border to the method. The image width percentage is at default 100 and we have the option to resize as well.
    Image img = new Image(ImageDataFactory.Create(path));
                img.SetWidth(UnitValue.CreatePercentValue(percentageImageWidth));
                Cell cell = new Cell(rowSpan, colSpan).Add(img).SetVerticalAlignment(cellVerticalAlignment);
                cell.SetBorder(Border.NO_BORDER);
                return cell;
  3. Using Background Image on Page
    Here we use the image path, fixed positioning to locate the image, and absolute positioning to resize the image on the document.
     Image imagebackground = new Image(ImageDataFactory.Create(BACKGROUNDIMGPATH));
                imagebackground.SetFixedPosition(1, 0, 60);
                imagebackground.ScaleAbsolute(530, 600);
                doc.Add(imagebackground);
  4. Adding Background Color and Opacity to Cell
    For this, we define a color object using DeviceRgb color values and assign it to the SetBackgroundColor property of the cell. Opacity is optional property so, if we want the cell to be transparent we have to specify a value less than 1 in the opacity field.
    Cell cell = new Cell(rowSpan, colSpan);
    Color customColor = new DeviceRgb(221, 235, 247);
    cell.SetBackgroundColor(customColor);
    //if opacity needed
    cell.SetBackgroundColor(customColor, opacity);
  5. Adding Border Color to Cell
    Here we set no border to the cell initially and then customize each edge of the cell using border color and width. 
    Cell cellFirst = new Cell(rowSpan, colSpan);
    cellFirst.SetBorder(Border.NO_BORDER);
    cellFirst.SetBorderLeft(new SolidBorder(cellBorderColor, cellBorderWidth));
    cellFirst.SetBorderBottom(new SolidBorder(cellBorderColor, cellBorderWidth));
    cellFirst.SetBorderTop(new SolidBorder(cellBorderColor, cellBorderWidth));
    cellFirst.SetBorderRight(new SolidBorder(cellBorderColor, cellBorderWidth));
    Cell Border Color is the Color object we discussed above and cell border width unit is in float ( float cellBorderWidth = 0.6f)

  6. Adding page border using PdfCanvas
    We use the stroke property to draw lines. Firstly we identify the page to draw using the page number, then we find the page size from the document and define a shape, here we use the rectangle object to draw a page border. Then we allocate some offset from the edge of the page to the rectangle object. Finally, we provide the above properties to Pdf  Canvas and draw rectangle border using a stroke.
    PdfPage page = pdfDoc.GetPage(1);
    float width = pdfDoc.GetDefaultPageSize().GetWidth();
    float height = pdfDoc.GetDefaultPageSize().GetHeight();
    Rectangle pageRect = new Rectangle(20, 20, width - 40, height - 40);
    new PdfCanvas(page).SetStrokeColor(CELL_BORDER_COLOR).SetLineWidth(0.6f).Rectangle(pageRect).Stroke(); 
    
  7. Formating text inside a cell
    We use Paragraph objects for text display, so in the method, we have provided text alignment, font color, font type, font size, bold, and line height  options for formatting. Multiplied leading is used to calculate line-height based on font of text.1 is the default height of font and if we need to reduce or increase we have to specify the value accordingly for multipliedLeading property.
     Cell cell = new Cell(rowSpan, colSpan);
                Paragraph p = new Paragraph();
                p.SetTextAlignment(textAlignment);
                p.Add(new Text(text).SetFont(fontType));
                p.SetFontColor(fontColor).SetFontSize(fontsize);
                p.SetMultipliedLeading(multipliedLeading);           
                p.SetBold();
  8. Formatting cell contents
    We can vertically align the contents of cell and provide padding using below options.
    Cell cell = new Cell(rowSpan, colSpan);
         Paragraph p = new Paragraph();            
         p.Add(new Text(text).SetFont(fontType));           
         cell.Add(p).SetVerticalAlignment(cellVerticalAlignment).SetPadding(commonCellPadding);
  9. Adding line break or Empty line
    We use paragraph objects to add an empty line to the pdf document as mentioned below.
     doc.Add(new Paragraph());
  10. Importing Custom Font 
    We can use font files like (.ttf,.woff) to use custom font in pdf generation. then using pdf font factory we create a pdffont object from font file path. Afterwards use custom font in the text property to display.
    public static readonly string CUSTOM_FONT_URL = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "assets", "StarellaTattoo.ttf");
    var CUSTOM_FONT = PdfFontFactory.CreateFont(FontProgramFactory.CreateFont(CUSTOM_FONT_URL), PdfEncodings.WINANSI,
                                             PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);
         Paragraph p = new Paragraph();            
         p.Add(new Text(text).SetFont(CUSTOM_FONT)); 
  11. Using Datatable to populate Data
    Here we use two for populating datable header columns and respectively rows. The table has a percentage array that defines the width of each column, this array count should be the same as the of column count in datatable.
    int noOfColumns = dataTable.Columns.Count;
    int fixedColumnWidthPercentage = 2;
    var percentageArray = Enumerable.Repeat<float>(fixedColumnWidthPercentage, noOfColumns).ToArray();
    
    Table table = new Table(UnitValue.CreatePercentArray(percentageArray)).UseAllAvailableWidth();
    //Adding column headers
    foreach (DataColumn dataColumn in dataTable.Columns)
    {
        table.AddCell(CreateTextCellCustom(dataColumn.ColumnName, TextAlignment.LEFT, VerticalAlignment.BOTTOM, 8, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, true, true, true, commonCellPadding: 5));
    }
    //Adding data in each cell.
    foreach (DataRow dataRow in dataTable.Rows)
    {
        foreach (DataColumn dataColumn in dataTable.Columns)
        {
              table.AddCell(CreateTextCellCustom(dataRow[dataColumn.ColumnName].ToString(), TextAlignment.LEFT, VerticalAlignment.BOTTOM, 8, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, false, true, commonCellPadding: 5));
         }
    }
  12. Using ByteArrayOutputStream 
    The main purpose of using ByteArrayOutputStream is that it helps to implement an outputstream in which data is written into a byte array,  the buffer automatically increases as we write data.
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    PdfDocument pdfDoc = new PdfDocument(new PdfWriter(baos));
    
    //rest of pdf generation logic
    
    resultFile.Attachment = baos.ToArray();


  13. Generating response in File format
    In the pdf generation service, we use FileDownloadDto to transfer byte array data to the controller. It also has other fields like MimeType and Filename which are used to provide a file response.
    FileDownloadDto resultFile = new FileDownloadDto
    {
       MimeType = "application/pdf"
    };
    //rest of pdf generation logic
    resultFile.Attachment = baos.ToArray();
    resultFile.FileName = string.Format("Test_Data_PDF_{0}.pdf", System.DateTime.Now.ToString("yyyyMMddHHmmssffff"));
    return Task.FromResult(resultFile);
    
    //controller method give file response
    public async Task<IActionResult> GeneratePdf()
    {            
      var result = await _pdfGenerateService.GeneratePdf(Utility.GenerateDatatableWithData(4,3));
      return File(result.Attachment, result.MimeType, result.FileName);               
    }

The full code inside PdfGenerateService class is as below. All the functionalities we have discussed above have been used in the service class. The generated sample pdf can be seen here Sample Pdf.

public class PdfGenerateService : IPdfGenerateService
    {

        private static Color DEFAULT_FONT_COLOR = new DeviceRgb(0, 0, 0);
        private static Color CELL_BORDER_COLOR = new DeviceRgb(215, 222, 232);
        private static Color CELL_BACKGROUND_COLOR = new DeviceRgb(238, 232, 213);
        private PdfFont DEFAULT_FONT_TYPE;
        public static readonly string LOGOIMGPATH = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "assets", "logo.jpg");
        public static readonly string BACKGROUNDIMGPATH = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "assets", "background.png");
        public static readonly string CUSTOM_FONT_URL = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "assets", "StarellaTattoo.ttf");
       
        
        public Task<FileDownloadDto> GeneratePdf(DataTable dataTable)
        {
            DEFAULT_FONT_TYPE = PdfFontFactory.CreateFont(StandardFonts.HELVETICA);
            var CUSTOM_FONT = PdfFontFactory.CreateFont(FontProgramFactory.CreateFont(CUSTOM_FONT_URL), PdfEncodings.WINANSI,
                                         PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);

            FileDownloadDto resultFile = new FileDownloadDto
            {
                MimeType = "application/pdf"
            };
            int noOfColumns = dataTable.Columns.Count;
            int fixedColumnWidthPercentage = 2;

            var percentageArray = Enumerable.Repeat<float>(fixedColumnWidthPercentage, noOfColumns).ToArray();



            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(baos));
            Document doc = new Document(pdfDoc);

            //code to add background Image
            Image imagebackground = new Image(ImageDataFactory.Create(BACKGROUNDIMGPATH));
            imagebackground.SetFixedPosition(1, 0, 60);
            imagebackground.ScaleAbsolute(530, 600);
            doc.Add(imagebackground);

            //define the table and columns for header 
            Table headerTable = new Table(UnitValue.CreatePercentArray(new float[] { 2, 3, 2 })).UseAllAvailableWidth();

            //adding logo Title and other fields in head section
            headerTable.AddCell(CreateImageCell(LOGOIMGPATH, VerticalAlignment.BOTTOM, 4, 0, 50));
            headerTable.AddCell(CreateTextCellCustom("Main Title with rowspan", TextAlignment.CENTER, VerticalAlignment.BOTTOM, 10, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, isBold: true, isCellBorder: false, isCellBackgroundColor: false, rowSpan: 4));
            headerTable.AddCell(CreateTextCellCustom($"Date :{System.DateTime.Today.ToString("dd-MMM-yyyy")}", TextAlignment.LEFT, VerticalAlignment.BOTTOM, 8, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, multipliedLeading: 1.5f));
            headerTable.AddCell(CreateTextCellCustom($"Time : {System.DateTime.Now.ToString("HH:mm")}", TextAlignment.LEFT, VerticalAlignment.BOTTOM, 8, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, multipliedLeading: 1.5f));
            headerTable.AddCell(CreateTextCellCustom("Report generated by : UserName", TextAlignment.LEFT, VerticalAlignment.BOTTOM, 8, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, multipliedLeading: 1.5f));
            doc.Add(headerTable);

            //define table columns for the data
            Table table = new Table(UnitValue.CreatePercentArray(percentageArray)).UseAllAvailableWidth();

            table.AddCell(CreateTextCellCustom("Sub title with colspan", TextAlignment.CENTER, VerticalAlignment.BOTTOM, 9, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, true, false, false, 0, 7, 5, 2f));
            //Adding column headers
            foreach (DataColumn dataColumn in dataTable.Columns)
            {
                table.AddCell(CreateTextCellCustom(dataColumn.ColumnName, TextAlignment.LEFT, VerticalAlignment.BOTTOM, 8, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, true, true, true, commonCellPadding: 5));
            }

            //Adding data in each cell.
            foreach (DataRow dataRow in dataTable.Rows)
            {
                foreach (DataColumn dataColumn in dataTable.Columns)
                {
                    table.AddCell(CreateTextCellCustom(dataRow[dataColumn.ColumnName].ToString(), TextAlignment.LEFT, VerticalAlignment.BOTTOM, 8, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, false, true, commonCellPadding: 5));
                }
            }

            doc.Add(table);
            doc.Add(new Paragraph());
            doc.Add(new Paragraph());
            doc.Add(new Paragraph());


            Table tableNext = new Table(UnitValue.CreatePercentArray(new float[] { 10 }));
            tableNext.SetWidth(UnitValue.CreatePercentValue(100));
            tableNext.SetFixedLayout();

            tableNext.AddCell(CreateTextCellCustom("Sub title with Custom Font", TextAlignment.CENTER, VerticalAlignment.BOTTOM, 20, DEFAULT_FONT_COLOR, CUSTOM_FONT, true, false, false, 0, 0, 5,2f));
            Cell mainCell = FormattedEmptyCell(CELL_BACKGROUND_COLOR, CELL_BORDER_COLOR,opacity:0.5f);
                Table innerTable = new Table(UnitValue.CreatePercentArray(new float[] { 3, 7,2 }));
                innerTable.SetWidth(UnitValue.CreatePercentValue(100));
                innerTable.SetFixedLayout();


                //table header styles
                innerTable.AddCell(CreateTextCellCustom("MAIN ITEM",
                TextAlignment.LEFT, VerticalAlignment.BOTTOM, 9, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, true, false, commonCellPadding: 5));

                innerTable.AddCell(CreateTextCellCustom("DESCRIPTION",
                TextAlignment.LEFT, VerticalAlignment.BOTTOM, 9, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, true, false, commonCellPadding: 5));

                innerTable.AddCell(CreateTextCellCustom("AMOUNT",
                TextAlignment.RIGHT, VerticalAlignment.BOTTOM, 9, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, true, false, commonCellPadding: 5));

                //table data values
                innerTable.AddCell(CreateTextCellCustom("Item name",
                TextAlignment.LEFT, VerticalAlignment.BOTTOM, 8, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, true, false, commonCellPadding: 5));

                innerTable.AddCell(CreateTextCellCustom("Item description in detail",
                TextAlignment.LEFT, VerticalAlignment.BOTTOM, 8, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, true, false, commonCellPadding: 5));

                innerTable.AddCell(CreateTextCellCustom("23.00",
                TextAlignment.RIGHT, VerticalAlignment.BOTTOM, 8, DEFAULT_FONT_COLOR, DEFAULT_FONT_TYPE, true, false, commonCellPadding: 5));


            mainCell.Add(innerTable);
            tableNext.AddCell(mainCell);
            doc.Add(tableNext);

            PdfPage page = pdfDoc.GetPage(1);
            float width = pdfDoc.GetDefaultPageSize().GetWidth();
            float height = pdfDoc.GetDefaultPageSize().GetHeight();
            Rectangle pageRect = new Rectangle(20, 20, width - 40, height - 40);
            new PdfCanvas(page).SetStrokeColor(CELL_BORDER_COLOR).SetLineWidth(0.6f).Rectangle(pageRect).Stroke();          

            doc.Close();

            resultFile.Attachment = baos.ToArray();
            resultFile.FileName = string.Format("Test_Data_PDF_{0}.pdf", System.DateTime.Now.ToString("yyyyMMddHHmmssffff"));
            return Task.FromResult(resultFile);
        }


        private static Cell CreateTextCellCustom(
        string text,
        TextAlignment textAlignment,
        VerticalAlignment cellVerticalAlignment,
        float fontsize,
        Color fontColor,
        PdfFont fontType,
        bool isBold = false,
        bool isCellBorder = false,
        bool isCellBackgroundColor = false,
        int rowSpan = 0,
        int colSpan = 0,
        float commonCellPadding = 0,
        float multipliedLeading = 1)
        {

            Cell cell = new Cell(rowSpan, colSpan);
            Paragraph p = new Paragraph();
            p.SetTextAlignment(textAlignment);

            p.Add(new Text(text).SetFont(fontType));
            p.SetFontColor(fontColor).SetFontSize(fontsize);
            p.SetMultipliedLeading(multipliedLeading);
            if (isBold)
                p.SetBold();
            cell.Add(p).SetVerticalAlignment(cellVerticalAlignment).SetPadding(commonCellPadding);
            if (!isCellBorder)
                cell.SetBorder(Border.NO_BORDER);
            if (isCellBackgroundColor)
            {
                Color customColor = new DeviceRgb(221, 235, 247);
                cell.SetBackgroundColor(customColor);
            }
            return cell;
        }

        private static Cell CreateImageCell(
        string path,
        VerticalAlignment cellVerticalAlignment,
        int rowSpan = 0,
        int colSpan = 0,
        float percentageImageWidth = 100)
        {
            Image img = new Image(ImageDataFactory.Create(path));
            img.SetWidth(UnitValue.CreatePercentValue(percentageImageWidth));
            Cell cell = new Cell(rowSpan, colSpan).Add(img).SetVerticalAlignment(cellVerticalAlignment);
            cell.SetBorder(Border.NO_BORDER);
            return cell;
        }

        public static Cell FormattedEmptyCell(
        Color cellBackgroudColor,
        Color cellBorderColor,
        float cellBorderWidth = 0.6f,
        int rowSpan = 0,
        int colSpan = 0,
        float opacity = 1f)
        {

            Cell cellFirst = new Cell(rowSpan, colSpan);
            cellFirst.SetBorder(Border.NO_BORDER);
            cellFirst.SetBorderLeft(new SolidBorder(cellBorderColor, cellBorderWidth));
            cellFirst.SetBorderBottom(new SolidBorder(cellBorderColor, cellBorderWidth));
            cellFirst.SetBorderTop(new SolidBorder(cellBorderColor, cellBorderWidth));
            cellFirst.SetBorderRight(new SolidBorder(cellBorderColor, cellBorderWidth));
            cellFirst.SetBackgroundColor(cellBackgroudColor, opacity);
            return cellFirst;
        }

    }

 

Overall we have discussed some of the daily use features and customization possible with iText7 library. The scope of the library is much more than what we discussed above, however above mentioned tips will be very handy while you are developing pdf for some applications.

The complete source code of the project is available here.

Hope you enjoy the article. Kindly share it on your social media profile if you find this helpful and don't forget to drop in your comments.

Common Fluent validation usages in web api development

Validation is one of the essential parts of any api development, below will discuss some of the common usage scenarios of Fluentvalidation.

Note: The main idea of this post is to make you familiar with the different usage scenarios of the Fluentvalidation, so we will not discuss much on the dot net core project creation and solution structure. In this solution, we are using the Dependency injection concept, so you are assumed to be familiar with those concepts ahead.

For the demo purpose, I have created a simple web api project in dot net core. Below are the classes and objects used in the project.

  • Request Object Customer
  • One Service Method Class with Interface (ServiceMethod.cs)
  • One Validator Class (CustomerValidator.cs)
  • One Controller class (FluentValidationDemo.cs)
  • One Enum, Utility, and EnumExtension classes

Prerequisite:

We have to add FluentValidation.AspNetCore package from Nuget.

Once the package is added we can see the reference below:

We have created a dummy customer class object as below to demonstrate different scenarios.

public class Customer
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string IdentificationNumber { get; set; }
        public string Email { get; set; }
        public string Gender { get; set; }
        public DateTime? DateOfBirth { get; set; }
        public string Mobile { get; set; }
        public string Username { get; set; }
        public List<Address> AddressList { get; set; }
        public List<Document> DocumentList { get; set; }
    }

    public class Address
    {
        public string AddressLine1 { get; set; }
        public string AddressLine2 { get; set; }
        public string PostBox { get; set; }
    }

    public class Document
    {
        public int Id { get; set; }
        public bool? IsActive { get; set; }
        public string DocumentName { get; set; }
        public DateTime ExpiryDate { get; set; }
        public DateTime CreatedDate { get; set; }
    }

 

All validation functionality will be handled in the CustomerValidator class. From controller we will be calling the validator class as below.

await new CustomerValidator(_serviceMethods).ValidateAndThrowAsync(customer);

 

Let us discuss different validation scenarios now:

  1. Empty and Null check for a string field
    Field: FirstName
    Description: Checks the Firstname field for empty and null cases.
    ValidationCode:
    RuleFor(x => x.FirstName)
            .NotEmpty()
            .WithMessage("First name required");
  2. Empty check for nullable field
    Field: DateOfBirth
    Description: As you know dateofbirth is a nullable field, it checks DateOfBirth for value, please note that NotNull() check will not help in this case.
    ValidationCode:
    RuleFor(x => x.DateOfBirth)
               .NotEmpty()
               .WithMessage("Date of birth required");
  3. Validation based on Condition (using When)
    Field: DateOfBirth
    Description: Check DateofBirth greater than today's date when it has value.
    ValidationCode:
    When(e => e.DateOfBirth.HasValue, () =>
                {
                    RuleFor(model => model.DateOfBirth.Value.Date)
                        .LessThanOrEqualTo(x => System.DateTime.Today)
                        .WithMessage("Date of birth cannot be greater than todays date.");
                   
                });
  4. Validation using custom rule and context
    Field: DateOfBirth
    Description: Using DateofBirth we check the user is aged 18 years or above otherwise deny. The context object is used to pass the proper validation message
    ValidationCode:
    RuleFor(model => model.DateOfBirth.Value.Date)
       .Custom((x, context) =>
           {
             if (x.AddYears(18) > DateTime.Now)
               {
                  context.AddFailure($"Users with age less than 18 years not allowed to register, please check DateofBirth {x:dd-MMM-yyyy}");
               }
           });
  5. Validation using Regular Expression
    Field: Email
    Description: The format of the email is checked using regular expressions.
    ValidationCode:
    RuleFor(x => x.Email)
        .NotEmpty()
        .WithMessage("Email required")
        .Matches(@"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
        .WithMessage("Email format is wrong.");
  6. Validation using Static method
    Field: Mobile
    Description: The business logic is written in a static class, you can write your own logic in the method. In our example, we validate mobile number should start with 04 or 09 and has 10 digits.
    ValidationCode:
    RuleFor(e => e.Mobile)
        .NotEmpty()
        .WithMessage("Mobile number required.")
        .Must(x => Utility.ValidateMobileNumber(x))
        .WithMessage("Mobile number Not Valid");
    
    
    public static bool ValidateMobileNumber(string userMobile)
      {
        bool isValidMobileNumber = false;
         if (!string.IsNullOrEmpty(userMobile))
             isValidMobileNumber = new Regex(@"^0(9|4)\d{8}$").IsMatch(userMobile);
         return isValidMobileNumber;
      }
  7. Validation based on items in enum List
    Field: Gender
    Description: Here we use an enum extension function to get the list of enum descriptions and validate whether the gender field value is present in that list when the gender field is not empty.
    ValidationCode:
    //get list of gender types
    readonly List<string> genderTypes = EnumExtension.GetEnumValuesAndDescriptions<GenderTypes>().Select(c => c.Value).ToList();
    
    //validation
    When(e => !string.IsNullOrEmpty(e.Gender), () =>
        {
           RuleFor(e => e.Gender)
               .Must(x => genderTypes.Contains(x.ToUpper()))
               .WithMessage($"Gender is invalid, allowed values are {String.Join(",", genderTypes)}");
       });
    
    //enum 
    public enum GenderTypes
            {
                [Description("MALE")]
                MALE,
                [Description("FEMALE")]
                FEMALE,
                [Description("OTHER")]
                OTHER
            }
    
    //enum extesion method
    public static List<KeyValuePair<string, string>> GetEnumValuesAndDescriptions<T>()
            {
                Type enumType = typeof(T);
                if (enumType.BaseType != typeof(Enum))
                    throw new ArgumentException("T is not System.Enum");
                List<KeyValuePair<string, string>> enumValList = new List<KeyValuePair<string, string>>();
                foreach (var e in Enum.GetValues(typeof(T)))
                {
                    var fi = e.GetType().GetField(e.ToString());
                    var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    enumValList.Add(new KeyValuePair<string, string>(e.ToString(), (attributes.Length > 0) ? attributes[0].Description : e.ToString()));
                }
                return enumValList;
            }
  8. Validation based on two fields in the request model
    Field: Username, Email
    Description: Here we check if the email field contains username text when both fields are not empty.
    ValidationCode:
    When(e => (!string.IsNullOrEmpty(e.Username) && !string.IsNullOrEmpty(e.Email)), () =>
                {
                    //Validation based on two fields in request model
                    RuleFor(e => new {e.Username,e.Email })
                            .Must(x => !x.Email.Contains(x.Username))
                            .WithMessage(x=>$"Email should not contain the username: {x.Username}");
                });
  9. Validation based on service method using Dependency Injection
    Field: IdentificationNumber
    Description: Here we validate IdentificationNumber matching certain criteria, we can write our own business logic in that method, and we can also using this method for any database related checks. We inject the service interface into the constructor of the validation class.
    ValidationCode:
     RuleFor(e => e.IdentificationNumber)
         .NotEmpty()
         .WithMessage("Identification number required.")
         .MustAsync(async (f, _) => await _serviceMethods.ValidateIdentificationNumber(f))
         .WithMessage("Identification number not valid");
  10. Validation for each child List items
    Field: AddressList.PostBox
    Description: Here we validate postbox field inside the list object AddressList. Each address object should have mandatory postbox text.
    ValidationCode:
    RuleForEach(x => x.AddressList).ChildRules(items =>
        {
           items.RuleFor(e => e.PostBox)
             .NotEmpty()
             .WithMessage("Postbox required.");
        });
  11. Validation for List of Items using SetValidator
    Field: DocumentList
    Description: Here we validate documentList using a separate validator method. We use this approach when documentList object is used in multiple places in the application, so all validation for this object remains in one place.
    ValidationCode:
    When(e => (e.DocumentList != null && e.DocumentList.Count > 0), () =>
            {
                RuleForEach(x => x.DocumentList)
                    .SetValidator(model => new DocumentValidator());
            });
    
    //DocumentValidator Class
    public class DocumentValidator : AbstractValidator<Document>
        {
            public DocumentValidator()
            {
    
                RuleFor(x => x.DocumentName)
                   .NotEmpty()
                   .WithMessage("Document name required");
    
                RuleFor(x => x.CreatedDate)
                        .LessThan(x => System.DateTime.Today)
                        .WithMessage("Document created date cannot be greater than todays date.");
    
                RuleFor(x => x.ExpiryDate)
                      .GreaterThan(x => System.DateTime.Today)
                      .WithMessage("Document expiry date should be greater than todays date.");
    
                RuleFor(x => x.ExpiryDate)
                     .GreaterThan(x => x.CreatedDate)
                     .WithMessage("Document expiry date should be greater than created date.");
            }
        }


  12. Validation based on the conditional rule in List of Items
    Field: DocumentList
    Description: Here we validate items in documentList which are having IsActive value as true. This validation is closely similar to method 10 mentioned above, the only difference is that we need to add OverridePropertyName since there is a condition in the list of items.
    ValidationCode:
    RuleForEach(model => model.DocumentList.Where(g => g.IsActive.HasValue  && g.IsActive.Value)).ChildRules(items =>
        {
           items.RuleFor(x => x.Id)
                 .NotEmpty()
                 .WithMessage("DocumentList Id required when document active.");
        }).OverridePropertyName("DocumentListValidatorWhenActive");


The complete source code of CustomerValidator and Document Validator is as below.

public class CustomerValidator : AbstractValidator<Customer>
    {
        readonly List<string> genderTypes = EnumExtension.GetEnumValuesAndDescriptions<GenderTypes>().Select(c => c.Value).ToList();
        public CustomerValidator(IServiceMethod _serviceMethods)
        {
            //Validation for empty and null check for string field
            RuleFor(x => x.FirstName)
                .NotEmpty()
                .WithMessage("First name required");

            // Validation for nullable type
            RuleFor(x => x.DateOfBirth)
                .NotEmpty()
                .WithMessage("Date of birth required");

            //Validation based on When condition in a field
            When(e => e.DateOfBirth.HasValue, () =>
            {
                RuleFor(model => model.DateOfBirth.Value.Date)
                    .LessThanOrEqualTo(x => System.DateTime.Today)
                    .WithMessage("Date of birth cannot be greater than todays date.");

                //Validation using custom rule and Validation context
                RuleFor(model => model.DateOfBirth.Value.Date)
                 .Custom((x, context) =>
                 {
                     if (x.AddYears(18) > DateTime.Now)
                     {
                         context.AddFailure($"Users with age less than 18 years not allowed to register, please check DateofBirth {x:dd-MMM-yyyy}");
                     }
                 });

            });

            // Validation for Email id using Regular Expression
            RuleFor(x => x.Email)
                .NotEmpty()
                .WithMessage("Email required")
                .Matches(@"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
                .WithMessage("Email format is wrong.");

            //Validation using a static method call            
            RuleFor(e => e.Mobile)
                .NotEmpty()
                .WithMessage("Mobile number required.")
                .Must(x => Utility.ValidateMobileNumber(x))
                .WithMessage("Mobile number Not Valid");

            //Validation based on enum values with description, gender is optional value
            When(e => !string.IsNullOrEmpty(e.Gender), () =>
            {
                RuleFor(e => e.Gender)
                        .Must(x => genderTypes.Contains(x.ToUpper()))
                        .WithMessage($"Gender is invalid, allowed values are {String.Join(",", genderTypes)}");
            });

            
            When(e => (!string.IsNullOrEmpty(e.Username) && !string.IsNullOrEmpty(e.Email)), () =>
            {
                //Validation based on two fields in request model
                RuleFor(e => new {e.Username,e.Email })
                        .Must(x => !x.Email.Contains(x.Username))
                        .WithMessage(x=>$"Email should not contain the username: {x.Username}");
            });

            //Validation based on external service method
            RuleFor(e => e.IdentificationNumber)
                .NotEmpty()
                .WithMessage("Identification number required.")
                .MustAsync(async (f, _) => await _serviceMethods.ValidateIdentificationNumber(f))
                .WithMessage("Identification number not valid");

            //Validation for Child List items
            RuleForEach(x => x.AddressList).ChildRules(items =>
            {
                items.RuleFor(e => e.PostBox)
                 .NotEmpty()
                 .WithMessage("Postbox required.");
            });

            //Validation with use of SetValidator seperate class
            When(e => (e.DocumentList != null && e.DocumentList.Count > 0), () =>
            {
                RuleForEach(x => x.DocumentList)
                    .SetValidator(model => new DocumentValidator());
            });

            //Validation with conditional rule in a list of items
            RuleForEach(model => model.DocumentList.Where(g => g.IsActive.HasValue
            && g.IsActive.Value)).ChildRules(items =>
            {
                items.RuleFor(x => x.Id)
                    .NotEmpty()
                    .WithMessage("DocumentList Id required when document active.");
            }).OverridePropertyName("DocumentListValidatorWhenActive");
        }
    }


    public class DocumentValidator : AbstractValidator<Document>
    {
        public DocumentValidator()
        {

            RuleFor(x => x.DocumentName)
               .NotEmpty()
               .WithMessage("Document name required");

            RuleFor(x => x.CreatedDate)
                    .LessThan(x => System.DateTime.Today)
                    .WithMessage("Document created date cannot be greater than todays date.");

            RuleFor(x => x.ExpiryDate)
                  .GreaterThan(x => System.DateTime.Today)
                  .WithMessage("Document expiry date should be greater than todays date.");

            RuleFor(x => x.ExpiryDate)
                 .GreaterThan(x => x.CreatedDate)
                 .WithMessage("Document expiry date should be greater than created date.");
        }
    }


The full source code is in git FluentValidationDemo

Summary

We have seen twelve commonly needed use cases of Fluent validation in asp.net core. There are more use cases and scenarios for using this powerful library, you can visit the official documentation of Fluentvalidation for that docs.

 

Apache Camel ActiveMq Installation

ActiveMQ

Apache ActiveMQ is the most popular open source, multi-protocol, Java-based message broker. It supports industry standard protocols so users get the benefits of client choices across a broad range of languages and platforms. Connect from clients written in JavaScript, C, C++, Python, .Net, and more. Integrate your multi-platform applications using the ubiquitous AMQP protocol. Exchange messages between your web applications using STOMP over websockets. Manage your IoT devices using MQTT. Support your existing JMS infrastructure and beyond. ActiveMQ offers the power and flexibility to support any messaging use-case.

Installation Steps

  1. Browse ActiveMq Official page.
  2. Choose the ActiveMQ distribution you want to install.
  3. Choose the zip file for the respective OS distribution.
  4. Unzip the downloaded zip file and open the activeMQ folder.        
  5. Move into bin directory and choose the preferred architecture(win32 or win64).
  6. Open the activeMq.bat file.
  7. Browse to http://localhost:8161/ to check whether activeMq is up and running.
  8. You will be prompted to enter the credentials. 
    username : admin
    password : admin
  9. Login to index page and choose Manage activeMQ broker
  10. Browse to ActiveMQ Home page and enjoy.

For further clarification please watch the video https://youtu.be/QHIzu9rluIw

.

 

Apache Camel CSV

Apache Camel

Camel is an Open Source integration framework that empowers you to quickly and easily integrate various systems consuming or producing data.Camel supports most of the Enterprise Integration Patterns from the excellent book by Gregor Hohpe and Bobby Woolf, and newer integration patterns from microservice architectures to help you solve your integration problem by applying best practices out of the box.

Apache Camel is standalone, and can be embedded as a library within Spring Boot, Quarkus, Application Servers, and in the clouds. Camel subprojects focus on making your work easy.Packed with several hundred components that are used to access databases, message queues, APIs or basically anything under the sun. Helping you integrate with everything.Camel supports around 50 data formats, allowing to translate messages in multiple formats, and with support from industry standard formats from finance, telco, health-care, and more.

CSV

The CSV Data Format uses Apache Common CSV to handle CSV payloads (Comma Separated Values) such as those exported/imported by Excel.Commons CSV reads and writes files in variations of the Comma Separated Value (CSV) format.

Read & Create CSV

https://youtu.be/fJ3iLNfKvR4

Dependencies

To use CSV in your Camel routes you need to add a dependency on camel-csv, which implements this data format.

<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-csv</artifactId>
  <version>x.x.x</version>
</dependency>

References

https://camel.apache.org/components/latest/dataformats/csv-dataformat.html

Bindings in Angular-Types and Usages

What is Binding?
It defines the connection between the UI of the application( HTML) and the data coming from some business logic through components.

 

Here we will discuss different types of bindings in Angular. basically, there are 3 types of bindings, but there are few variations of it, will discuss all of them.

  1. Property Binding
  2. Event Binding
  3. Two-way Binding

Property Binding

It works one side that is the direction of binding is from component to DOM. Any change in the properties of the component is reflected in the DOM.
In property binding, we define the dom element in the square bracket [] to which the binding should reflect.

<img [src]="imageUrl">


Here src is the dom element and imageUrl is the property that is bind from the component.
Code in the Component file is as below:

... 
 imageUrl:any;
  constructor() { }

  ngOnInit() {
    this.imageUrl="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
  }
...

Once we render the page we can see the image as below:

As you can see the URL value is bind to the src attribute in the img element of html.

Some of the variations of the property binding are:

  • String Interpolation
  • Attribute Binding
  • Class Binding
  • Style Binding

String Interpolation
In string interpolation, the property or field in the component is bind in a special syntax called string interpolation syntax with two curly brackets {{}}.
An example of the same is provided in this article.

Attribute Binding 
Similar to property binding only the main difference here is that we use attributes to reference the dom element. Why we use this approach is because there may come situations where we cannot identify direct DOM elements to bind for some html elements. eg. colspan.In order to bind dynamic values to those fields, we use attribute binding.

Sample code in html and components are as follows:

<table border="1">
    <tr>
        <td> A</td>
        <td> B</td>
        <td> C</td>
    </tr>
    <tr>
        <td [attr.colspan]="colspan"> colspan row</td>
    </tr>
</table>

 

...
export class BooksComponent implements OnInit {

  colspan:number
  constructor() { }

  ngOnInit() {
    this.colspan=3;
  }
}
...

 

When the page renders you can see below the output and value of the colspan bound properly.

 

Class Binding
In class binding syntax is the same as square bracket and we mention the class to be added to the html element as:

<button [class.active]="isActive">Save</button>
Here active is the class name to be added or remove and isActive the property from the component based on which class is added dynamically.
The code in the component is as below:
export class BooksComponent implements OnInit {
  isActive:boolean
  constructor() { }
  ngOnInit() {
    this.isActive=true;
  }
}
We have added a style class in the scss file as below:
.active{
    background-color: red;
}
Once we render the page we can see below style in button, also we can see the class added to the html element.


Style Binding
Functionality is the same as class binding, the only difference is that instead of class we use style, and instead of class name we use CSS styles defined. code in html is as below:

<button [style.backgroundColor]="isActive? 'blue':'grey'">Save</button>
For the same code in the component the page will render as below with inline style added to html element.

Event Binding
In event binding, we bind the event to some function inside the component. So the method of communication is from UI to the component. the syntax of it is that the event is enclosed in round brackets as shown below:
<button (click)="onSave()">Save</button>
In order to access the event object we can pass it as shown below:
<button (click)="onSave($event)">Save</button>
$event is the standard event object in angular. To stop the propagation of the event we can mention the below code in the component function, where $event signifies the event object passed to the function.
$event.stopPropagation();
The component code is as below:
 
export class BooksComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
  onSave(event) {
    console.log('Button Clicked',event);
    event.stopPropagation();
  }
}
Finally, when we click the button we get the below message in the console.
 
Two-way Binding
The final and most important binding method is two-way binding. Here changes in the property can be passed in both ways from UI to component and vice versa. The syntax for two-way binding is [(ngModel)]="propertyname". In order to use it, we need to import FormsModule to our app.module.ts file
import { FormsModule } from '@angular/forms';
...
imports: [
   ...
    FormsModule
  ]
Code in the html is as below: Here we use keyUp event binding with filtering option which is called Event filtering 
<input [(ngModel)]="email" (keyUp.enter)="onKeyUp()"/>
Code in component is as follows:
export class BooksComponent implements OnInit {
  email="me@example.com"
  constructor() { }
  ngOnInit() {  }
  onKeyUp()
  {
    console.log('Email changed:',this.email);
  }
}
Initially, the value of the email field is bind as me@example.com and once we update it the same property has updated value reflected in the component as well.
The functionality of the two-way binding is clear from below demo video:
Hope you get an idea about different types of bindings and how to use it. Do let us you if you have any clarifications or feedbacks.
 

Building Blocks of an Angular Application - Components and Modules

The basic building blocks of an Angular application are:

  1. Components
  2. Modules

Component

It is the combination of Data, HTML template, and Logic for showing the data.

Component=Data+HTML Template+Logic

Module

Container of a group of related components

There are three steps for creating a component

  • Create a component
  • Register it in a Module
  • Add an element in HTML mark up

We will walk you through each step in creating a component and using it in the angular application.

Creating a Component using Command Line
Command to use:

ng g c Books

ng stands for Next Generation, g stands for Generate, c stands for Component and Books stands for the name of the Component

Tip: When you create a component the naming convention is important. We can use camel casing when typing the name of the component in the command window, and once the component is created each capital letter will be replaced by a dash(-). this is applicable to folder name as well as file names.

Register Component in Module

When you create a component it creates a folder and adds necessary files related to that. It also does the second step of registering the component in the module. this is the advantage of using Angular CLI. if we are creating a component manually then we need to register it by adding the component name in the declaration section inside Module.

Add element in HTML markup

Once the component is registered we can use the selector inside the component to add the HTML mark up in the main file.

Component Structure

 Once we create a component the contents of it will as shown below.

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-books',
  templateUrl: './books.component.html',
  styleUrls: ['./books.component.scss']
})
export class BooksComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}
@Component is called a decorator function, and it has selector, templateUrl, styleUrls as you can see from the code above.
  • selector- it is used to identify this component using the html markup. for example, the above component will be called in the main index.html file as below:
<app-books></app-books>
  • templateUrl-it specifies the file path of  the html content used in this component. Mostly it will be inside the same folder. we can also add html content inline in the component.ts file itself, but it depends upon the purpose and use of the component. if you are using inline html, the keyword should be template, and is used is as below
...
template:'<h2>Books Component </h2>
...
  • styleUrls- It specifies the file path of the styles for this component. the style we add inside this css or scss file will reflect inside our component only. we can have multiple css files so it is denoted by an array.
Then we have export class ClassName. the export keyword denotes that this component class can be imported. this same class name we will be adding in the declarations of the module.
The class has a constructor which is used to initialize the values of the class and it is also used to set up DI(Dependency Injection). Constructor is called first when we render a component, so it needs to be kept clean and light for the optimal performance of the application.
The ngOnInit() function is called a Life cycle hook, which is used to execute some action after the component is fully loaded. there are other Life cycle hooks also that we will discuss more in a different article since it is out of the scope of this one.
 
In order to make the component fully working, I am adding one message from ts file.
Below is the code inside books.component.ts file
...
export class BooksComponent implements OnInit {
  message:any;
  constructor() { }

  ngOnInit() {
    this.message="Message from Component ts file!";
  }
...
Below is the code inside books.component.html

The syntax used in the below html is called String Interpolation.

<p>Books Works!</p>
<p>
    {{message}}
</p>
To run the full application enter the below command in the terminal.
ng serve
 
If everything goes well you will see the below message in the browser once you navigate to http://localhost:4200/
Hope you get a basic idea about component and modules in Angular.
 
 

How to use Custom Field in BlogEngine?

If you are new to Blogengine and want to know how to set up blogengine for your new website check here.

After setting up our blog site using BlogEngine people stuck on how to use custom fields. They have doubts like can we do all the changes from the admin side itself or do we need to make code change and publish the files again.

This article will help you get a clear idea of how to use custom fields in the BlogEngine admin panel.

There are two ways you can add custom fields.

  • Custom Fields for a Profile
  • Custom Fields for a Post

Custom Field for a Profile
To add a custom field for a Profile User we have to enable the multiuser option in the web.config file. In web.config file go to appsettings in the XML tag and change the default value of BlogEngine.UsageScenerio from singleblog to multiusers. The three usage scenarios are also commented just above the key field setting.


After saving the web.config file, login to the admin panel by navigating to http://www.<yourdomain>.com/admin. Go to the profile section under the menu Users.

 Now Click the Custom Field add button, a popup opens and there we can enter a unique key and value. The value can be a string or HTML. What the custom fields do is, when we use this key in some places of the page the value in the Value field will be shown.

To be able to make the Custom field visible we have to add some jquery mark up in the postview.ascx file.The File location is <root folder>/Custom/Themes/Standard/PostView.ascx.You have to open the file using a text editor like notepad or notepad++ or Visual Studio editor etc. The place and the content of the mark up to be added are shown below.

var user = new BlogEngine.Core.AuthorProfile("Admin");
var foo = "";
if (user.CustomFields != null && user.CustomFields["foo"] != null)
{
foo = user.CustomFields["foo"].Value;
}


 Custom Field: <%= foo %>

In the figure above you can see I have placed the custom field to show up just above the Body content.

Now you can see that our custom HTML will show up in all postview pages just above the post content as you can see in the below figure.

Custom Field for a Post

Take the post in which you are going to add the custom field then click on the customize link and enable the Customfield checkbox.

On the right side, a new field to add Custom Fields will be visible. Now click on the link and add the custom field in the same way as you have done for the User-specific custom field.

Now we have to add the mark up in the postview.ascx.The content to add and the screenshots are below.

 var pass = "";
    if (Post.CustomFields != null && Post.CustomFields["post-foo"] != null)
    {
        pass = Post.CustomFields["post-foo"].Value;
    }

 <div>Post Custom Field: <%= pass %></div> 

Since we have added the custom field below the post content it will be shown accordingly in the UI.

 

Hope everyone got a clear idea of how to add custom fields in BlogEngine. Custom fields are very powerful data structures .you can add more functionalities and extend the design of the pages using it.

Please refer to the BlogEngine page for custom field explanation.

Comment below if you have any doubts.

If you like the article and find it helpful please share it in your favourite social media sites.

Thank you have a great day!

Purpose of Webpack in Angular Application

If you are new to angular please refer to this article to know how to set up your first project in angular.

Webpack is a build automation tool used by angular to bundle the script files and style sheets and minifies them at runtime.
When we run the ng server command to run the angular application we can see a set of files compiled and minified. This bundling process is done using Webpack.

when we make any change in Html, style sheet or script files web pack will automatically rebuild the full application and reloads the web page.

Webpack also injects the compiled files reference to the index.html dynamically.
So a refresh is not required on the page to see new changes and this feature is called Hot Module reloading or Hot Module Replacement (HMR).

How to Create first Angular Project using Command Line Interface ?

Steps Involved are:-

  • Download and install node js. Node provider some tools to build Angular project.
  • Use NPM to install angular CLI. Refer here to Install Angular CLI
  • Command to create a new project in angular
    ng new hello-world

    Below are the screenshots of the project creation process.






  • During setting up of project it will ask for enabling angular routing. enter yes and continue.
  • Also, choose the style sheet format for the project.
  • After the project creation is successful it will try to integrate git with the mail present in the system. if it cannot find a proper git configured email it will ask to enter the name and email id to integrate with git.if you are not using git, you can ignore this step.
  • Finally to run the project type below command
    ng serve
    The default port for angular is 4200.project will be running in URL http://localhost:4200/ after compiling.

Structure of an Angular Application

Below we explain the basic structure of an angular application. We give a brief idea about what is the purpose of each folder and files.

e2e [Folder]
Used for writing end-to-end tests in the application. Mainly used for automated tests that stimulates a user browsing process on a web page.e2e test is done by using a library called Protractor. As an angular developer he doesn't need to worry about this folder, mostly comes in picture when we are doing testing in our application.

-protractor.conf.js [File]
It has all the setting for running test

-tsconfig.json [File]
It has settings for the compiler when running e2e tests.

-src [Folder] > app.e2e-spec.ts [File]
All our test cases are written in this file. The test code is written using Jasmine.

-src [Folder] > app.po.ts [File]
We write code in this file to identify elements on our page.

node_modules [Folder]
It contains all third party libraries which are used for development purpose only. During compiling the contents of this folder are bundled. We will not deploy the node_modules folder to the production server.

src [Folder]
Inside this folder our actual source code is present.

-app [Folder]
Here basic building blocks of angular applications like components and modules are present. Every application has at least one module and one component.

-assets [Folder]
we store all images and static files inside this folder.

-environments [Folder]
We store configuration settings for the different environments in this folder. Mostly it has two files environment.prod.ts,environment.ts

-main.ts [File]
This is the starting point of our application.it bootstraps the main module of the application and then the angular will load this module and the rest of the functionality works from there.

-polyfills.ts [File]
It is a bridging file to fill the gap between features that are supported in browsers and features need for the angular application to work.mainly it imports some javascript.

-styles.scss [File]
We add global styles in this file.

-test.ts [File]
It has settings for the testing environment.

.editorconfig [File]
It contains the settings for the code editor. when working in a team on the same project all developers should have the same setting on this file.

.gitignore [File]
It is used in version control to ignore files when checking out files to the repo.

angular.json [File]
It contains standard configurations for the application.

karma.conf.js [File]
Karma is a test runner in javascript. All settings are present in this file.

package.json [File]
It is a standard file present for all applications. It specifies what all libraries our application is depending upon.it has two sections: devDependencies -dependencies for the developer machine and those libraries are not needed to upload to production, and the other one Dependencies-core libraries needed for the main application.

tsconfig.json [File]
It has settings for the typescript compiler.

tslint.json [File]
It is a static analysis tool for typescript code.it checks the code for readability and functionality errors.