Archive for the ‘csharp’ Category.

Log4Net Example

One of my pet peeves of third party libraries is that they are often not intuitive. I have always held off on using Log4Net because it was not intuitive to use. Well, it is just such a well-known and often-used library that it is impossible to be a C# developer without being familiar with this library.

You don’t always get what you want from a 3rd party library. I want a simple way to put a single line in code and be done. For example, a line of code that says: “Give me a log in the same directory as my exe file and name it the same as my .exe file with the .log extension appended. ILog log = Log4Net.SimpleFileLogger(Assembly.GetExecutingAssembly().Location + “.log”);

Step 1 – Create a new project

  1. Create a new Console Application project in Visual Studio. I named mine Log4Net.Example.
  2. Right-click on the Solution and choose Manage NuGET Packages for Solution.
  3. Click Online and search for Log4Net.
  4. Click Install and install the project for your poject.
  5. Close NuGET Package Manager.

Step 2 – Logging to the console window

  1. Add references to log4Net and log4Net.Config.
    (Note: I don’t know why they have the first character in log4Net namespace lowercase. That goes against most C# coding guidelines. Perhaps this is because it is a port of a java logger?)
  2. Add a member variable or property for your log.
  3. Add a line of log.
// Step 1 - Add references to log4Net and Log
using log4net;
using log4net.Config;

namespace Log4Net.Example
{
    class Program
    {
        // Step 1 - Create a variable to hold your log
        static ILog Log = LogManager.GetLogger("MyApp.log");

        static void Main(string[] args)
        {
            // Step 2 - Run this method. Why? Because the documentation says so. I know, this is NOT INTUITIVE.
            BasicConfigurator.Configure();

            // Step 3 - Log to the console
            Log.Debug("Hello, log!");
        }
    }
}

Step 3 – Log to a file

  1. Add references to log4Net assemblies and other needed assemblies.
  2. Create a variable to hold your log.
  3. Create and configure a FileAppender object.
  4. Configure log4Net to use the FileAppender.
  5. Add a line to log to the file.
// Step 1 - Add references to log4Net assemblies and other needed assemblies
using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Layout;
using System.Reflection;
using System.Text;

namespace Log4Net.Example
{
    class Program
    {
        // Step 2 - Create a variable to hold your log
        static ILog Log = LogManager.GetLogger(Assembly.GetExecutingAssembly().Location + ".log");

        private static void Main()
        {
            // Step 3 - Create and configure a FileAppender object
            var appender = new FileAppender()
            {
                Layout = new SimpleLayout(),
                File = Assembly.GetExecutingAssembly().Location + ".log",
                Encoding = Encoding.UTF8,
                AppendToFile = true,
                LockingModel = new FileAppender.MinimalLock()
            };
            appender.ActivateOptions();

            // Step 4 - Configure log4Net to use the FileAppender
            BasicConfigurator.Configure(appender);

            // Step 5 - Log to the file
            Log.Debug("Hello, log!");
        }
    }
}

Step 4 – Improving the log file

So the easiest way to improve the log is to add date and timestamps to each entry and the log level. This can be done by switching from a SimpleLayout to a PatternLayout as shown:

// Step 1 - Add references to log4Net assemblies and other needed assemblies
using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Layout;
using System.Reflection;
using System.Text;

namespace Log4Net.Example
{
    class Program
    {
        // Step 2 - Create a variable to hold your log
        static ILog Log = LogManager.GetLogger(Assembly.GetExecutingAssembly().Location + ".log");

        private static void Main()
        {
            // Step 3 - Create and configure a FileAppender object
            var appender = new FileAppender()
            {
                Layout = new PatternLayout("%date (%p) %message%newline"),
                File = Assembly.GetExecutingAssembly().Location + ".log",
                Encoding = Encoding.UTF8,
                AppendToFile = true,
                LockingModel = new FileAppender.MinimalLock()
            };
            appender.ActivateOptions();

            // Step 4 - Configure log4Net to use the FileAppender
            BasicConfigurator.Configure(appender);

            // Step 5 - Log to the file
            Log.Debug("Hello, log!");
        }
    }
}

How to write your first C# Unit Test with Visual Studio?

Visual Studio makes Unit Testing easy by bundling a Unit Test framework into it.

Imagine you have a string extension method as shown below and you wanted to unit test it.

using System;

namespace ConsoleApplication1
{
    public static class StringExtensions
    {
        public static bool IsPrimaryColor(this string inString)
        {
            string[] primaryColors = { "Red", "Yellow", "Blue" };
            foreach (var color in primaryColors)
            {
                if (inString.Equals(color, StringComparison.CurrentCultureIgnoreCase))
                    return true;
            }
            return false;
        }
    }
}

Creating a Unit Test project to test this method is very easy.

Step 1 – Create a C# Unit Test Project

  1. In Visual Studio (assuming you already have a project open), click on the Solution and choose Add new project.
  2. Select Templates | Visual C# | Test from the menu on the left.
  3. Select Unit Test Project.
  4. Enter a name for the project.
    Note: Use a good name convention, such as naming the test project the same as the project it tests but with “Tests” at the end.  For example if you have a project called MyProject you would name your test project MyProjectTests. No, it isn’t rocket science. We like to keep it simple.
  5. Click OK.

Step 2 – Give your Unit Test project a reference to the project to test

  1. Right-click on References under the newly created Unit Test project and choose Add reference.
  2. Select Solution from the right.
  3. Add the project you plan to test as a reference.

Step 3 – Create your C# test class and first test method

  1. A test class was already created by default called UnitTest1.cs. Feel free to rename it to an appropriate name.
    Note: Use a good name convention, such as naming the test class the same as the class it tests but with “Tests” at the end.  For example if you have an object called MyObject you would name your test project MyObjectTests.
  2. Add a using statement to reference the namespace of the class you plan to test.
  3. Rename the first Test method. You can’t miss it. It has the [TestMethod] attribute.
    Note: Use a good name convention, such as naming the test method so clearly that you know what it is testing just by the name. For example, StringExtensionIsBlueAPrimaryColorTest().
  4. Add code to make your first test. It is recommended you create your method using the Arrange, Act, Assert pattern.
  5. Add additional test methods as needed.
    using ConsoleApplication1;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    
    namespace StringExtensionTests
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void StringExtensionIsBlueAPrimaryColorTest()
            {
                // Arrange
                string color = "Blue";
    
                // Act
                bool actual = color.IsPrimaryColor();
    
                // Assert
                const bool expected = true;
                Assert.AreEqual(expected, actual);
            }
    
            [TestMethod]
            public void StringExtensionIsRedAPrimaryColorTest()
            {
                // Arrange
                string color = "Red";
    
                // Act
                bool actual = color.IsPrimaryColor();
    
                // Assert
                const bool expected = true;
                Assert.AreEqual(expected, actual);
            }
    
            [TestMethod]
            public void StringExtensionIsYellowAPrimaryColorTest()
            {
                // Arrange
                string color = "Yellow";
    
                // Act
                bool actual = color.IsPrimaryColor();
    
                // Assert
                const bool expected = true;
                Assert.AreEqual(expected, actual);
            }
    
            [TestMethod]
            public void StringExtensionIsBlackAPrimaryColorTest()
            {
                // Arrange
                string color = "Black";
    
                // Act
                bool actual = color.IsPrimaryColor();
    
                // Assert
                const bool expected = false;
                Assert.AreEqual(expected, actual);
            }
        }
    }
    

You have now created your first Unit Test. Go ahead and run it. You should be able to run it in Visual Studio starting with VS 2012. If you have an earlier version, you can run tests using other tools.

Thorough Unit Testing

OK. Now let’s think about what tests would be valid that we don’t have? Here are a few:

  • Case insensitive. All the following strings should return true: Red, red, rEd.
  • What if the string is blank? Null? Junk characters?

Now you write additional unit tests to test this method.

Note: It is too bad that Visual Studio’s MSTest doesn’t support Row tests. NUnit does support Row tests. With Row tests, the above Unit Test code would involve a single method that passing in multiple string values.

How to query a SQL database in C# using TableAdapters

Visual Studio has some great features to help you access the database and create objects for your database. You could manually create a connection string and manually create objects that represent the data in your database described here: How to query a SQL database in C#?. This article can show you how Visual Studio can do this for you.

So how is it done? By adding a Data Source.

Imagine you have a simple database for authentication with these tables:

User
- Id INT AUTOINCREMENT
- UserName VARCHAR(100)
- Password VARCHAR(MAX)
- Salt VARCHAR(MAX)

Person
- Id INT AUTOINCREMENT
- FirstName VARCHAR(255)
- LastName VARCHAR(255)
- Birthdate DATETIME
- UserId int FK to User.Id

Now imagine that you want to query these tables and use the data in your application.

Step 1 – Create a Visual Studio Project

  1. In visual studio create a new C# Console Application project.
  2. Once you have the project created, click on Project | Add New Data Source.
  3. Select Database and click Next.
  4. Select DataSet and click Next.
  5. Click New Connection and follow the wizard to connect to your database.
  6. Make sure that Yes, save the connection as is checked and give your saved connection a name and click Next.
  7. Click the checkbox next to Tables and click Finish.

This adds the following files to your project (the names might be slightly different on yours):

  • AuthDataSet.xsd
  • AuthDataSet.Designer.cs
  • AuthDataSet.xsc
  • AuthDataSet.xss

This code will add table adapters to your project. This basically does a lot of work for you and can save you a lot of potential development time.

Step 2 – Query a SQL Database using the Table Adapter

Now you can get the data from either of your tables with one line of code:

using System;
using System.Data;
using TableAdapterExample.AuthDataSetTableAdapters;

namespace TableAdapterExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // Query the database (select * from Person) into a DataTable
            AuthDataSet.PersonDataTable table = new PersonTableAdapter().GetData();

            // Print out the table as proof.
            PrintDataTable(table);
        }

        /// How to print a DataTable
        private static void PrintDataTable(AuthDataSet.PersonDataTable table)
        {
            foreach (DataRow row in table.Rows)
            {
                foreach (DataColumn col in table.Columns)
                {
                    Console.Write(row[col].ToString().Trim() + " ");
                }
                Console.WriteLine();
            }
        }
    }
}

Hope that helps you.

ASP.NET, JavaScript, and HTML Element ID attributes

Today I had to fix some legacy code. It is ASP.NET code and it has both ASP.NET elements and ASP.NET Controls. The plan was to replace a large portion of code behind with JavaScript. The ASP.NET code needed to be a UserControl that could appear twice on the same page. This created some problems:

  1. ASP.NET creates some html controls but changes the id and the name attributes. While it is possible to run the web page and see what the attributes will be changed to and then use those strings statically in JavaScript, the JavaScript could easily break with slight changes to the ASP.NET code. This is not scalable or maintainable.
  2. ASP.NET does NOT rename the the id or the name attributes for normal HTML tags. First, that is a consistency issue. Second it is an issue using the same control multiple times. Third, if you want to get the value of a form element, doing so uses the name attribute and so each form element needs a separate name.

So lets explain the is problem with a real world scenario.

Lets say you have the following requirements:

  1. Create a UserControl, called PersonControl, that accepts person’s basic info: First name, Last name, and Birthdate.
  2. The form also has a button and it should only be enabled if all three fields are populated.
  3. The Birthdate should use JQuery’s DateTimePicker.
  4. The First name and Last name should be ASP.NET text boxes.

Now imagine the site already exists and you have to add this requirement:

  1. A web page should exist that has multiple PersonControls showing: for example: Employee, Emergency Contact.

The problem with ASP.NET, JavaScript, and HTML Element ID attributes

So let’s build this project using a single control and static id and name attributes and see how it works. Later we will see what we need to do to get this working with multiple PersonControls.

  1. Open Visual Studio and create a new ASP.NET Empty Web Application.
  2. Add JQuery and JQuery-UI. Do this as follows:
    1. Right-click on the project and choose Manage NuGet Packages.
    2. In the Manage NuGet Packages window, on the left, click Online.
    3. On the right, in the search field, type JQuery.
    4. Install JQuery and JQuery UI.
  3. Create new Web Form called PersonForm.
  4. Add the following into your PersonForm.aspx file:
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="PersonForm.aspx.cs" Inherits="AspAndJavaScriptExample.PersonForm" %>
    
    <%@ Register Src="~/PersonControl.ascx" TagPrefix="uc1" TagName="PersonControl" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>ASP.NET, JavaScript, and HTML id Attributes</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <h2>Employee</h2>
                <uc1:PersonControl runat="server" ID="PersonControlEmployee" />
            </div>
            <%--<div>
                <uc1:PersonControl runat="server" ID="PersonControlEmergencyContact" />
            </div>--%>
        </form>
    </body>
    </html>
    
  5. Create a new Web User Control called PersonControl.
  6. Add the following into your PersonControl.ascx file:
    <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="PersonControl.ascx.cs" Inherits="AspAndJavaScriptExample.PersonControl" %>
    <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="PersonControl.ascx.cs" Inherits="AspAndJavaScriptExample.PersonControl" %>
    <link href="Content/themes/base/minified/jquery.ui.datepicker.min.css" rel="stylesheet" />
    <script src="scripts/jquery-2.0.0.min.js"></script>
    <script src="scripts/jquery-ui-1.10.3.min.js"></script>
    <script src="scripts/ButtonManager.js"></script>
    <script>
        $(function () {
            $(".datepicker").datepicker();
        });
    </script>
    
    <div style="border: solid; padding: 2px">
        First name:
        <asp:TextBox ID="FirstName" runat="server"></asp:TextBox><br />
        Last name:
        <asp:TextBox ID="LastName" runat="server"></asp:TextBox><br />
        Birthdate:
        <input type="text" name="BirthDate" id="BirthDate" class="datepicker" /><br />
        <asp:Button ID="SubmitPerson" runat="server" Text="Submit" OnClick="SubmitPerson_Click" />
    </div>
    
  7. Add the following button SubmitPerson_Click method into your PersonControl.ascx file:
            protected void SubmitPerson_Click(object sender, EventArgs e)
            {   // Put break point here            
                var firstName = FirstName.Text;
                var laststName = LastName.Text;
                var birthdate = Request.Form["Birthdate"];
            }
    
  8. Now add this ButtonManager.js file.
    jQuery(document).ready(function () { 
        $("#PersonControlEmployee_FirstName").bind("propertychange keyup input paste", setButtonState);
        $("#PersonControlEmployee_LastName").bind("propertychange keyup input paste", setButtonState);
        $("#BirthDate").change(setButtonState);
        setButtonState();
    });
    
    var setButtonState = function () {
        if (!areValuesPopulated())
            $("#PersonControlEmployee_SubmitPerson").attr("disabled", "disabled");
        else
            $("#PersonControlEmployee_SubmitPerson").removeAttr("disabled");
    }
    
    var areValuesPopulated = function () {
        return $("#PersonControlEmployee_FirstName").val() != ""
             && $("#PersonControlEmployee_LastName").val() != ""
             && $("#BirthDate").datepicker().val() != "";
    }
    
  9. Now run the project and look at the source code of the html. It looks as follows:
    
    
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head><title>
    	ASP.NET, JavaScript, and HTML id Attributes
    </title></head>
    <body>
        <form method="post" action="PersonForm.aspx" id="form1">
    <div class="aspNetHidden">
    <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="nkizDAjcAtd96A9EOpli0xdG3n6zTXVaM/5t2fmcAI5+LPQ6OzzIV2wUpisxoUTMFxIKkUwKDY4Xk36/NouRsiE81gq5z3Ch/tz3DlxJW9g=" />
    </div>
    
    <div class="aspNetHidden">
    
    	<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="XCB0fxwKvdqEXpUBaICUtf6EzkAvBeahq0bywZekyukCuzvGVagqOnVHUWFHF2Cycd2xkg/UhNh/B3qNqabkBI+Flj52GkM3p6SF5eL/M4SnnfwmFBjWVOaTZ+IlwMvkR1bGuMxomyeJJ5HaU1FXWSYDYHVtgM9tdsVi31EireM=" />
    </div>
            <div>
                <h2>Employee</h2>
                
    <link href="Content/themes/base/minified/jquery.ui.datepicker.min.css" rel="stylesheet" />
    <script src="scripts/jquery-2.0.0.min.js"></script>
    <script src="scripts/jquery-ui-1.10.3.min.js"></script>
    <script src="scripts/ButtonManager.js"></script>
    <script>
        $(function () {
            $(".datepicker").datepicker();
        });
    </script>
    
    <div style="border: solid; padding: 2px">
        First name:
        <input name="PersonControlEmployee$FirstName" type="text" id="PersonControlEmployee_FirstName" /><br />
        Last name:
        <input name="PersonControlEmployee$LastName" type="text" id="PersonControlEmployee_LastName" /><br />
        Birthdate:
        <input type="text" name="BirthDate" id="BirthDate" class="datepicker" /><br />
        <input type="submit" name="PersonControlEmployee$SubmitPerson" value="Submit" id="PersonControlEmployee_SubmitPerson" />
    </div>
    
            </div>
            
        </form>
    </body>
    </html>
    

Problems

  1. Notice the id and name attributes on the tags. The ASP.NET controls have been altered by ASP.NET with a prefix. This is not the problem. This is good. If the control is used multiple times, then this keeps the id and name attributes unique and they are supposed to be unique. However, the problem is, if the id is changed in this line . . .
    <uc1:PersonControl runat="server" ID="PersonControlEmployee" />
    

    . . . then id and name attributes in the child control will change. Since we are using those values statically in the ManageButton.js, any such change also breaks in the javascript. Also, we aren’t using a master page, but if you decided to add a master page, that add an additional prefix, which would create different id and name attributes, again causing the javascript to break. In fact, any such nesting change will change the id and name attributes breaking the javascript.

  2. The control that is not an ASP.NET control, the JQuery datepicker control, did not have the same modifications made to the Birthdate. So this tag won’t work if the control is used multiple times.

Do you want to see the problem?

Update your form in PersonForm.aspx to include multiple controls.

    <form id="form1" runat="server">
        <div>
            <h2>Employee</h2>
            <uc1:PersonControl runat="server" ID="PersonControlEmployee" />
        </div>
        <div>
            <h2>Emergency Contact</h2>
            <uc1:PersonControl runat="server" ID="PersonControlEmergencyContact" />
        </div>
    </form>

Now give it try. See the problems? Ok. So now you have a simulation of the problematic code that I faced today.

Solution to ASP.NET, JavaScript, and HTML Element ID attributes

So we are going to fix this in parts. We are going to use a variable in the ASP.NET control called ClientID, that is basically the prefix used.

  1. Fix html elements to use the same prefix as the ASP.NET controls
  2. Fix the javascript to receive the ClientID as a parameter
  3. Fix the datepicker attributes

    First, let’s fix the ASP.NET and HTML so that all the id and name attributes are consistently changed.

    Change the datepicker line and add some code so it will have the same prefix as ASP.NET created html controls.

    <input type="text" name="<%=ClientID%>$BirthDate" id="<%=ClientID%>_BirthDate" class="datepicker" /><br />
    

    Pass the prefix into the JavaScript

    1. In the PersonControl.ascx file, add a little snippet of JavaScript code to pass the ClientID into the JavaScript files.
      <script>
          $(function () {
              $(".datepicker").datepicker();
          });
          jQuery(document).ready(function () {
              startManagingButton("<%=ClientID%>");
          });
      </script>
      
    2. Now update your JavaScript file to use that ClientID as the prefix. Notice, this is used in the events. I created a simple buildId method that I use throughout now.
      var startManagingButton = function (inIdPrefix) {
          $(buildId(inIdPrefix, "_FirstName")).bind("propertychange keyup input paste", inIdPrefix, setButtonState);
          $(buildId(inIdPrefix, "_LastName")).bind("propertychange keyup input paste", inIdPrefix, setButtonState);
          $(buildId(inIdPrefix, "_BirthDate")).change(inIdPrefix, setButtonState);
          setButtonState(inIdPrefix);
      }
      
      var setButtonState = function (inIdPrefix) {
          if (inIdPrefix.data)
              inIdPrefix = inIdPrefix.data;
          
          if ($(buildId(inIdPrefix, "_FirstName")).val() == "" || $(buildId(inIdPrefix, "_LastName")).val() == "" || $(buildId(inIdPrefix, "_BirthDate")).val() == "")
              $(buildId(inIdPrefix, "_SubmitPerson")).attr("disabled", "disabled");
          else
              $(buildId(inIdPrefix, "_SubmitPerson")).removeAttr("disabled");
      };
      
      var buildId = function (inIdPrefix, idSuffix) {
          return "#" + inIdPrefix + idSuffix;
      };
      

      Now no matter how you update or move this web page, the Id values always work.

    Use the ClientID in ASP.NET SubmitPerson_Click method

    Update the code to look as follows:

        protected void SubmitPerson_Click(object sender, EventArgs e)
        {   // Put break point here            
            var firstName = FirstName.Text;
            var laststName = LastName.Text;
            var birthdate = Request.Form[ClientID + "$Birthdate"];
        }
    

    Using the PersonControl multiple times

    Now everything should be working and you should be able to include as many instances of your control in your web page as you want.

    Update your form in PersonForm.aspx to include many of these controls.

        <form id="form1" runat="server">
            <div>
                <h2>Employee</h2>
                <uc1:PersonControl runat="server" ID="PersonControlEmployee" />
            </div>
            <div>
                <h2>Spouse</h2>
                <uc1:PersonControl runat="server" ID="PersonControlSpouse" />
            </div>
            <div>
                <h2>Emergency Contact</h2>
                <uc1:PersonControl runat="server" ID="PersonControlEmergencyContact" />
            </div>
        </form>
    

    Now give it try. All instances of the PersonControl are now working. The dynamic id and name attributes are not a problem as we are handling them; in fact, they are part of the ultimate solution to make the control reusable.

    Conclusion

    ASP.NET, JavaScript, and HTML Element ID attributes can all be used to work together to make a nice cohesive application.

    If you have a better solution, please post a comment and let me know.

    Downloads

    Here is the project in both states:

    AspAndJavaScriptExample-problematic.zip

    AspAndJavaScriptExample-working.zip

    Bugs

    Now the only bug I can find is on clicking submit the JQuery datepicker field is cleared. I’ll try to fix that and post the solution in another post.

How to create an excel spreadsheet with C#?

I needed to create an Excel spread sheet in C# and I didn’t want to reinvent the wheel.

I found this awesome project: https://closedxml.codeplex.com

I already had a DataTable that I wanted to export in ASP.NET to an Excel file and download. I created an extension method for the DataTable.

    public static class CloseXMLHelper
    {
        public static XLWorkbook ToExcel(this DataTable inDataTable)
        {
            var wb = new XLWorkbook();
            var dataTable = inDataTable;

            // Add a DataTable as a worksheet
            wb.Worksheets.Add(dataTable);
            return wb;
        }
    }

Then I just followed the documentation on the project for allowing a user to download the excel file. I already had the myDataTable variable in the below snippet. If you are wondering how to create a DataTable from a database, see this post: How to query a SQL database in C#?

    var httpResponse = Response;
    httpResponse.Clear();
    httpResponse.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    httpResponse.AddHeader("content-disposition", "attachment;filename=\"HelloWorld.xlsx\"");

    // Flush the workbook to the Response.OutputStream
    using (var memoryStream = new MemoryStream())
    {
        dataset.Tables[0].ToExcel().SaveAs(memoryStream);
        memoryStream.WriteTo(httpResponse.OutputStream);
        memoryStream.Close();
    }

    httpResponse.End();

It doesn’t get much more simple than this.

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: What 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# – Big O

  1. How to find the duplicate in an array using Big O of N?

C# – Open Ended Questions

  1. What design patterns do you use when developing? What design patterns do you hope to learn?
  2. What is the latest C# object or feature you have learned to use?
  3. Which areas of C# have your worked with? Which areas of C# have you not worked with?

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(&quot;File created or added: &quot; + inArgs.FullPath);
        }

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

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

        public void Watcher_Renamed(object sender, RenamedEventArgs inArgs)
        {
            Log.WriteLine(&quot;File renamed: &quot; + inArgs.OldFullPath + &quot;, New name: &quot; + 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. Right-click on the Service1.cs file and choose View Code.
  2. Change both the Name and the ServiceName to DirectoryMonitoringService. You can right-click on the file to rename. If that doesn’t rename the class, you can open the file, right-click on the class name and choose Refactor | Rename.
  3. Go to the code of the DirectoryMonitoringService.cs file (which was Service1.cs just a couple steps ago) in Visual Studio.
  4. Implement the constructor as follows:
using System.IO;
using System.ServiceProcess;

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

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

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

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

        protected override void OnStop()
        {
        }
    }
}

Step 5 – Create a Service Installer

  1. Right-click on DirectoryMonitoringService.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.
    Note: If you don’t have the Developer Command Prompt, you can open a normal command prompt as administration and get installUtil.exe from this path:

    c:\Windows\Microsoft.NET\Framework64\v4.0.30319\installutil.exe
  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#.

Updated: 7/25/2016

using System;
using System.IO;

namespace Rhyous.Logging
{
    public class Log
    {

        #region Singleton

        private static readonly Lazy<Log> Lazy = new Lazy<Log>(() => new Log());

        public static Log Instance { get { return Lazy.Value; } }

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

        #endregion

        public StreamWriter Writer { get; set; }

        public string LogPath
        {
            get { return _LogPath ?? (_LogPath = AppDomain.CurrentDomain.BaseDirectory); }
            set { _LogPath = value; }
        } private string _LogPath;

        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)
        {
            Instance.WriteLineToLog(inLogMessage);
        }

        public static void Write(string inLogMessage)
        {
            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