Wednesday, May 24, 2017

Add Custom Configuration Elements in .net

When we talk about configuration file in .net the obvious first question that pops up in our mind is what is a configuration file? and why do we actually need it?
According to MSDN, the Configuration files are the XML files that can be changed as needed.The reason why we actually need them is that we can change some data that may be required by the application without recompiling the application again.
While working with the .net application we come across two very common configuration files ie. app.config and web.config.Both these configuration files have a tag, where we can add the settings related to an application.But appSetting tag allows us to add only key value pair.
<appsettings> <add key="" value=""> </appsettings>

But there are many scenarios where we want our settings to be something more than just key value pairs.
To overcome this situation Microsoft provides many classes that allow us to write our custom configuration section.All the classes related to these are present in System.Configuration dll.In this sample application, I will show how to create your custom configuration section Group, configuration section, configuration element.In the later part of this sample, I will be showing how to add intellisence to our custom tags in visual studio.
First of all, we will create a new class library project and name it as Custom tags.



Now we will add the reference to System.Configuration to the project.
First of all, we will create a class that represents the innermost element of the custom section in our case it is company tag.For creating a configuration element we need to inherit it from ConfigurationElement class.Now we need to define the attributes of the configuration element.For this, we will create public properties and add a ConfigurationPropertyAttribute to it.This ConfigurationProperty attribute has various parameters like name, DefaultValue, IsKey, IsRequired.Below is the screen shot of the CompanyElement class.

#region Company Element public class CompanyElement : ConfigurationElement { [ConfigurationProperty("name", DefaultValue = "", IsKey = true, IsRequired = true)] public string Name { get { return (string)this["name"]; } set { this["name"] = value; } } [ConfigurationProperty("shortName", DefaultValue = "", IsRequired = true)] public string ShortName { get { return (string)this["shortName"]; } set { this["shortName"] = value; } } [ConfigurationProperty("companyCode", DefaultValue = "", IsRequired = true)] public string CompanyCode { get { return (string)this["companyCode"]; } set { this["companyCode"] = value; } } } #endregion

Now our Company Element is ready, we need to create a collection of type Company Element.To achieve this we need to create a class CompanyElementCollection which inherits from ConfigurationElementCollection which is an abstract class, so we need to provide the implementation of its two abstract methods and will add ConfigurationCollection attribute to it.This ConfigurationCollection attribute has four parameters.First is the type of items that this collection will contain and the remaining three parameters are AddItemName, ClearItemsName, and RemoveItemName.If we don’t supply the AddItemName we will get add tag instead of company tag.
#region CompanyElement Collection [ConfigurationCollection(typeof(CompanyElement), AddItemName = "company")] public class CompanyElementCollection : ConfigurationElementCollection { protected override ConfigurationElement CreateNewElement() { return new CompanyElement(); } protected override object GetElementKey(ConfigurationElement element) { return ((CompanyElement)element).Name; } } #endregion

Now we are done with creating an element and its collection, we will create a new class CompanySection that inherits from ConfigurationSection.Our CompanySection will contain a public property of type company collection and decorated by attribute ConfigurationProperty. We will add the name for the property collection and set IsDefaultCollection to true as it is our default collection.
#region Company Section public class CompanySection : ConfigurationSection { [ConfigurationProperty("companies", IsDefaultCollection = true)] public CompanyElementCollection Companies { get { return (CompanyElementCollection)this["companies"]; } set { this["companies"] = value; } } } #endregion

We can have multiple sections in our application that can be grouped into one.To highlight this I have created one more section
#region Settings Section public class SettingSection : ConfigurationSection { [ConfigurationProperty("countrycode", DefaultValue = "", IsKey = true, IsRequired = true)] public string CountryCode { get { return (string)this["countrycode"]; } set { this["countrycode"] = value; } } [ConfigurationProperty("isenabled", DefaultValue = true, IsRequired = true)] public bool IsEnabled { get { return (bool)this["isenabled"]; } set { this["isenabled"] = value; } } } #endregion

Now we will create a new class MySectionGroup that inherits from ConfigurationSectionGroup. In this class, we will add two public properties that will return the sections that we have created.
#region MySection Group public class MySectionGroup : ConfigurationSectionGroup { [ConfigurationProperty("setting", IsRequired = false)] public SettingSection GeneralSettings { get { return (SettingSection)base.Sections["setting"]; } } [ConfigurationProperty("companySection", IsRequired = false)] public CompanySection ContextSettings { get { return (CompanySection)base.Sections["companySection"]; } } } #endregion

Now we will build our class library project and create its dll.Once our project builds successfully, we can test it by creating a console application and add reference of our dll to it. Open the App.config file and add the configSections,sectionGroup, and section to it.We need to specify the name and fully qualified type of all the section and section group.
<configSections> <sectionGroup name="mysection" type="CustomTags.MySectionGroup,CustomTags"> <section name="companySection" type="CustomTags.CompanySection,CustomTags"/> <section name="settingSection" type="CustomTags.SettingSection,CustomTags"/> </sectionGroup> </configSections>

Note: configSections must be the first tag inside the configuration element otherwise you may end up in getting “The parameter 'sectionGroupName' is invalid” when you try to access a section from code.
Now we will add our custom tags in App.config file.

<mysection xmlns="http://tempuri.org/XMLSchema.xsd"> <settingSection countrycode="US" isenabled='true' /> <companySection> <companies> <company name="Microsoft Corporation" shortName="MSFT" companyCode="MSFT"/> <company name="Yahoo" shortName="YHOO" companyCode="YHOO"/> </companies> </companySection> </mysection>

We will now try to access these tags from code.Below is the code snippet for the same. br/>
class Program { static void Main(string[] args) { MySectionGroup group= ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).SectionGroups["mysection"] as MySectionGroup; foreach (ConfigurationSection section in group.Sections) { Console.WriteLine("\n\n==========================================="); Console.WriteLine(section.SectionInformation.Name.ToUpper()); Console.WriteLine("==========================================="); if (section.GetType() == typeof(CompanySection)) { CompanySection c = (CompanySection)section; CompanyElementCollection coll = c.Companies; foreach (CompanyElement item in coll) { Console.WriteLine("|{0,25}| {1,6}| {2,6}|", item.Name, item.ShortName , item.CompanyCode); Console.WriteLine("-------------------------------------------"); } } else if (section.GetType() == typeof(SettingSection)) { SettingSection s = (SettingSection)section; Console.WriteLine("|{0,2}| {1,5}| ", s.CountryCode, s.IsEnabled); Console.WriteLine("-------------------------------------------"); } } Console.ReadLine(); } }


We have successfully created a custom section and we are able to access its values from code.But still, we have one issue ie visual studio doesn’t provide intellisense for the tags.This is because the visual studio does not contain the schema definition for our tags. To do this we have a simple hack.Open App.config, go to the XML menu item in the menu bar and click create the schema.This will create an xsd file.Copy your element from this file.
<xs:element name="mysection"> <xs:complexType> <xs:sequence> <xs:element name="settingSection"> <xs:complexType> <xs:attribute name="countrycode" type="xs:string" use="required" /> <xs:attribute name="isenabled" type="xs:boolean" use="required" /> </xs:complexType> </xs:element> <xs:element name="companySection"> <xs:complexType> <xs:sequence> <xs:element name="companies"> <xs:complexType> <xs:sequence> <xs:element maxOccurs="unbounded" name="company"> <xs:complexType> <xs:attribute name="name" type="xs:string" use="required" /> <xs:attribute name="shortName" type="xs:string" use="required" /> <xs:attribute name="companyCode" type="xs:string" use="required" /> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element>

Now add a new schema file to your project and add the above code in it and save it.Now again go to App.config properties and browse your schema file and add it.



This will enable intellisense for your custom tags.

Tuesday, March 21, 2017

The Microsoft Jet database engine could not find the object 'Sheet1$_' issue while reading multiple sheets in excel.

In most of the applications where we gave the user the option to upload data using excel .User can upload an excel sheet containing multiple sheets.
But some times when the user uploads excel he may get the below error
"The Microsoft Jet database engine could not find the object 'Sheet1$_'.
Make sure the object exists and that you spell its name and the path name correctly."
Now when we go through the excel sheet uploaded by the user we couldn't find the Sheet with _.
So where does this sheet come from.The answer to this question is that when we apply filter to a sheet then Microsoft creates a hidden sheet to show filtered data.
So does this mean that we can remove the above error by just removing the filter.The answer is no .Even though we remove the filter from the sheet ,still the hidden sheet is there and while uploading excel this will throw error.
So how to solve this problem.Now we can solve this problem in 2 ways
1)Create a new excel sheet and copy all the sheets to that sheet and upload.
2)Handle the hidden sheet in code.
First option is fine when we have limited users and limited sheets .But we cannot ask a user to do create a new sheet with filter .So in this article i will show how to handle this issue in Asp.net MVC.

First of all we will create a ImportExcel in Home Controller which returns a View.This method will return a View for Get Request. Now we will create another method ImportExcel1 and decorate it with [HttpPost] Attribute.Since in MVC 2 Methods cannot have same method name,we can call 2 actions using Action Name attribute .So we will decorate ImportExcel1 with [ActionName("Importexcel")]. Now if we make a get request then ImportExcel will be called and for post request ImportExcel1 will be called.Below is the code to read excel files.
using System; using System.Collections.Generic; using System.Data; using System.Data.OleDb; using System.IO; using System.Linq; using System.Web; using System.Web.Mvc; using ExcelUpload.Models; namespace ExcelUpload.Controllers { public class HomeController : Controller { public ActionResult ImportExcel() { return View(); } [ActionName("Importexcel")] [HttpPost] public ActionResult Importexcel1() { if (Request.Files["FileUpload1"].ContentLength > 0) { string extension = System.IO.Path.GetExtension(Request.Files["FileUpload1"].FileName).ToLower(); string query = null; string connString = ""; string[] validFileTypes = { ".xls", ".xlsx" }; string path1 = string.Format("{0}/{1}", Server.MapPath("~/Content/Uploads"), Request.Files["FileUpload1"].FileName); if (!Directory.Exists(path1)) { Directory.CreateDirectory(Server.MapPath("~/Content/Uploads")); } if (validFileTypes.Contains(extension)) { if (System.IO.File.Exists(path1)) { System.IO.File.Delete(path1); } Request.Files["FileUpload1"].SaveAs(path1); //Connection String to Excel Workbook if (extension.Trim() == ".xls") { connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + path1 + ";Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=2\""; DataSet dt = Utility.ConvertXSLXtoDataSet(path1,connString); ViewBag.Data = dt; } else if (extension.Trim() == ".xlsx") { connString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + path1 + ";Extended Properties=\"Excel 12.0;HDR=Yes;IMEX=2\""; DataSet dt = Utility.ConvertXSLXtoDataSet(path1, connString); ViewBag.Data = dt; } } else { ViewBag.Error = "Please Upload Files in .xls, .xlsx or .csv format"; } } return View(); } } }
Here we have created a static class Utility ,which contains a method ConvertXSLXtoDataSet. Below is the code for Utility class.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.SqlClient; using System.IO; using System.Linq; using System.Web; using System.Data.OleDb; namespace ExcelUpload.Models { public static class Utility { public static DataSet ConvertXSLXtoDataSet(string strFilePath, string connString) { OleDbConnection oledbConn = new OleDbConnection(connString); DataTable dt = new DataTable(); DataSet ds = new DataSet(); try { oledbConn.Open(); using (DataTable Sheets = oledbConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null)) { for (int i = 0; i < Sheets.Rows.Count; i++) { string worksheets = Sheets.Rows[i]["TABLE_NAME"].ToString(); OleDbCommand cmd = new OleDbCommand(String.Format("SELECT * FROM [{0}]", worksheets), oledbConn); OleDbDataAdapter oleda = new OleDbDataAdapter(); oleda.SelectCommand = cmd; DataTable t = new DataTable(worksheets); oleda.Fill(t); ds.Tables.Add(t); } } } catch(Exception ex) { } finally { oledbConn.Close(); } return ds; } } }
Now we will create a view that contains file upload control and a button.When a request for ImportExcel of Home Controller is made,we will show file upload control with button control.When we select a file and press button it will make a post request to Home Controller and ImportExcel1 method will be called.Below is the Razor View for both request.
@using System.Data; @{ ViewBag.Title = "Import Excel With Multiple Sheets"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Import Excel With Multiple Sheets</h2> <!--[if !IE]><!--> <style type="text/css"> /* Generic Styling, for Desktops/Laptops */ table { width: 100%; border-collapse: collapse; } /* Zebra striping */ tr:nth-of-type(odd) { background: #eee; } th { background: #333; color: white; font-weight: bold; } td, th { padding: 6px; border: 1px solid #ccc; text-align: left; } /* Max width before this PARTICULAR table gets nasty This query will take effect for any screen smaller than 760px and also iPads specifically. */ @@media only screen and (max-width: 760px), (min-device-width: 768px) and (max-device-width: 1024px) { /* Force table to not be like tables anymore */ table, thead, tbody, th, td, tr { display: block; } /* Hide table headers (but not display: none;, for accessibility) */ thead tr { position: absolute; top: -9999px; left: -9999px; } tr { border: 1px solid #ccc; } td { /* Behave like a "row" */ border: none; border-bottom: 1px solid #eee; position: relative; padding-left: 50%; } td:before { /* Now like a table header */ position: absolute; /* Top/left values mimic padding */ top: 6px; left: 6px; width: 45%; padding-right: 10px; white-space: nowrap; } /* Label the data */ td:before { content: attr(data-title); } } </style> <!--<![endif]--> @using (Html.BeginForm("ImportExcel","Home",FormMethod.Post,new { enctype = "multipart/form-data" } )) { <table> <tr><td>Excel file</td><td><input type="file" id="FileUpload1" name="FileUpload1" /></td></tr> <tr><td></td><td><input type="submit" id="Submit" name="Submit" value="Submit" /></td></tr> </table> } <div> @if (ViewBag.Data != null) { foreach (DataTable dt in (ViewBag.Data as System.Data.DataSet).Tables) { <h3>@dt.TableName.Replace("$","")</h3> <hr/> <table id=""> <thead> <tr> @foreach (DataColumn column in dt.Columns) { <th>@column.ColumnName.ToUpper()</th> } </tr> </thead> @if (dt.Rows.Count > 0) { foreach (DataRow dr in dt.Rows) { <tr> @foreach (DataColumn column in dt.Columns) { <td data-title='@column.ColumnName'> @dr[column].ToString()&nbsp; </td> } </tr> } } else { int count = dt.Columns.Count; <tr> <td colspan='@count' style="color:red;"> No Data Found. </td> </tr> } </table> } } else { if (ViewBag.Error != null) { <table> <tr> <td style="color:red;"> @(ViewBag.Error != null ? ViewBag.Error.ToString() : "") </td> </tr> </table> } } </div>
Now if we run the above code and call the ImportExcel Method of Home Controller,
it works fine until we upload excel having sheets without filter.But as soon as we upload
an excel sheet with filter we will get the error:-
"The Microsoft Jet database engine could not find the object 'Sheet1$_'.
Make sure the object exists and that you spell its name and the path name correctly."
So why we are getting this sheet with "_"? As you can see in the above code "ConvertXSLXtoDataSet" method,we are using a method "GetOleDbSchemaTable".This "GetOleDbSchemaTable" also returns hidden tables in the excel file.  There is a simple workaround for this.We need to just check whether the sheet name contains "_" and ignore it while reading file.Below is the modified ConvertXSLXtoDataSet Method.

public static DataSet ConvertXSLXtoDataSet(string strFilePath, string connString) { OleDbConnection oledbConn = new OleDbConnection(connString); DataTable dt = new DataTable(); DataSet ds = new DataSet(); try { oledbConn.Open(); using (DataTable Sheets = oledbConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null)) { for (int i = 0; i < Sheets.Rows.Count; i++) { string worksheets = Sheets.Rows[i]["TABLE_NAME"].ToString(); if (!worksheets.Contains("_")) { OleDbCommand cmd = new OleDbCommand(String.Format("SELECT * FROM [{0}]", worksheets), oledbConn); OleDbDataAdapter oleda = new OleDbDataAdapter(); oleda.SelectCommand = cmd; DataTable t = new DataTable(worksheets); oleda.Fill(t); ds.Tables.Add(t); } } } } catch(Exception ex) { } finally { oledbConn.Close(); } return ds; }

Monday, March 20, 2017

Import excel with multiple sheets in Asp.net MVC

In this article, we will see how to import data from an Excel spreadsheet(xlx,xlsx) which contains multiple sheets using ASP.NET MVC. We will connect to a Microsoft Excel workbook using the OLEDB.NET data provider, extract data and then display the data in a View.
First of all we will create a ImportExcel in Home Controller which returns a View.This method will return a View for Get Request. Now we will create another method ImportExcel1 and decorate it with [HttpPost] Attribute.Since in MVC 2 Methods cannot have same method name,we can call 2 actions using Action Name attribute .So we will decorate ImportExcel1 with [ActionName("Importexcel")]. Now if we make a get request then ImportExcel will be called and for post request ImportExcel1 will be called.Below is the code to read excel files.
using System; using System.Collections.Generic; using System.Data; using System.Data.OleDb; using System.IO; using System.Linq; using System.Web; using System.Web.Mvc; using ExcelUpload.Models; namespace ExcelUpload.Controllers { public class HomeController : Controller { public ActionResult ImportExcel() { return View(); } [ActionName("Importexcel")] [HttpPost] public ActionResult Importexcel1() { if (Request.Files["FileUpload1"].ContentLength > 0) { string extension = System.IO.Path.GetExtension(Request.Files["FileUpload1"].FileName).ToLower(); string query = null; string connString = ""; string[] validFileTypes = { ".xls", ".xlsx" }; string path1 = string.Format("{0}/{1}", Server.MapPath("~/Content/Uploads"), Request.Files["FileUpload1"].FileName); if (!Directory.Exists(path1)) { Directory.CreateDirectory(Server.MapPath("~/Content/Uploads")); } if (validFileTypes.Contains(extension)) { if (System.IO.File.Exists(path1)) { System.IO.File.Delete(path1); } Request.Files["FileUpload1"].SaveAs(path1); //Connection String to Excel Workbook if (extension.Trim() == ".xls") { connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + path1 + ";Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=2\""; DataSet dt = Utility.ConvertXSLXtoDataSet(path1,connString); ViewBag.Data = dt; } else if (extension.Trim() == ".xlsx") { connString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + path1 + ";Extended Properties=\"Excel 12.0;HDR=Yes;IMEX=2\""; DataSet dt = Utility.ConvertXSLXtoDataSet(path1, connString); ViewBag.Data = dt; } } else { ViewBag.Error = "Please Upload Files in .xls, .xlsx or .csv format"; } } return View(); } } }
Here we have created a static class Utility ,which contains a method ConvertXSLXtoDataSet. Below is the code for Utility class.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.SqlClient; using System.IO; using System.Linq; using System.Web; using System.Data.OleDb; namespace ExcelUpload.Models { public static class Utility { public static DataSet ConvertXSLXtoDataSet(string strFilePath, string connString) { OleDbConnection oledbConn = new OleDbConnection(connString); DataTable dt = new DataTable(); DataSet ds = new DataSet(); try { oledbConn.Open(); using (DataTable Sheets = oledbConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null)) { for (int i = 0; i < Sheets.Rows.Count; i++) { string worksheets = Sheets.Rows[i]["TABLE_NAME"].ToString(); OleDbCommand cmd = new OleDbCommand(String.Format("SELECT * FROM [{0}]", worksheets), oledbConn); OleDbDataAdapter oleda = new OleDbDataAdapter(); oleda.SelectCommand = cmd; DataTable t = new DataTable(worksheets); oleda.Fill(t); ds.Tables.Add(t); } } } catch(Exception ex) { } finally { oledbConn.Close(); } return ds; } } }
Now we will create a view that contains file upload control and a button.When a request for ImportExcel of Home Controller is made,we will show file upload control with button control.When we select a file and press button it will make a post request to Home Controller and ImportExcel1 method will be called.Below is the Razor View for both request.
@using System.Data; @{ ViewBag.Title = "Import Excel With Multiple Sheets"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Import Excel With Multiple Sheets</h2> <!--[if !IE]><!--> <style type="text/css"> /* Generic Styling, for Desktops/Laptops */ table { width: 100%; border-collapse: collapse; } /* Zebra striping */ tr:nth-of-type(odd) { background: #eee; } th { background: #333; color: white; font-weight: bold; } td, th { padding: 6px; border: 1px solid #ccc; text-align: left; } /* Max width before this PARTICULAR table gets nasty This query will take effect for any screen smaller than 760px and also iPads specifically. */ @@media only screen and (max-width: 760px), (min-device-width: 768px) and (max-device-width: 1024px) { /* Force table to not be like tables anymore */ table, thead, tbody, th, td, tr { display: block; } /* Hide table headers (but not display: none;, for accessibility) */ thead tr { position: absolute; top: -9999px; left: -9999px; } tr { border: 1px solid #ccc; } td { /* Behave like a "row" */ border: none; border-bottom: 1px solid #eee; position: relative; padding-left: 50%; } td:before { /* Now like a table header */ position: absolute; /* Top/left values mimic padding */ top: 6px; left: 6px; width: 45%; padding-right: 10px; white-space: nowrap; } /* Label the data */ td:before { content: attr(data-title); } } </style> <!--<![endif]--> @using (Html.BeginForm("ImportExcel","Home",FormMethod.Post,new { enctype = "multipart/form-data" } )) { <table> <tr><td>Excel file</td><td><input type="file" id="FileUpload1" name="FileUpload1" /></td></tr> <tr><td></td><td><input type="submit" id="Submit" name="Submit" value="Submit" /></td></tr> </table> } <div> @if (ViewBag.Data != null) { foreach (DataTable dt in (ViewBag.Data as System.Data.DataSet).Tables) { <h3>@dt.TableName.Replace("$","")</h3> <hr/> <table id=""> <thead> <tr> @foreach (DataColumn column in dt.Columns) { <th>@column.ColumnName.ToUpper()</th> } </tr> </thead> @if (dt.Rows.Count > 0) { foreach (DataRow dr in dt.Rows) { <tr> @foreach (DataColumn column in dt.Columns) { <td data-title='@column.ColumnName'> @dr[column].ToString()&nbsp; </td> } </tr> } } else { int count = dt.Columns.Count; <tr> <td colspan='@count' style="color:red;"> No Data Found. </td> </tr> } </table> } } else { if (ViewBag.Error != null) { <table> <tr> <td style="color:red;"> @(ViewBag.Error != null ? ViewBag.Error.ToString() : "") </td> </tr> </table> } } </div>

Sunday, October 9, 2016

HttpResponseException was Unhandled by user code.

In order to reach broad range of clients including browsers or mobile devices ,industry is moving towards using HTTP based restful services.Asp.Net Web API is an ideal platform for building restful services using .Net Framework. 
Exception handling is one of the most important thing that we use while creating any application .If we try to throw exception from an Action method within Web API, may be you will face the following exception "HttpResponseException was Unhandled by user code."
This is actually not an error, actually you are throwing an exception that will go outside the user code and needs to be handled by the framework to generate HTTP response that need to be send to the client. So to solve this issue we need to add an exception in Exceptions within debug menu of visual studio. 
In Visual Studio 2015 select Debug => Windows => Exception Settings 


In the Exception Settings ,Go to Common Language Runtime.


Right Click On Common Language Run time Exceptions and Click Add Exception. Enter the Exception Type as “System.Web.Http.HttpResponseException”. Right Click on the newly added exception and Click Continue When Unhanded in User Code.

Saturday, August 6, 2016

Memory management using Finalize and Dispose Method.

In this article I will be talking about one of the most important topic related to memory management in .net. We know that managing the memory is the primary concern of any application. So to help the programmers focus on implementing their functionality .net introduced automatic memory management using Garbage Collector. Garbage collection is the heart of .net application. But Garbage collector has a limitation that it can clean up only managed resources. So now the question is what is a managed resource and what is an unmanaged resource.
Managed Resource:-Managed resource means anything that can be managed by CLR(any code that uses CLR ,this can be managed code written in c# or c++).CLR handles memory management for such resources and automatically clears the memory when not needed.
Unmanaged Resources: -Unmanaged resources are generally c or c++ code, libraries or dlls.These are called unmanaged because coder has do the memory management (allocate memory for the object and clean the memory after the object is no longer being used.).These can be file handles, database connections ,etc.

So now when we have a basic idea of Managed and Unmanaged resources, We will move further towards our main topic how to implement memory management for unmanaged resources. CLR provides some help in releasing memory claimed by unmanaged resources. For clearing unmanaged resources we have a virtual method finalize in System.Object Class.
Finalize Method:- Object Class does not provide any implementation to the Finalize method. Unless a class derived from object class overrides the finalize method garbage collector cannot mark it for finalization. Garbage collector maintains a finalization queue for all the objects in the Heap whose finalization method code must run before Garbage Collector can run to reclaim their memory. Garbage Collector automatically calls the finalize method but it is not sure when Garbage Collector will run and call finalize method.

Now I will show you how to implement Finalize Method .Finalize is a virtual method of Object Class. It does not have any access modifier. We cannot call the finalize method directly as there is no keyword like finalize. So to use finalize we need to create a destructor. Destructor is a special method that has same name as class name with a tilt prefixed before it. Destructor cannot have any parameters. At compile time the destructor is converted to Finalize() Method. Below is the sample code for the same.
using System; namespace FinalizeDemo { class Program { static void Main(string[] args) { FinalizeDemo d = new FinalizeDemo(); d = null; Console.ReadLine(); } } class FinalizeDemo { public FinalizeDemo() { Console.WriteLine("Object Created"); } ~FinalizeDemo() { Console.WriteLine("Destructor Called."); } } }

Now we have added a destructor for the class ,lets verify whether it has created a finalize method for the same. So for this purpose I will be using ILSPY .In ILSPY we will browse the exe created .Below is the snapshot for the same .Here we can see the constructor but not the destructor. Now click on the Finalize method, you will see the destructor. So destructors are converted to Finalize method at compile time. Now we will run the above code .Even though we assign null to object still it’s not garbage collected. To see the destructor being called run the above application through command prompt. See the below snapshot for the same.




Note: Even though we assigned null to the object we cannot predict when memory will be de-allocated. So to make the memory de-allocated immediately we can call GC.Collect() method.
In .net we have one more way to clear unmanaged memory.
Dispose Method:- Dispose method is also used to unmanaged resources like connections ,file ,etc. This method belongs to IDisposable interface. IDisposable interface has only one method i.e. Dispose. To clear all the unmanaged resources held by a class we need to inherit that class from IDisposable interface and implement Dispose method.We have to write all cleanup code in DisposeMethod. Whenever we want to free the resources held by that object we can call the Dispose method.
using System; namespace FinalizeDemo { class Program { static void Main(string[] args) { FinalizeDemo d = new FinalizeDemo(); d.Dispose(); d = null; Console.ReadLine(); } } class FinalizeDemo:IDisposable { public FinalizeDemo() { Console.WriteLine("Object Created"); } ~FinalizeDemo() { Console.WriteLine("Destructor Called."); } public void Dispose() { Console.WriteLine("Dispose Method Called"); } } }

But there is a problem in this approach. If the user forgot to call the Dispose method, there will be memory leak. To overcome this problem its recommended to use Dispose and Finalize together. So that if user forgot to call Dispose method ,Garbage Collector can call the Finalize Method and clear all the memory held by the object.Below is the code snippet to implement Dispose and Finalize .Instead of writing the same logic in Dispose method and destructor ,we will be creating a Dispose Method that accepts a Boolean parameter. This method can be called from destructor or from Dispose () method.
using System; namespace FinalizeDemo { class Program { static void Main(string[] args) { FinalizeDemo d = new FinalizeDemo(); d.Dispose(); d = null; Console.ReadLine(); } } class FinalizeDemo:IDisposable { private bool Disposed = false; public FinalizeDemo() { Console.WriteLine("Object Created"); } ~FinalizeDemo() { Console.WriteLine("Destructor Called."); Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public void Dispose(bool disposing) { if(!Disposed) { if (disposing) { Console.WriteLine("Called From Dispose"); //Clear all managed resoures here } else { //Clear all Unmanaged resources here } Disposed = true; } } }

Here we have taken a Boolean variable Disposed =false. Now we have 2 Scenarios 1)If user calls Dispose method:-Here we are checking whether object has been disposed or not .Now when we call this method from Dispose method of IDisposable interface then we pass true. In if block we will write all clean up code and then outside it we will set the Disposed variable to true.
2)If User Forget to Call Dispose Method:-In this case Destructor will call the Dispose Method with false and control will go to else block inside Dispose method .Here we will write all clean Up code.
.Net introduce using block to take care of calling Dispose method ,if a class is implementing IDisposable interface. So it’s a good practice to create object within using block.

Tuesday, July 5, 2016

Working with HashSet in c-sharp

A HashSet is an unordered collection of unique elements.It was introduced in .net 3.5 and is found in System.Collections.Generic namespace.It is used in a situation where we want to prevent duplicates from being inserted in collection. Performancewise it is better in comparison to List.In this article i will begin by starting with creating a simple HashSet,hen will continue to perform various operations on HashSet.At the end of article ,i will show how to create a HashSet of Custom type and how to prevent duplicates from being inserted in HashSet. So lets begin our example.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HashSetDemo { class Program { static void Main(string[] args) { HashSet<string> names = new HashSet<string> { "Rajeev", "Akash", "Amit" }; foreach (var name in names) { Console.WriteLine(name); } Console.ReadKey(); } } }


In the above code we are creating a simple HashSet of string type and adding strings to it.We can also add string using Add Method .We will see how we can use Add method in the below snippet.We will now try to add the duplicate string and see what happens.
using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HashSetDemo { class Program { static void Main(string[] args) { HashSet<string> names = new HashSet<string> { "Rajeev", "Akash", "Amit" }; names.Add("Rajeev"); //duplicates are not added into collection. foreach (var name in names) { Console.WriteLine(name); } Console.ReadKey(); } } }


In he above snippet even though we try to add a duplicate string,we will not get any error but when we iterate he collection we could not find the string.This shows that we cannot add duplicate elements to a HashSet. Now we will look into some of the important methods of HashSet.
1)UnionWith:-This method combines the elements present in both the collections into collection on which it is called.

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HashSetDemo { class Program { static void Main(string[] args) { HashSet<string> names = new HashSet<string> { "Rajeev", "Akash", "Amit" }; HashSet<string> names1 = new HashSet<string> { "Rajeev", "Akash", "Amit", "Deepak", "Mohit" }; names.UnionWith(names1); foreach (var name in names) { Console.WriteLine(name); } Console.ReadKey(); } } }


2)IntersectWith:-This method combines the elements that are common to both collections.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HashSetDemo { class Program { static void Main(string[] args) { HashSet<string> names = new HashSet<string> { "Rajeev", "Akash", "Amit" }; HashSet<string> names1 = new HashSet<string> { "Rajeev", "Akash", "Amit", "Deepak", "Mohit" }; names.IntersectWith(names1); foreach (var name in names) { Console.WriteLine(name); } Console.ReadKey(); } } }



2)ExceptWith:-This method removes all the elements that are present in other collections from the collection on which it is called.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HashSetDemo { class Program { static void Main(string[] args) { HashSet<string> names = new HashSet<string> { "Rajeev", "Akash", "Amit" }; HashSet<string> names1 = new HashSet<string> { "Rajeev", "Akash", "Amit", "Deepak", "Mohit" }; names1.ExceptWith(names); foreach (var name in names1) { Console.WriteLine(name); } Console.ReadKey(); } } }


Now lets go a step further and create a class and try to create a HashSet of class type and add try to add duplicates to it.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HashSetDemo { class Program { static void Main(string[] args) { Console.WriteLine("-----Custom HashSet With Duplicates----"); HashSet<Employee> employees = new HashSet<Employee> { {new Employee{Emp_Id=1,Emp_name="Rajeev",Dept_name="IT"}}, {new Employee{Emp_Id=1,Emp_name="Rajeev",Dept_name="IT"}}, {new Employee{Emp_Id=3,Emp_name="Akash",Dept_name="IT"}}, {new Employee{Emp_Id=4,Emp_name="Amit",Dept_name="IT"}} }; Console.WriteLine("{0,-6}{1,10}{2,-8}", "Emp_Id", "Emp_name", "Dept_name"); Console.WriteLine("=============================="); foreach (var employee in employees) { Console.WriteLine("{0,-8}{1,-10}{2,5}", employee.Emp_Id, employee.Emp_name, employee.Dept_name); } Console.WriteLine("=============================="); Console.ReadKey(); } } public class Employee { public int Emp_Id { get; set; } public string Emp_name { get; set; } public string Dept_name { get; set; } } }


We know that HashSet will not allow duplicates to collection but still in out output we are having duplicate records.To overcome this drawback we need to implement IEquatable interface and override Equals and GetHashCode methods.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HashSetDemo { class Program { static void Main(string[] args) { Console.WriteLine("-----Custom HashSet With Duplicates----"); HashSet<Employee> employees = new HashSet<Employee> { {new Employee{Emp_Id=1,Emp_name="Rajeev",Dept_name="IT"}}, {new Employee{Emp_Id=1,Emp_name="Rajeev",Dept_name="IT"}}, {new Employee{Emp_Id=3,Emp_name="Akash",Dept_name="IT"}}, {new Employee{Emp_Id=4,Emp_name="Amit",Dept_name="IT"}} }; Console.WriteLine("{0,-6}{1,10}{2,-8}", "Emp_Id", "Emp_name", "Dept_name"); Console.WriteLine("=============================="); foreach (var employee in employees) { Console.WriteLine("{0,-8}{1,-10}{2,5}", employee.Emp_Id, employee.Emp_name, employee.Dept_name); } Console.WriteLine("=============================="); Console.ReadKey(); } } public class Employee : IEquatable<Employee> { public int Emp_Id { get; set; } public string Emp_name { get; set; } public string Dept_name { get; set; } public bool Equals(Employee other) { return this.Emp_Id.Equals(other.Emp_Id); } public override int GetHashCode() { return this.Emp_Id.GetHashCode(); } } }


So HashSet is a generic collection that does not allow duplicates.We can use HashSet to remove duplicates from any collection like List using HashSet.

Reading & Writing File in NodeJs

There are 2 ways to read files in node.js
1)Read synchronously:Used in the cases where file need to be read before any further processing . eg-any config file.
2)Read Asynchronously(Default):-read file in a separate thread. 


Read AsyncSynchronously
First we need to include file system object using require. Now we will call readFile method of file system.This has 2 parameters 

1)location of the file. 
2) callback function :This will notify us when we successfully read it.
console.log("--------Async Reading------------------"); console.log("Started Reading File..."); console.log("Reading File Asynchronously"); var content=fs.readFile('read.js',function(error,data) { if(error) { console.log(error); } else { console.log("Content \n "+data); } } ); console.log("-------- End Async Reading-------------");
First we need to include file system object using require. Now we will call readFileSync method of file system.This has one parameter -location of the file.
var fs=require('fs'); console.log("--------Synchronously Reading------------------"); console.log("Started Reading File..."); console.log("Reading File Synchronously"); var content=fs.readFileSync('read.js'); console.log("Content Printed First:-- \n "+content); console.log("--------End Synchronously Reading--------------");