Wednesday, 24 June 2015

Dealing with PathTooLongException while scanning files with long paths in C#

Suppose you have a list of object of class ‘FileInfo’. This class provide properties and instance methods for the creation, copying, deletion, moving, and opening of files, and aids in the creation of FileStream objects.
List<FileInfo> AllFilesInfo;
Let say you have a DataTable 'dt' with columns ‘Name’ and ‘Path’. For all the files in AllFilesInfo object, you want to fill in the name and directory name in dataTable.
foreach (FileInfo fileInfo in AllFilesInfo)
{
       DataRow dr = dt.NewRow();
       dr[0] = fileInfo.Name;
       dr[1] = fileInfo.DirectoryName;
}
The above code works well if you don’t have any file with long path. But as soon as, your code finds any such file, you will encounter the below exception:
PathTooLongException  was caught: The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
When you debug and add a watch for fileInfo object, you will find both Directory and DirectoryName are throwing this exception. Now if you expand the ‘Non-public members’ and then the ‘base’ object of ‘fileInfo’, you will see a property named ‘FullPath’ giving the fullpath, which is what you need.


‘FullPath’ is a protected property of class ‘FileSystemInfo’, which is a base class for both ‘FileInfo’ and ‘DirectoryInfo’. You can access the path as follows:
DataRow dr = dt.NewRow();
dr[0] = fileInfo.Name;
try
{
    dr[1] = fileInfo.DirectoryName;
}
catch (PathTooLongException ex)
{
    FieldInfo fld = typeof(FileSystemInfo).GetField(
                                                    "FullPath",
                                                     BindingFlags.Instance |
                                                     BindingFlags.NonPublic);
    string fullPath = fld.GetValue(fileInfo).ToString();
    fullPath = fullPath.Remove(fullPath.IndexOf(fileInfo.Name)); // Removing file name from the fullpath
    dr[1] = fullPath;
}
By using the above code, you can access the fullPath of files with long names.

Tuesday, 16 June 2015

Determining the owner of a file\folder in C#.Net and handling with general exceptions

Determining the owner of a file\folder in C#.Net

In order to determine the owner of a file/folder, you would need to use the classes from the following namespaces:
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;

Put the following lines in a function and it will give you the owner name:
FileSecurity fileSecurity = File.GetAccessControl(path);
IdentityReference sid = fileSecurity.GetOwner(typeof(SecurityIdentifier));
NTAccount ntAccount = sid.Translate(typeof(NTAccount)) as NTAccount;
string owner = ntAccount.Value;

Here ‘path’ is the location of the file/folder. 

General Exceptions:

1.  UnauthorizedAccessException: If you don’t have access to the file, you will get this exception.

2.  IdentityNotMappedException: “Some or all identity references could not be translated”


Whenever any user is created on the machine, a unique security ID is assigned. This SID can be converted to Domain Name\Username format by translating the SID to NTAccount type, but if that user is removed from the machine then only SID exists. Now if you try to convert the SID to NTAccount type, the above exception would occur. In that case, you may just want to display the SID as follows: 
IdentityReference sid = null;
string owner = null;
try
{
FileSecurity fileSecurity = File.GetAccessControl(path);
sid = fileSecurity.GetOwner(typeof(SecurityIdentifier));
NTAccount ntAccount = sid.Translate(typeof(NTAccount)) as NTAccount;
owner = ntAccount.Value;
}
catch (IdentityNotMappedException ex)
{
if (sid != null)
owner = sid.ToString();
}

Optimizing the code if you want to display the owner name of large number of files :

If you have too many files, getting the SIDs and translating it to DomainName\username(s) would be very time consuming. You can optimize the code by finding the SIDs for all the files and once you have all the SIDs, translate them to DomainName\username.

So, for example: If you have 10000 files, determine the SID for all the 10000 files. Let say you get 7 SIDs. Now translate only those 7 SIDs to DomainName\username format. It will definitely speed up the process.

Friday, 10 October 2014

Exporting datagrid to CSV using Save Dialog in C#.NET

Below is the code for exporting the data of a data grid in C#.Net

Datagrid is as follows:


System.Windows.Forms.SaveFileDialog saveDlg = new System.Windows.Forms.SaveFileDialog();
                saveDlg.InitialDirectory = @"C:\";
                saveDlg.Filter = "CSV files (*.csv)|*.csv";
                saveDlg.FilterIndex = 0;
                saveDlg.RestoreDirectory = true;
                saveDlg.Title = "Export csv File To";
                if (saveDlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    string CsvFpath = saveDlg.FileName;
                    System.IO.StreamWriter csvFileWriter = new StreamWriter(CsvFpath, false);
                    string columnHeaderText = "";
                    int countColumn = comparisonGrid.Columns.Count - 1;
                    if (countColumn >= 0)
                    {
                        columnHeaderText = (comparisonGrid.Columns[0].Header).ToString();
                    }

                    // Writing column headers
                    for (int i = 1; i <= countColumn; i++)
                    {
                        columnHeaderText = columnHeaderText + ',' + (comparisonGrid.Columns[i].Header).ToString();
                    }
                    csvFileWriter.WriteLine(columnHeaderText);

                    // Writing values row by row
                    for (int i = 0; i <= comparisonGrid.Items.Count - 2; i++)
                    {
                        string dataFromGrid = "";
                        for (int j = 0; j <= comparisonGrid.Columns.Count - 1; j++)
                        {
                            if (j == 0)
                            {
                                dataFromGrid = ((DataRowView)comparisonGrid.Items[i]).Row.ItemArray[j].ToString();
                            }
                            else
                            {
                                dataFromGrid = dataFromGrid + ',' + ((DataRowView)comparisonGrid.Items[i]).Row.ItemArray[j].ToString();
                            }
                        }
                        csvFileWriter.WriteLine(dataFromGrid);
                    }
                    csvFileWriter.Flush();
                    csvFileWriter.Close();
                }

The content of output csv file looks like:

Thursday, 9 October 2014

Exporting data grid to Excel with Save Dialog box in C#.Net

I’ve the following data grid (say comparisonGrid) and I'll export this data into excel by following the below steps.


Step 1: Include the following namespace to your code behind file (.cs file)
using Excel = Microsoft.Office.Interop.Excel;

Step 2:  Now you would need to instantiate the instances of Excel application, excel workbook and worksheet as below (I'll do that in the export button click event):
                Excel.Application xlApp;
                Excel.Workbook xlWorkBook;
                Excel.Worksheet xlWorkSheet;
                object misValue = System.Reflection.Missing.Value;
                xlApp = new Excel.ApplicationClass();
                xlWorkBook = xlApp.Workbooks.Add(misValue);
                xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

Step 3: Fill in the excel sheet with the values of the data grid (cell by cell) as follows:
               for (int i = 0; i <= comparisonGrid.Items.Count - 1; i++)
                {
                    for (int j = 0; j <= comparisonGrid.Columns.Count - 1; j++)
                    {
                             xlWorkSheet.Cells[i + 1, j + 1] =  
                             ( (DataRowView)comparisonGrid.Items[i]).Row.ItemArray[j].ToString();
                    }
                }

Step 4: For saving the file using “Save dialog” box, you would add the following code:
               
               System.Windows.Forms.SaveFileDialog saveDlg = new System.Windows.Forms.SaveFileDialog();
                saveDlg.InitialDirectory = @"C:\";
                saveDlg.Filter = "Excel files (*.xls)|*.xls";
                saveDlg.FilterIndex = 0;
                saveDlg.RestoreDirectory = true;
                saveDlg.Title = "Export Excel File To";
             if (saveDlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    string path = saveDlg.FileName;
                    xlWorkBook.SaveCopyAs(path);
                    xlWorkBook.Saved = true;
                    xlWorkBook.Close(true, misValue, misValue);
                    xlApp.Quit();
                }

You may encounter the below error:
Error 1 Interop type 'Microsoft.Office.Interop.Excel.ApplicationClass' cannot be embedded. Use the applicable interface instead.
Fix:In your Project, expand the "References", find the Microsoft Office Interop reference. Right click it and select properties, and change "Embed Interop Types" to false. Add the following refrence “using Excel = Microsoft.Office.Interop.Excel;”

Monday, 4 August 2014

Creating WCF Client from Service Metadata

Below are the steps to create WCF clients from service metadata using Visual Studio 2013:

I'm assuming you've a WCF service created and running on WCF Test client.

1. Open Visual Studio command prompt. You can find in under Start Menu -> All Programs -> Visual Studio Tools. If you're working on Windows 7, please make sure you "Run as administrator".
2. Type in the below command:

svcutil.exe /out:<OutputFileName>.cs /config:<configFileName>.config <Service URL>

For example:
If the service url is http://localhost:54225/TestService.svc

Type in the below command:
svcutil.exe /out:WCFGeneratedProxy.cs /config:output.config http://localhost:54225/TestService.svc

This will generate the proxy file and an output.config file. Add WCFGeneratedProxy.cs file to your project and add the content of output.config file to the web.config file.


Sunday, 12 January 2014

Working with LINQ to SQL


Creating an ASP.NET website and working with LINQ

You can use LINQ to XML for following purposes-

1. For creating xml file.
2. For loading an xml file.
3. For querying xml data.
4. Manipulating xml data.
5. Transforming the xml into another shape.

In this example we will load an already created xml file. We will use Contacts.xml file. The content of this file is as shown below-

<contacts>
<contact>
<id> 1 </id>
<name> Name1 </name>
     <department> IT </department>
</contact>
<contact>
<id> 2 </id>
<name> Name2 </name>
     <department> IT </department>
</contact>
   <contact>
     <id> 3 </id>
     <name> Name3 </name>
     <department> CS </department>
   </contact>
   <contact>
     <id> 4 </id>
     <name> Name4 </name>
     <department> CS </department>
   </contact>
</contacts>

Follow the below steps to query through the xml file-

1. Open Visual Studio and create an ASP.NET website called Linq2Xml by using C#.
2. Add the above created Contacts.xml file to the App_Code directory of your solution.
3. Add a new class file called Contact.cs to the solution. This class represents an contact object and will be used when the xml is turned to a collection of strongly typed objects. The following code shows an example-

namespace Linq2Xml
{
    public class Contact
    {
        public int id { get; set; }
        public string name { get; set; }
        public string department { get; set; }
    }
}

4. Add a new class file called ContactServices.cs. This class will expose methods that use LINQ to work with the xml file. Add following code to this file.

 i. Add a class level variable to read the class file. Also, add the reference for namespace System.Xml.Linq.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Linq;

namespace Linq2Xml
{
    public class ContactServices
    {
        XElement _conXml = XElement.Load("c:\\....\\visual studio 2010\\Projects\\Linq2Xml\\Linq2Xml\\App_Data\\Contacts.xml");
. . . 

// define methods here
    }
}

ii. Add a method called GetDepartments to return the distinct departments from the xml file.

public List<string> GetDepartments()
        {
            var deptQuery =
                from con in _conXml.Descendants("contact")
                group con by con.Element("department").Value
                    into conGroup
                    select conGroup.First().Element("department").Value;
            return deptQuery.ToList();
        }
       
iii. Add another method called GetContactsByDept that takes department as a parameter. It will then query the xml file and returns department with a matching name. The query will transform data into a list of Contact object.

public List<Contact> GetContactsByDept(string department)
        {
            IEnumerable<Contact> conQuery =
                from con in _conXml.Descendants("contact")
                where con.Element("department").Value == department
                select new Contact
                {
                    id = Convert.ToInt32(con.Element("id").Value),
                    department = con.Element("department").Value,
                    name = con.Element("name").Value,
                };
            return conQuery.ToList();
        }

5. Open the default.aspx page. Add a label, Dropdown list, Button, GridView and ObjectDataSource controls to the page.

6. Configure the ObjectDataSource to point to ContactServices.GetDepartments method. 

7. Configure the dropdown list to use the ObjectDataSource.

The markup inside the MainContent placeholder should look similar to the following-

<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <asp:Label ID="Label1" runat="server" Text="Select a department:"></asp:Label>
    <br />
    <br />
    <asp:DropDownList ID="DropDownListDepts" runat="server" DataSourceID="ObjectDataSourceDept">
    </asp:DropDownList>
    &nbsp;
    <asp:Button ID="Button1" runat="server" Text="Update " onclick="Button1_Click" />
    <br />
    <br />
    <asp:GridView ID="GridViewContacts" runat="server">
    </asp:GridView>
    <br />
    <asp:ObjectDataSource ID="ObjectDataSourceDept" runat="server" SelectMethod="GetDepartments"
        TypeName="Linq2Xml.ContactServices"></asp:ObjectDataSource>
</asp:Content>

8. Add a click event to the button control. Inside the code for the click event, call the ContactServices. GetContactsByDept method and pass the selected method from the dropdown list. Update the data in the gridView control with the results. The following code shows an example-
protected void Button1_Click(object sender, EventArgs e)
        {
            ContactServices conSrv = new ContactServices();
            GridViewContacts.DataSource =
                conSrv.GetContactsByDept(DropDownListDepts.SelectedItem.Text);
            GridViewContacts.DataBind();
        }

9. Run your application. Select a department and click on Update button.  Your result should look similar to the below figure.



Monday, 2 December 2013

Creating AJAX enabled web forms

Creating AJAX enabled web forms

  1. AJAX is a platform-independent, ECMAScript-compliant technology for communicating between code running on the client and code running on the server.
  2. ASP.NET includes both a set of server controls for working with AJAX and a set of client-side JavaScript files called the Microsoft AJAX Library.
  3. The ScriptManager control is required on all pages that work with the AJAX Extensions for ASP.NET. It manages the JavaScript files sent to the client and the communication between the server and the client.
  4. The ScriptManagerProxy control is used on pages that work with a master page that already defines a ScriptManager control or with user controls that will be used on pages that include a ScriptManager control.
  5. The UpdatePanel control allows you to define an area within your page that can post back to the server and receive updates independent of the rest of the page.
  6. The UpdateProgress control is used to provide notice to the user that the page has initiated a callback to the server.

Uses and Benefits of ASP.NET AJAX


  1. Partial-page updates 
  2. Client-side processing 
  3. Desktop-like UI 
  4. Progress indication improved performance and higher scale

Building an AJAX enabled webpage:

Enabling Partial page updates:



  1. Open Visual Studio and create a new ASP.NET website.
  2. Add SQL Server database to the App_Data folder of the site or you can add northwnd.mdf database file.
  3. Add a table to the above added database. For Eg. Create a table “Employees” with columns “EmployeeID” and “EmployeeName” and add entries to these columns.
  4. Open Default.aspx in Source view. Add a ScriptManager control to the body of the page from the AJAX Extensions tab of the Toolbox. 
  5. Add text to the page to serve as a title followed by a horizontal line. Your markup inside the BodyContent control might look as follows.
  6. Add an AJAX UpdatePanel control to the page from the AJAX Extensions tab of the Toolbox.
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <h2>Employees</h2>
    <hr />
</asp:Content> 
  1. Switch to Design view and add a GridView control inside the UpdatePanel and bind the GridView to the database table.
  2. Again, open the GridView Tasks window by using the smart tag. Select the Enable Paging check box.

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="ButtonSave" EventName="Click" />
        </Triggers>
        <ContentTemplate>
            <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="SqlDataSource1"
                AllowPaging="True">
                <Columns>
                    <asp:BoundField DataField="EmployeeID" HeaderText="Employee ID" SortExpression="Employee ID" />
                    <asp:BoundField DataField="EmployeeName" HeaderText="Employee Name" SortExpression="Employee Name" />
                </Columns>
            </asp:GridView>
            <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString %>"
                SelectCommand="SELECT * FROM [Employee]"></asp:SqlDataSource>
                   </ContentTemplate>
    </asp:UpdatePanel>

9. Run the application and view the Default.aspx page in a browser. Click the data page numbers to move between data pages. Notice that only the grid is being updated and not the entire page; this is because the UpdatePanel control wraps requests for data and replaces the markup for the grid rather than refreshing the entire page.
10. Next, add a section at the top of the form (outside of the UpdatePanel) that allows the user to enter a new employee and have it added to the database. Your markup code might look as follows.

<div style="margin: 20px 0px 20px 40px">
                    Employee Name
                    <br />
                    <asp:TextBox ID="TextBoxName" runat="server" Width="200"></asp:TextBox>
                    <br />
                    <asp:Button ID="ButtonSave" runat="server" Text="Add" Style="margin-top: 15px" OnClick="ButtonSave_Click" />
 </div>

11. Next, add a Click event to the ButtonSave button defined in step 11 (onclick="ButtonSave_ Click"). This Click event will  add employee name  to theEmployees table in the database. At the end of this event, rebind the GridView control. The following code shows an example.

protected void ButtonSave_Click(object sender, EventArgs e)
        {
            SqlConnection con = new SqlConnection(conStr);
            string qry = "Insert into Employee(EmployeeName) Values('" +TextBoxName.Text + "')";
            SqlCommand cmd = new SqlCommand(qry, con);
            con.Open();
            cmd.ExecuteNonQuery();
            con.Close();
            GridView1.DataBind();
        }
12. Run the application and enter a row in the table. Notice that the entire page refreshes. Add behavior to the page so that the Add button triggers a partial-page update to the GridView control. To do so, add a trigger to the UpdatePanel control and connect the trigger to the ButtonEnter control. The following markup shows an example.

<Triggers>
            <asp:AsyncPostBackTrigger ControlID="ButtonSave" EventName="Click" />
</Triggers>

13. Run the application again and notice that now only GridView updates when a new row is added.




Adding a Progress Indicator: 

1. Open Default.aspx in Source view. Add an UpdateProgress control to the UpdatePanel. Add the control to the bottom of the panel just inside the ContentTemplate element.
2. Add text inside the ProgressTemplate elements of the UpdateProgress control to notify the user that processing is happening on the server. The following shows a sample markup.

<asp:UpdateProgress ID="UpdateProgress1" runat="server">
    <ProgressTemplate>
        <div style="margin-top: 20px; font-size: larger; color: Green">
            Processing, please wait ...
        </div>
    </ProgressTemplate>
</asp:UpdateProgress>

3. The processing happens pretty fast. Therefore, add a line of code to the end of the ButtonSave_Click event to pause the server-side processing. You can simply put the thread to sleep for a few seconds. The following code shows an example.


System.Threading.Thread.Sleep(2000);

4. Run the application and notice that the notification is shown to the user when you enter a new record in the GridView control.