Mental Jetsam

By Peter Finch

Archive for November, 2008

Dynamically creating C# class instances using reflection.

Posted by pcfinch on November 27, 2008

Reflection, the ability for a program to dynamically inspect itself, is possibly one of the most powerful features of modern programming languages like C# and Java. The following is a simple example of how to interrogate the current C# assembly, locate all the classes that are derived from a base class, and then dynamically created and executed an instance of the class.

I wrote this code for a set of tests I wanted to implement. The idea was to make it simple to add new tests to the project by just adding new class derived from the base “Test” class. The program would then automatically find all the tests and run them.

  1. First, create the “Test” base class.
    abstract class Test {
      protected String m_sName ;
      public String name { get { return (m_sName) ; } }
      protected Test(String sName) { m_sName = sName; }
      abstract public void run() ;
    }

  2. Derive the actual tests from the “Test” base class.
    class UsersTest : Test {
      public UsersTest() : base("Test user names and passwords") { }
      override public void run() {
        // Test code does here
      }
    }

  3. To run the tests, first get the current Assembly, and find all the Types that are “Classes” and are derived from the class “Test”. Once you have the type you need to Dynamically create and instance of it. This method looks for the default constructor (the one with no parameters) and uses that, however, the code could look for any constructor if required. It then calls the contractor to
    create an instance of the class, and finally executes the classes run() method.
    Assembly asm = Assembly.GetExecutingAssembly();
    foreach (Type type in asm.GetTypes()) {
      if (type.IsSubclassOf(typeof(Test)) && type.IsClass) {
        ConstructorInfo ci = type.GetConstructor(new Type[] { });
        Test t = (Test)ci.Invoke(new Object[] { }) ;
        Console.Out.WriteLine ("Running Test - " + t.name);
        t.run();
      }
    }

This is a very simple example, and there are other ways to runs tests, but it is easy to see how this design could be extended and used in all sorts of situations.

Posted in C#.NET, Programming | 3 Comments »

Loading an SqlDataReader into a DataGridView

Posted by pcfinch on November 20, 2008

This is a simple example of how to load the results from an arbitrary SQL Query, contained in a SqlDataReader, into a DataGridView on a Windows Form (C# Client application). This is an example of a customised view and not an automatically generated one using the AutoGenerateColumns feature and it also demonstrates calling a SQL Server Stored Procedure from C#.

  1. Create the DataGridView object e.g. dgvTrials
  2. Add the Column names to the DataGridView using Visual Studio. For each of the columns set the DataPropertyName to the column name returned in the SQL query result set.
    Add Column to DataGridView
  3. Create the SQL Server stored procedure.
    IF OBJECT_ID('sys.sp_getTrialsByUser') IS NOT NULL
     DROP PROCEDURE [sys].sp_getTrialsByUser
    GO
    CREATE PROCEDURE [sys].sp_getTrialsByUser (@username varchar(50)) AS
    select distinct TRIAL_ID, START_DATE, END_DATE, BOOKACRONYM
        from [sys].TRIALS t
    	where t.USERNAME = @username ;
  4. Code up the SQL Query using a SqlConnection, SqlCommand and SqlDataReader and load the SqlDataReader results into a DataTable. Then bind the DataTable to the DataGridView.
    using (SqlConnection connection = new SqlConnection(sConnectString))
    {
      connection.Open();
      using (SqlCommand command = connection.CreateCommand())
      {
        command.CommandText = "[sys].sp_getTrialsByUser";
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add("@USERNAME", SqlDbType.VarChar, 50);
        command.Prepare();
        command.Parameters["@USERNAME"].Value = tbUserName.Text;
        SqlDataReader reader = command.ExecuteReader();
        using (reader)
        {
          DataTable table = new DataTable();
          table.Load(reader);
          dgvTrials.DataSource = table;
        }
      }
    }

Posted in C#.NET, Programming | 4 Comments »

Create nested SqlCommands on a single SqlConnection in C#

Posted by pcfinch on November 17, 2008

When trying to create multiple SqlCommand Objects on a single SqlConnection I got the following error.

There is already an open DataReader associated with this Command which must be closed first.

I was trying to use an SqlDataReader, from the first SqlCommand, and use the data in the records in that reader to perform another query by creating another [nested] SqlCommand object while the first reader was still running. After a little research the solution is very simple. Just add “MultipleActiveResultSets=True” to the connection string.

Data Source=server\PORTAL;Initial Catalog=mydb;User ID=user;Password=password;MultipleActiveResultSets=True

Warning… Don’t forget to Close() the inner SqlDataReader and Dispose() of the SqlCommand otherwise you may quickly run out of resources, or better still use the “using(…) { … }” statement. e.g.

using (SqlConnection connection = new SqlConnection(sConnectionString))
{
  connection.Open();
  using (SqlCommand command = connection.CreateCommand()) 
  {
    command.CommandText = @"
      select USERNAME from USERS where GROUP = @GID";
    command.Parameters.Add("@GID", SqlDbType.Int);
    command.Prepare();
    command.Parameters["@GID"].Value = nGroupId;
    using (SqlDataReader reader = command.ExecuteReader())
    {
      while (reader.Read())
      {
        String sUsername = reader.GetString(0); // USERNAME
        // ...
      }
    }
  }
}

Posted in C#.NET, Programming | Leave a Comment »

Simple IP/Hostname based security for C# web services.

Posted by pcfinch on November 10, 2008

The following code implements a simple IP / Hostname based security for a web service. If you need to restrict access to a C# web services there are a number of methods and the common one is to pass a username and password in the request. This works great until the username and password get “out in the wild” and then you have to change everything. Another common method is to use the web server serurity, but then the application does not have control.

The method described here just gets the incoming IP address of the client, for the web service, and then looks the IP address and / or the hostname up in the <appSettings> section on the web.config file. If the IP address or hostname is defined in the file, then the client is allowed access the service otherwise an error message can be returned.

using System.Configuration;
using System.Net; 

[WebMethod(Description = "Get the server date and time")]
public string GetDateTime()
{
  String sResponse = CheckClientAccess(HttpContext.Current.Request.UserHostAddress) ;
  if (String.IsNullOrEmpty(sResponse))
    sResponse = DateTime.Now.ToString();
  return (sResponse);
}

/// <summary>
/// Return empty string if access is granted otherwise return a error message.
/// </summary>
public String CheckClientAccess(String sClientIpAddress)
{
  String sResult = String.Empty;
  String sAccess = ConfigurationManager.AppSettings["ACCESS-" + sClientIpAddress];
  if (String.IsNullOrEmpty(sAccess) || (!sAccess.Equals("allow", StringComparison.OrdinalIgnoreCase)))
  {
    IPHostEntry host = Dns.GetHostEntry(sClientIpAddress);
    if ((host != null) && (!String.IsNullOrEmpty(host.HostName)))
    {
      String sHostname = host.HostName.ToLower();
      sAccess = ConfigurationManager.AppSettings["ACCESS-" + sHostname];
      if (String.IsNullOrEmpty(sAccess) || (!sAccess.Equals("allow", StringComparison.OrdinalIgnoreCase)))
        sResult = String.Format("Access from {0} \"{1}\"  denied", sClientIpAddress, sHostname) ;
    }
    else
      sResult  = String.Format("Access from {0} denied", sClientIpAddress) ;
  }
  return (sResult);
}

The settings in the web.config file are as follows.

<appSettings>
  <add key="ACCESS-127.0.0.1" value="allow"/>
  <add key="ACCESS-server23.domain.int" value="allow"/>
</appSettings>

This is not a perfect solution, and is not recommend for high security systems, but it’s simple to implement and pretty safe if you trust the incoming computers IP addresses and host names.

Posted in C#.NET, Programming | 2 Comments »