Archive for the ‘C# (C-Sharp)’ Category.

Get Active Directory User’s GUID and SID in C#? (Part 2)

Yesterday we learned how to Get the Current User’s Active Directory info. Today we will learn how to get a named user’s Active Directory info?

Get a named User’s Active Directory info?

The first steps are the same as yesterday.

Step 1 – Create a new Console Application project in Visual Studio.

Step 2 – Add a .NET reference to System.DirectoryServices.AccountManagement.

Step 3 – Populate the Main Method as shown below.

using System;
using System.DirectoryServices.AccountManagement;

namespace NamedUserAdInfo
{
    class Program
    {
        static void Main(string[] args)
        {
            string userName = "Rhyous";
            PrincipalContext context = new PrincipalContext(ContextType.Domain);
            UserPrincipal user = UserPrincipal.FindByIdentity(context, userName);
            Console.WriteLine("Name: " + user.Name);
            Console.WriteLine("User: " + user.UserPrincipalName);
            Console.WriteLine("GUID: " + user.Guid);
            Console.WriteLine(" SID: " + user.Sid);
        }
    }
}

The only difference between the current user and a named user is that there is a static value for the current user called UserPrincipal.Current whereas for a named user, you need the user name.

Writing a program that does both

OK, so lets make a program that takes a parameter and does both. Here it is.

using System;
using System.DirectoryServices.AccountManagement;

namespace GetAdUserInfo
{
    class Program
    {
        static UserPrincipal user = UserPrincipal.Current;

        static void Main(string[] args)
        {
            ParseArgs(args);
            OutputUserInformation();
        }
        
        private static void OutputUserInformation()
        {
            Console.WriteLine("Name: " + user.Name);
            Console.WriteLine("User: " + user.UserPrincipalName);
            Console.WriteLine("GUID: " + user.Guid);
            Console.WriteLine(" SID: " + user.Sid);
        }

        private static void ParseArgs(string[] args)
        {
            foreach (var arg in args)
            {
                if (arg.StartsWith("user=", StringComparison.CurrentCultureIgnoreCase))
                {
                    string[] splitArgs = arg.Split("=".ToCharArray());
                    string userName = string.Empty;
                    if (splitArgs.Length == 2)
                        userName = splitArgs[1];
                    if (string.IsNullOrWhiteSpace(userName))
                    {
                        Syntax();
                    }

                    // set up domain context
                    PrincipalContext ctx = new PrincipalContext(ContextType.Domain);

                    // find a user
                    user = UserPrincipal.FindByIdentity(ctx, userName);
                    continue;
                }

                if (arg.StartsWith("user=", StringComparison.CurrentCultureIgnoreCase))
                {
                    Syntax();
                }

                // if arg not found treat it like /?
                {
                    Console.WriteLine("Argument not found: " + arg);
                    Syntax();
                }
            }
        }

        private static void Syntax()
        {
            String fullExeNameAndPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
            String ExeName = System.IO.Path.GetFileName(fullExeNameAndPath);
            Console.WriteLine(ExeName + " user=[username]");
        }
    }
}

Here are the sample projects.
GetAdUserInfo.zip

Get Active Directory User’s GUID and SID in C#? (Part 1)

Get the Current User’s Active Directory info?

Here is how to get the currently logged in users Active Directory GUID and SID.

Step 1 – Create a new Console Application project in Visual Studio.

Step 2 – Add a .NET reference to System.DirectoryServices.AccountManagement.

Step 3 – Populate the Main Method as shown below.

using System;
using System.DirectoryServices.AccountManagement;

namespace GetAdUserInfo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Name: " + UserPrincipal.Current.Name);
            Console.WriteLine("User: " + UserPrincipal.Current.UserPrincipalName);
            Console.WriteLine("GUID: " + UserPrincipal.Current.Guid);
            Console.WriteLine(" SID: " + UserPrincipal.Current.Sid);
        }
    }
}

See Part 2 – Get a named User’s Active Directory info?

C# Interview Questions

Comparing C# to other languages

  1. Q: What makes C# different than C++?
    A: C# has the CLR. C# has a Garbage collector, Properties, no globals, statics, C# has single inheritance with multiple interfaces while C++ has multiple inheritance. C# allows for the property syntax.
  2. Q: In what ways are C# and C++ the same?
    A: Object oriented. They both have classes, enums, methods, similar types (bool, int, double, etc…).

You can change the above to questions by replacing C++ with any language that candidate may say they are familiar with on their resume: Java, PHP, Ruby, Perl, Python. Of course, you may have to look up the answer. (Or not. You can usually tell by the interviewee’s confidence without knowing the answers yourself.)

C# Basics

Look the basics at least make sure they aren’t completely lying on there resume and they actually have at least done something in C#.

  1. Q: Why is a benefit of having Properties over getters and setters?
    A: If you started using a variable and now you need to wrap code to have multiple actions on get and set, you don’t have to refactor as the Property has the same name and is used the same as a member variable.
    A: Readability. For syntactical purposes the getter and the setter always have to be in the same place in code because they are grouped. Other languages allow for the getter and setter to be anywhere in the object.
  2. Q: What is the syntax for instantiating an instance of each of the following:
    boolean
    A: bool b = true;
    integer
    A: int i = 0;
    real number
    A: double d = 1.0;
    array of integers
    A: int[] myArray = new int[10];
  3. Q: What is the standard way to create an empty string?
    A: string someEmptyValue = string.empty
  4. Q: Is a string mutable or immutable?
    A: immutable.
    Q: What does that mean when performing string manipulation functions?
    A: Any time the string changes, what really happens is a new string is created in a new location in memory.
  5. Q: Write both a for loop and a foreach loop that iterates through a List called myStrings.
    A:

    for (int i = 0; i < myStrings.Count; i++)
    {
        // put code here
    }
    
    foreach  (string str in myStrings)
    {
        // put code here
    }
    

    Q: Why would you use one method over another?
    A: Maybe you need the current id, so you use the for loop.

C# – Security

  1. Q: What are some security related tools (executable files) included with .NET Framework?
    A: Caspol.exe (Code Access Security Policy Tool): Enables you to view and configure security policy for the machine policy level, the user policy level, and the enterprise policy level. In the .NET Framework 4 and later, this tool does not affect code access security (CAS) policy unless the element is set to true. For more information, see Security Changes in the .NET Framework.Cert2spc.exe (Software Publisher Certificate Test Tool): Creates a Software Publisher’s Certificate (SPC) from one or more X.509 certificates. This tool is for testing purposes only.

    Certmgr.exe (Certificate Manager Tool): Manages certificates, certificate trust lists (CTLs), and certificate revocation lists (CRLs).

    Makecert.exe (Certificate Creation Tool): Generates X.509 certificates for testing purposes only.

    Peverify.exe (PEVerify Tool): Helps you verify whether your Microsoft intermediate language (MSIL) code and associated metadata meet type safety requirements.

    SecAnnotate.exe (.NET Security Annotator Tool): Identifies the SecurityCritical and SecuritySafeCritical portions of an assembly.

    SignTool.exe (Sign Tool): Digitally signs files, verifies signatures in files, and time-stamps files.

    Sn.exe (Strong Name Tool): Helps create assemblies with strong names. This tool provides options for key management, signature generation, and signature verification.

    Ref: http://msdn.microsoft.com/en-us/library/dd233106.aspx

  2. Q: What are some libraries in the System.Security namespace?
    A:System.Security
    System.Security.AccessControl
    System.Security.Authentication
    System.Security.Authentication.ExtendedProtection
    System.Security.Authentication.ExtendedProtection.Configuration
    System.Security.Claims
    System.Security.Cryptography
    System.Security.Cryptography.Pkcs
    System.Security.Cryptography.X509Certificates
    System.Security.Cryptography.Xml
    System.Security.Permissions
    System.Security.Policy
    System.Security.Principal
    System.Security.RightsManagementQ: Can you discuss any of these libraries?
    A: See what they have to say and compare it to the web site on MSDN for these libraries.

    Q: Which libraries have you used? Tell my about a project you used that library in.

  3. What are some of the Key Security Concepts in C#?
    A: Security Permissions, Type Safety and Security,  Principal, Authentication, Authorization, Security Concerns for Keywords
    Ref: http://msdn.microsoft.com/en-us/library/z164t8hs.aspx
  4. What is Code Access Permissions?
    A: permission objects that are used to help protect resources and operations from unauthorized use. They are a fundamental part of the common language runtime’s mechanism for enforcing security restrictions on managed code.
    Ref: http://msdn.microsoft.com/en-us/library/h846e9b3.aspx

More to come . . .

Sorting by Reversals in C#

I am getting a masters and I was studying this and wanted to implement it to understand it fully. Efficiency could be improved for sure but the goal of this is not efficiency, just to implement the algorithm so when I question comes up on the final, I can answer it.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Reversals
{
    class Program
    {
        static void Main(string[] args)
        {
            // SolveByReversals1
            int[] array1 = new int[] { 0, 1, 2, 3, 7, 6, 5, 4, 9, 8, 10 };
            Console.WriteLine("Before: " + string.Join(", ", array1));
            SolveByReversals1(array1);
            Console.WriteLine(" After: " + string.Join(", ", array1));

            Console.WriteLine();

            // SolveByReversals2
            int[] array2 = new int[] { 0, 1, 2, 3, 7, 6, 5, 4, 9, 8, 10 };
            Console.WriteLine("Before: " + string.Join(", ", array2));
            SolveByReversals1(array2);
            Console.WriteLine(" After: " + string.Join(", ", array2));

            int[] array3 = new int[] { 0, 10, 20, 30, 70, 60, 50, 40, 90, 80, 100 };
            Console.WriteLine("Before: " + string.Join(", ", array3));
            SolveByReversals2(array3);
            Console.WriteLine(" After: " + string.Join(", ", array3));

            Console.WriteLine();

            // SolveByReversals3
            int[] array4 = new int[] { 0, 1, 2, 3, 7, 6, 5, 4, 9, 8, 10 };
            Console.WriteLine("Before: " + string.Join(", ", array4));
            SolveByReversals3(array4);
            Console.WriteLine(" After: " + string.Join(", ", array4));

            int[] array5 = new int[] { 0, 10, 20, 30, 70, 60, 50, 40, 90, 80, 100 };
            Console.WriteLine("Before: " + string.Join(", ", array5));
            SolveByReversals3(array5);
            Console.WriteLine(" After: " + string.Join(", ", array5));

            int[] array6 = new int[] { 0, 0, 1, 4, 3, 3, 1, 2, 2, 4 };
            Console.WriteLine("Before: " + string.Join(", ", array6));
            SolveByReversals3(array6);
            Console.WriteLine(" After: " + string.Join(", ", array6));
        }

        /// <summary>
        /// Works only for perfect sequences starting at zero 
        /// and incrementing by one {0,1,2,3,...,10,...}
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        public static int[] SolveByReversals1(int[] array)
        {
            for (int i = 0; i < array.Length; i++)
            {
                int j = Array.IndexOf<int>(array, i);
                Array.Reverse(array, i, j - i + 1);
            }
            return null;
        }

        /// <summary>
        /// Works with sequences of unique integers.
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        public static int[] SolveByReversals2(int[] array)
        {
            int pos = 0;
            for (int i = 0; i < array.Max() - 1; i++)
            {
                int j = Array.IndexOf<int>(array, i, pos);
                if (j == -1)
                    continue;
                Array.Reverse(array, pos, j - pos + 1);
                pos++;
            }
            return null;
        }

        /// <summary>
        /// Works for numbers of any sequence.
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        public static int[] SolveByReversals3(int[] array)
        {
            int pos = 0;
            int highLoop = array.Max();
            if (array.Length > highLoop)
                highLoop = array.Length;
            for (int i = 0; i < array.Max() - 1; i++)
            {
                int j = 0;
                while ((j = Array.IndexOf<int>(array, i, pos)) != -1)
                {
                    Array.Reverse(array, pos, j - pos + 1);
                    pos++;
                }
            }
            return null;
        }
    }
}

So it was nice to implement this to understand some of the difficulties and solve this issue. I may never have arrived at the third method just from class discussion.

C# – Creating a Service to Monitor a Directory

Let’s say you wanted to watch a directory and perform an action each time a file is added, deleted, changed, or renamed.

  • Microsoft has a Visual C# Windows Service project template in Visual Studio.
  • Microsoft also has a nice class already created to help with this: FileSystemWatcher

Example Project

Here is an example project you can download: DirectoryMonitoring.zip

Step 1 – Create a Visual C# Windows Service project in Visual Studio

  1. Select File | New Project.
  2. Select Templates | VIsual C# | Windows | Windows Service.
  3. Provide a name: DirectoryMonitoring
  4. Click OK.

Step 2 – Create an object that inherits from FileSystemWatcher

  1. Right-click on Project and choose Add | Class.
  2. Name it MyFileSystemWatcher.cs.
using System;
using System.IO;

namespace DirectoryMonitoring
{
    public class MyFileSystemWatcher : FileSystemWatcher
    {
        public MyFileSystemWatcher()
        {
            Init();
        }

        public MyFileSystemWatcher(String inDirectoryPath)
            : base(inDirectoryPath)
        {
            Init();
        }

        public MyFileSystemWatcher(String inDirectoryPath, string inFilter)
            : base(inDirectoryPath, inFilter)
        {
            Init();
        }

        private void Init()
        {
            IncludeSubdirectories = true;
            // Eliminate duplicates when timestamp doesn't change
            NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size; // The default also has NotifyFilters.LastWrite
            EnableRaisingEvents = true;
            Created += Watcher_Created;
            Changed += Watcher_Changed;
            Deleted += Watcher_Deleted;
            Renamed += Watcher_Renamed;
        }

        public void Watcher_Created(object source, FileSystemEventArgs inArgs)
        {
            Log.WriteLine("File created or added: " + inArgs.FullPath);
        }

        public void Watcher_Changed(object sender, FileSystemEventArgs inArgs)
        {
            Log.WriteLine("File changed: " + inArgs.FullPath);
        }

        public void Watcher_Deleted(object sender, FileSystemEventArgs inArgs)
        {
            Log.WriteLine("File deleted: " + inArgs.FullPath);
        }

        public void Watcher_Renamed(object sender, RenamedEventArgs inArgs)
        {
            Log.WriteLine("File renamed: " + inArgs.OldFullPath + ", New name: " + inArgs.FullPath);
        }
    }
}

Notice that each method is logging. We will implement this log next.

Step 3 – Add logging

  1. Add the class from a previous post: A simple Log singleton in C#
  2. Make sure to change the namespace to match.

Step 4 – Implement the Service

  1. Double-click on the Service1.cs file.
  2. Change both the Name and the ServiceName to DirectoryMonitoringService.
  3. Go to the code of the Service1.cs file in Visual Studio.
  4. Implement the constructor as follows:
using System.IO;
using System.ServiceProcess;

namespace DirectoryMonitoring
{
    public partial class Service1 : ServiceBase
    {
        protected FileSystemWatcher Watcher;

        // Directory must already exist unless you want to add your own code to create it.
        string PathToFolder = @"C:\Directoy\To\Monitor";

        public Service1()
        {
            Log.Instance.LogPath = @"C:\ProgramData\DirectoryMonitoring";
            Log.Instance.LogFileName = "DirectoryMonitoring";
            Watcher = new MyFileSystemWatcher(PathToFolder);
        }

        protected override void OnStart(string[] args)
        {
        }

        protected override void OnStop()
        {
        }
    }
}

Step 5 – Create a Service Installer

  1. Right-click on Service1.cs and choose View Designer.
  2. Right-click anywhere in the designer window and choose Add Installer. This adds a ProjectInstaller.cs file.
  3. Right-click on ProjectInstaller.cs and choose View Designer.
  4. In the designer, right-click on serviceProcessInstaller1 and choose Properties.
  5. In the properties, set Account to LocalSystem.
  6. Back in the designer, right-click on serviceInstaller1 and choose Properties.
  7. Set StartType to Automatic.
  8. Add a descriptions if you want.

Step 6 – Install the Service

  1. Open the Developer Command Prompt by right-clicking and choosing Run as Administrator.
  2. In the command prompt, change to the bin\debug folder in your project directory.
  3. Run this command to install the service:

    installutil.exe DirectoryMonitoring.exe

  4. Start the service with this command.

    net start DirectoryMonitoringService

Step 7 – Debug the Service

  1. Make sure the service is started and running.
  2. In Visual Studio with the DirectoryMonitoring project open, click Debug | Attach to Process.
  3. Select the DirectoryMonitoring.exe file.
  4. Put a break point at each event in the MyFileSystemWatcher object.
  5. Test all four events:
    1. Add a file.
    2. Rename a file.
    3. Open and save a file.
    4. Delete a file.

You have now created a service to monitor a directory and you have seen how to debug it.

WPFSharp: A WPF Searchable TextBlock Control with Highlighting

So I needed a TextBlock that was searchable and from searching online, it seems a lot of people need one too. So I decided to inherit TextBlock and write a SearchableTextBox. It is really easy to use. I wrote the blog post over on my other site:

A WPF Searchable TextBlock Control with Highlighting

Creating a drill down chart with ASP.NET and MSChart

In my first post, A basic reporting chart in ASP.NET, I went over the basics of creating a report using MSChart and ASP.NET and this was quit easy. However, in today’s world where the importance of business intelligence is ever increasing, the ability to drill down on a report has become the de facto standard. MSChart, ASP.NET, and HTML make it easy to create a drill-down report.

Note: Microsoft has a drill-down report in their ChartSamples example, but it was bundled as part of the same project with two-hundred other reports and was not a minimal example. It requires the use of an Access database (and I had nothing to read Access with), it has a bunch of javascript code that is for a tooltip preview of the drill down report, and the charts are in two objects. All of this made it more difficult for me to break this down.  In this example, the report will be its own ASP.NET project and will be a minimal example, however the use case and the sample data is taken directly from Microsoft’s example.

Report Example Use Case

Imagine you have a list of sales reps, their regions, and their sales results. You want a report to look at total sales per region. Then you want to click on a region to the see the sales by sales rep.

Download the project here: SampleChart.zip

Step 1 – Create the Visual Studio project

  1. In Visual Studio, click on File | New | Project.
  2. Select Visual C# | Web from the Installed Templates.
  3. Locate and select ASP.NET Empty Web Application.
    Note: I like to demonstrate using an Empty project you nothing is done for you, and you have to learn everything you actually need to do.
  4. Give the project a name.
    I named mine DrillDownChart because that is my example’s purpose.
  5. Click OK.
  6. Right-click on the newly created project and click Add | Reference.
  7. Select the .NET tab.
  8. Locate System.Web.DataVisualization and highlight it.
  9. Click OK.

Step 2 – Add a web form for your chart

  1. Right-click on the Project and choose Add |  New Item.
  2. Select Web Form.
  3. Give the file a name.
    I named my file  Report.aspx.
  4. Click OK.

Step 3 – Create a data object for the report

Because data is often coming from a database, this example is going to use a DataSet. I am not going to connect to a database, but just use a statically build DataSet.

  1. Right-click on the Project and choose Add |  Class.
  2. Give the file a name.
    I named my file  SalesDataSet.cs.
  3. Make the class inherit from DataSet.
  4. Click OK.

Step 4 – Add example data to the data object for the report

While in a real world scenario, you would get the data from a database or somewhere, lets first just create some sample data. We are going to create two simple tables. One is a Region table, that has the region name and ID. One is a RepSales table that has sales per rep and the rep’s region id.

  1. Create a property with only a getter that creates a region DataTable called RegionTable.
  2. Add the columns needed: RegionID and RegionName.
  3. Add the appropriate rows.
  4. Create a property with only a getter that creates a reps sales DataTable called RepsSalesTable.
  5. Add the columns needed: ID, Name, RegionID, and Sales.
  6. Add the appropriate rows.
  7. Now in your constructor, add those to the list of Tables in your object.
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Data;
    
    namespace DrillDownChart
    {
        public class SalesDataSet : DataSet
        {
            public SalesDataSet()
            {
                Tables.Add(RegionTable);
                Tables.Add(RepsSalesTable);
    
            }
    
            public DataTable RegionTable
            {
                get
                {
                    if (_RegionTable == null)
                    {
                        List<String> Regions = new List<string>() { "East", "West", "Central", "International", "South" };
    
                        _RegionTable = new DataTable("Region");
                        _RegionTable.Columns.Add("RegionID", typeof(int));
                        _RegionTable.Columns.Add("RegionName", typeof(string));
    
                        int i = 0;
                        foreach (var region in Regions)
                        {
                            DataRow row = _RegionTable.NewRow();
                            row["RegionID"] = ++i;
                            row["RegionName"] = region;
                            _RegionTable.Rows.Add(row);
                        }
    
                    }
                    return _RegionTable;
                }
            } private DataTable _RegionTable;
    
            public DataTable RepsSalesTable
            {
                get
                {
                    if (_RepsSalesTable == null)
                    {
                        List<String> reps = new List<string>() {
                            "Aaron", "Larry", "Andrew", "Mary", "Sally", "Nguyen", "Francis",
                            "Jerry", "Danny", "Jim", "Sarah", "Hannah", "Kim", "Gerry", "Bob" };
                        int[] regions = { 1, 2, 3, 1, 4, 2, 4, 3, 1, 2, 2, 3, 5, 5, 5 };
                        int[] sales = { 10440, 17772, 23880, 7663, 21773, 32294, 11983, 14991,
                                        17946, 8551, 19443, 27887, 30332, 16668, 21225 };
    
                        _RepsSalesTable = new DataTable("RepsSales");
                        _RepsSalesTable.Columns.Add("ID", typeof(int));
                        _RepsSalesTable.Columns.Add("Name", typeof(string));
                        _RepsSalesTable.Columns.Add("RegionID", typeof(int));
                        _RepsSalesTable.Columns.Add("Sales", typeof(int));
    
                        for (int i = 0; i < reps.Count; i++)
                        {
                            DataRow row = _RepsSalesTable.NewRow();
                            row["ID"] = i + 1;
                            row["Name"] = reps[i];
                            row["RegionID"] = regions[i];
                            row["Sales"] = sales[i];
    
                            _RepsSalesTable.Rows.Add(row);
                        }
    
                    }
                    return _RepsSalesTable;
                }
            } private DataTable _RepsSalesTable;
        }
    }
    

That is it, your fake example data is prepared.

Step 5 – Add a Chart to the Report.aspx file

  1. Open the Report.aspx file.
  2. Add a Register to the System.Web.DataVisualization assembly.
  3. Locate the div inside the body.
  4. Inside the div, add a Chart that includes a ChartArea.
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Report.aspx.cs" Inherits="CompareYearsByQuarter.Report" %>
    
    <%@ Register Assembly="System.Web.DataVisualization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        Namespace="System.Web.UI.DataVisualization.Charting" TagPrefix="asp" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:Chart ID="SalesReport" runat="server">
                <chartareas>
                    <asp:ChartArea Name="ChartArea1">
                    </asp:ChartArea>
                </chartareas>
            </asp:Chart>
        </div>
        </form>
    </body>
    </html>
    

Step 6 – Add code the Report.aspx.cs file

We are going to use the same object for both the original report and the drill down report. We will just a little code that switches which data the chart is populated with.

  1. Open the Report.aspx.cs file.
  2. Create an instance of the SalesDataSet object that has our sample data.
  3. Add code in the Page_Load method to configure the Chart.
    Note 1: The steps for this code is in the code and comments itself. I created a method for each step and then populated the methods as  needed.
    Note 2: Notice that the AddDataToSeries() method uses and if statement to determine whether to add the original data or the drill down data.
    Note 3: Because we used a DataTable we query the example data using LINQ. It is likely that in your production reports you are using a real database and you will probably use queries directly to your database.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Data;
    using System.Web.UI.DataVisualization.Charting;
    
    namespace DrillDownChart
    {
        public partial class RegionReport : System.Web.UI.Page
        {
            // Step 1 - Create Example Data
            SalesDataSet ExampleData = new SalesDataSet();
    
            protected void Page_Load(object sender, EventArgs e)
            {
                // Step 2 - Populate chart drop down
                PopulateChartTypeDropDown();
    
                // Step 3 - Create Series
                Series series = CreateSeries();
    
                // Step 4 - Set the chart type
                SetChartType(series);
    
                // Step 5 - Add data (and if needed drilldown links to series)
                AddDataToSeries(series);
    
                // Step 6 - Add series into the chart's series collection
                SalesReport.Series.Add(series);
            }
    
            private void PopulateChartTypeDropDown()
            {
                List<String> chartTypes = new List<String>(Enum.GetNames(typeof(SeriesChartType)));
                chartTypes.Insert(0, "");
    
                foreach (var item in chartTypes)
                {
                    DropDownListChartType.Items.Add(item);
                }
            }
    
            private Series CreateSeries()
            {
                Series series = new Series("Sales");
                series.BorderWidth = 3;
                series.ShadowOffset = 2;
                return series;
            }
    
            private void SetChartType(Series inSeries)
            {
                if (Page.Request["ChartType"] != null)
                    DropDownListChartType.SelectedValue = Page.Request["ChartType"];
    
                if (DropDownListChartType.SelectedValue.ToString() == "")
                    DropDownListChartType.SelectedValue = SeriesChartType.Column.ToString();
    
                inSeries.ChartType = (SeriesChartType)System.Enum.Parse(typeof(SeriesChartType), DropDownListChartType.SelectedValue.ToString());
            }
    
            private void AddDataToSeries(Series series)
            {
                if (Page.Request["ChartType"] == null)
                    AddAllRegionData(series);
                else
                    AddSpecificRegionData(series);
            }
    
            private void AddAllRegionData(Series series)
            {
                DataTable sales = ExampleData.Tables["RepsSales"];
                DataTable regions = ExampleData.Tables["Region"];
    
                var query = from reps in sales.AsEnumerable()
                            join region in regions.AsEnumerable()
                            on reps.Field<int>("RegionID") equals region.Field<int>("RegionID")
                            group reps by region.Field<string>("RegionName") into regionGroup
                            select new { Region = regionGroup.Key, Sales = regionGroup.Sum(total => total.Field<int>("Sales")) };
    
                // Populate new series with data
                foreach (var value in query)
                {
                    series.Points.AddXY(value.Region, value.Sales);
                }
    
                // Step 7 - Make this series drillable
                for (int i = 0; i < series.Points.Count; i++)
                {
                    series.Points[i].Url = string.Format("RegionReport.aspx?region={0}&ChartType={1}", series.Points[i].AxisLabel, DropDownListChartType.SelectedValue);
                }
            }
    
            private void AddSpecificRegionData(Series series)
            {
                var query = from reps in ExampleData.RepsSalesTable.AsEnumerable()
                            join region in ExampleData.RegionTable.AsEnumerable()
                            on reps.Field<int>("RegionID") equals region.Field<int>("RegionID")
                            where region.Field<string>("RegionName") == (Page.Request["Region"] ?? "East")
                            select new { RepName = reps.Field<string>("Name"), Sales = reps.Field<int>("Sales") };
    
                // Populate new series with data
                foreach (var value in query)
                {
                    series.Points.AddXY(value.RepName, value.Sales);
                }
    
                // Step 7 - Make this series drillable
                for (int i = 0; i < series.Points.Count; i++)
                //{
                //    // Add drill down code to drill to a third chart
                //}
            }
    
            private void AddDrillDown(Series series)
            {
                for (int i = 0; i < series.Points.Count; i++)
                {
                    series.Points[i].Url = string.Format("RegionReport.aspx?region={0}&ChartType={1}", series.Points[i].AxisLabel, DropDownListChartType.SelectedValue);
                }
            }
        }
    }
    

Step 7 – Add an http handler to the Web.Config for the Chart

  1. Open the Web.Config file.
  2. Add an http handler for the chart.
<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <httpHandlers>
      <add path="ChartImg.axd" verb="GET,HEAD,POST" validate="false"
           type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </httpHandlers>
  </system.web>
</configuration>

Your project is now complete.

You now have a report that shows you the total sales per region.

Click on the report and you have the sales per region broken out by sales rep.

And your done.

Download the project here: SampleChart.zip

A basic reporting chart in ASP.NET

It is time to learn to write some charts. By charts I mean graphic views for reporting on data.

Obtaining MSChart

For .NET 4, MSChart is included in the .NET Framework, so if you have installed .NET 4, you have already obtained MSChart.

For .NET 3.5, the MSChart project which was an add-on. If you are using .NET 3.5, you need to download and install the add-on.

Note: I am using .NET 4 and it was installed with Visual Studio 2010, so I have no need to install the add-on.

Also, we are going to the very minimal steps manually. Many of these steps may be done for you (for example, the Visual Studio Designer will populate the Web.Config for you, but it is always good to know how do things yourself.

Report Example Use Case

Imagine you have sales trending for four years, 2009-2012, and you want to visualize this trend. You want a chart that should all four years, with the quarter results next to each other.

Download the project here: SampleChart.zip

Step 1 – Create the Visual Studio project

  1. In Visual Studio, click on File | New | Project.
  2. Select Visual C# | Web from the Installed Templates.
  3. Locate and select ASP.NET Empty Web Application.
    Note: I like to demonstrate using an Empty project you nothing is done for you, and you have to learn everything you actually need to do.
  4. Give the project a name.
  5. Click OK.
  6. Right-click on the newly created project and click Add | Reference.
  7. Select the .NET tab.
  8. Locate System.Web.DataVisualization and highlight it.
  9. Click OK.

Step 2 – Add a web form for your chart

  1. Right-click on the Project and choose Add |  New Item.
  2. Select Web Form.
  3. Give the file a name.
    I named my file  Report.aspx.
  4. Click OK.

Step 3 – Create a data object for the report

  1. Right-click on the Project and choose Add |  Class.
  2. Give the file a name.
    I named my file  Data.cs.
  3. Click OK.

Step 4 – Add example data to the data object for the report

While in a real world scenario, you would get the data from a database or somewhere, lets first just create some sample data.

  1. Create a few lists of numbers, one for each year as shown.
    namespace CompareYearsByQuarter
    {
        public class Data
        {
            public int[] Sales2009 = new int[] { 47, 48, 49, 47 };
            public int[] Sales2010 = new int[] { 47, 50, 51, 48 };
            public int[] Sales2011 = new int[] { 50, 52, 53, 46 };
            public int[] Sales2012 = new int[] { 53, 54, 55, 49 };
        }
    }
    

That is it, your fake example data is prepared.

Step 5 – Add a Chart to the Report.aspx file

  1. Open the Report.aspx file.
  2. Add a Register to the System.Web.DataVisualization assembly.
  3. Locate the div inside the body.
  4. Inside the div, add a Chart that includes a ChartArea.
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Report.aspx.cs" Inherits="CompareYearsByQuarter.Report" %>
    
    <%@ Register Assembly="System.Web.DataVisualization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        Namespace="System.Web.UI.DataVisualization.Charting" TagPrefix="asp" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:Chart ID="SalesReport" runat="server">
                <chartareas>
                    <asp:ChartArea Name="ChartArea1">
                    </asp:ChartArea>
                </chartareas>
            </asp:Chart>
        </div>
        </form>
    </body>
    </html>
    

Step 6 – Add code the Report.aspx.cs file

  1. Open the Report.aspx.cs file.
  2. Create an instance of the Data object that has our sample data.
  3. Add code in the Page_Load method to configure the Chart a separate series of data for each year.
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.DataVisualization.Charting;
    
    namespace CompareYearsByQuarter
    {
        public partial class Report : System.Web.UI.Page
        {
            Data data = new Data();
    
            protected void Page_Load(object sender, EventArgs e)
            {
                Series year2009 = new Series("Sales 2009");
                // Populate new series with data
                foreach (var value in data.Sales2009)
                {
                    year2009.Points.AddY(value);
                }
                SalesReport.Series.Add(year2009);
    
                Series year2010 = new Series("Sales 2010");
                // Populate new series with data
                foreach (var value in data.Sales2010)
                {
                    year2010.Points.AddY(value);
                }
                SalesReport.Series.Add(year2010);
    
                Series year2011 = new Series("Sales 2011");
                // Populate new series with data
                foreach (var value in data.Sales2011)
                {
                    year2011.Points.AddY(value);
                }
                SalesReport.Series.Add(year2011);
    
                Series year2012 = new Series("Sales 2012");
                // Populate new series with data
                foreach (var value in data.Sales2012)
                {
                    year2012.Points.AddY(value);
                }
                SalesReport.Series.Add(year2012);
            }
        }
    }
    

Step 7 – Add an http handler to the Web.Config for the Chart

  1. Open the Web.Config file.
  2. Add an http handler for the chart.
<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <httpHandlers>
      <add path="ChartImg.axd" verb="GET,HEAD,POST" validate="false"
           type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </httpHandlers>
  </system.web>
</configuration>

You are done. Build and look at your report.

You now have a simple report that should show you the sales trend for quarters 1,2,3,4 over four years. Your chart should look like this.

Download the project here: SampleChart.zip

A simple Log singleton in C#

Here is a simple Log singleton in C#.

using System;
using System.IO;

namespace FirstService
{
    public class Log
    {
        public static Log Instance = new Log();

        private Log()
        {
            LogFileName = "Example";
            LogFileExtension = ".log";
        }

        public StreamWriter Writer { get; set; }

        public string LogPath { get; set; }

        public string LogFileName { get; set; }

        public string LogFileExtension { get; set; }

        public string LogFile { get { return LogFileName + LogFileExtension; } }

        public string LogFullPath { get { return Path.Combine(LogPath, LogFile); } }

        public bool LogExists { get { return File.Exists(LogFullPath); } }

        public void WriteLineToLog(String inLogMessage)
        {
            WriteToLog(inLogMessage + Environment.NewLine);
        }

        public void WriteToLog(String inLogMessage)
        {
            if (!Directory.Exists(LogPath))
            {
                Directory.CreateDirectory(LogPath);
            }
            if (Writer == null)
            {
                Writer = new StreamWriter(LogFullPath, true);
            }

            Writer.Write(inLogMessage);
            Writer.Flush();
        }

        public static void WriteLine(String inLogMessage)
        {
            Log.Instance.WriteLineToLog(inLogMessage);
        }

        public static void Write(String inLogMessage)
        {
            Log.Instance.WriteToLog(inLogMessage);
        }
    }
}

Note: This is not tested with multiple threads as this is a simple example.

AOP – Implementing a lazy loading property in C# with PostSharp

When developing in C#, you may have an object that contain properties that need to be initialized before they can be used. Think of a List<String> property. If you forget to initialize it, you are going to a NullReferenceException error. The List can be initialized as part of the constructor to solve this exception. However, maybe the List isn’t always used and you only want to load it if it needs to be used. So many people create a property that initializes iteself on first use. While this is not a bad idea, in C# it results in one line of code becoming at least six lines of code because you have to break out the auto property.

Here is the one line version verses the six line version (I can make it five lines if I put the private variable on the same line as the last bracket, which is a syntax I like with full properties).

List AddressLines { get; set; }
public List AddressLines
{
    get { return _AddressLines; }
    set { _AddressLines = value; }
}
private List<String> _AddressLines;

Wouldn’t it be nice if we could do this by only added single line of code, in this case an attribute? It can be that easy. Creating an instance on first use, or lazy loading, is a cross-cutting concern and can be extracted to an aspect using PostSharp. This article is going to show you how to do this.

It is assumed you have the following already installed and licensed:

  1. Visual Studio
  2. PostSharp

Step 1 – Create your Visual Studio Project

So to show you how this works, let’s get started.

  1. Create a sample Console Application project in Visual Studio.
  2. Add a reference to PostSharp.

Step 2 – Create an example class with properties

Ok, so let’s go ahead and create an example class called Address.

  1. Right-click on your project and choose Add | Class.
  2. Give the class file a name.
    I named this class Address.cs.
  3. Click OK.
  4. Add properties needed to store and address.
    Here my Address class working.
using System;
using System.Collections.Generic;

namespace ExampleAspects
{
    public class Address
    {
        public List AddressLines
        {
            get { return _AddressLines; }
            set { _AddressLines = value; }
        } private List<String> _AddressLines;

        public String City { get; set; }

        public String State { get; set; }

        public String Country { get; set; }

        public String ZipCode { get; set; }
    }
}

So our goal is to use Aspect-oriented programming to extract the lazy load something like this:

[LazyLoadAspect]
public List AddressLines { get; set; }

For me this is much clearer and more readable than the full property. Let’s make this happen in the next step.

Step 3 – Create the LazyLoadAspect

Ok, so let’s go ahead and create an example class called Address.

  1. Right-click on your project and choose Add | Class.
  2. Give the class file a name.
    I named this aspect class LazyLoadAspect.cs. Another good name might be InstantiateOnFirstUse or something.
  3. Make the class inherit from LocationInterceptionAspect.
  4. Override the OnGetValue method.
  5. Write code to get the value, check if it is null, and if null instantiate and set the value.
  6. Add a Type property that takes a type and implement that type if it is set, just in case you want to initialize using a child class. Otherwise how would you implement an interface.
using System;
using PostSharp.Aspects;

namespace Rhyous.ServiceManager.Aspects
{
    [Serializable]
    public class LazyLoadAspect : LocationInterceptionAspect
    {
        public Type Type { get; set; }

        public override void OnGetValue(LocationInterceptionArgs args)
        {
            args.ProceedGetValue();
            if (args.Value == null)
            {
                args.Value = Activator.CreateInstance(Type ?? args.Location.PropertyInfo.PropertyType);
                args.ProceedSetValue();
            }
        }
    }
}

Note: You may have a factory for creating your objects and you could replace the Activator.CreateInstance method with your factory method.

As discussed, replace the full property with this:

[LazyLoadAspect]
public List AddressLines { get; set; }

Step 4 – Prove your LazyLoadAspect works

Give it a try by creating an instance of Address in the Main method of Program.cs.

using System;
using Common.Aspects;
using PostSharp.Aspects;

namespace AspectExamples
{
    class Program
    {
        static void Main(string[] args)
        {
            Address address = new Address();
            // NullReferenceException would occur here without the LazyLoadAspect
            address.AddressLines.Add("To: John Doe");
            address.AddressLines.Add("100 N 100 E");
            address.AddressLines.Add("Building 12 Floor 5 Suite 530");
            address.City = "SomeCity";
            address.State = "Utah";
            address.Country = "USA";
        }
    }
}

Well, you are done.

Please take time to look at how the code actually ended up using ILSpy or .NET Reflector.

Return to Aspected Oriented Programming – Examples