Wednesday, August 30, 2006

Exceptions

Exceptions

When throwing/handling exceptions you should be aware of a few things:

Take a look at the following code:

try

{

db.ExecuteNonQuery(dbCommandWrapper);

log.Debug("Executed: " + sqlCommand);

}

catch (SqlException ex)

{

throw new ApplicationException("Exception encountered while inserting data", ex);

}

Notice a few things:

* I am catching a specific exception instead of catching the generic Exception. So instead of catching all exceptions, just catch the exceptions that you intend to handle.
* I am throwing a new exception of type ApplicationException, and I am wrapping the original exception into the InnerException property. This accomplishes two things: It gives the caller the ability to handle exceptions of type ApplicationException instead of handling Exception or SqlException typed exceptions. The case for this is that if the business tier calls the data tier and the data tier encounters a SqlException, then either the data tier should handle the SqlException and don't throw it, or create a new exception and wrap the SqlException and throw this new exception to the business tier. This eliminates the need for the business tier to try to handle SqlException exceptions when the Data tier should handle the SqlException. Another point to note is that you should probably stay away from using the following throw commands: throw; throw ex; and throw new ApplicationException("some message"); as all three will overwrite any stack trace for the exception up to the point when the throw was executed, so all past stack traces before the throw was executed will be lost.

Thursday, August 24, 2006

Interesting discussions around Google's open API's

Discussions about who really owns your data on the web and how you can access your data here

Concurrency on the web

Lately, I've been noticing that more and more people are beginning to discuss concurrency and how it relates to the new multi core CPU's that are being released.

Kim Greenlee's blog post
Herb Sutter's article on concurrency
Musings about concurrency and manycore CPUs
Larry O'Brien

Most of the discussions center on how to design software to take advantage of multiple cores, and how to come up with an easy way to get developers interested in concurrency. Designing software to take advantage of multiple CPUs is familiar to most systems software engineers (operating systems, web servers, database servers, search engines), but most business applications are still designed to take advantage of a single CPU. Most business application developers are not familiar with concepts such as threading, synchronization, shared memory/data, deadlocks, etc. because the software that they build usually has the requirment that it perform one task at a time, in serial because there was never a requirement to run tasks in parallel. Even if there was a requirement to run tasks in parallel, it would probably be easier to install the system on a new machine and load balance both systems, since the cost of a new machine is less than the time/effort cost for the developer to redesign the system as a concurrent system.

From the business application developer standpoint there are two questions they will ask about concurrency: How can I split my application into different business processes that can run independently of one another? what's a thread? why would I use it? what's a lock? what's deadlock? All of these questions will need to get answered if the developer wants to take advantage of all of the computing power available to them. The questions around threads, locks, synchronization, etc. are easy to find answers to, there are lots of books/websites on the topic. The more difficult questions to answer are about how to divide applications into business processes that can run in parallel. Since every business application is different, there probably is no one right answer to this question, but I do feel that it is useful for developers to become familiar with how system engineers solve problems by programming for concurrency. Basically, I believe that we will start to see more and more design patterns that are used to solve concurrency problems. Martin Fowler's book: Patterns of Enterprise Application Architecture has a section on concurrency, and the book Data Access Patterns also has a section on concurrency, so these are two good places to start. For learning about multithreading, the book .NET Multithreading is a good one. There are a few frameworks that may make developing concurrent applications easier on the .NET platform:

Although not .NET-only, the framework OpenMP is another choice.

Tuesday, August 22, 2006

When the pros of using reflection outweigh the cons, you can take advantage of using it when iterating over properties of classes. To help with debugging, you can override the ToString() of your classes to return a string that contains the name of any public properties along with their corresponding values:

public override string ToString()
{
StringBuilder sb = new StringBuilder();
Type t = this.GetType();

PropertyInfo[] pInfo = t.GetProperties();

sb.Append(t.ToString() + "\r\n");

foreach (PropertyInfo p in pInfo)
{
string fmt = string.Format("{0} = {1}", p.Name, p.GetValue(this, null));

sb.Append(fmt + "\r\n");
}

return sb.ToString();
}

The function uses reflection to get the public properties of the class and it iterates over the collection of properties and builds a string that represents the state of the class. The string returned from ToString() would look like this:

Property1 = Value1
Property2 = Value2
.
.
.

The PropertyInfo.GetValue() function takes two parameters; the first parameter is the reference to this, while the second parameter is an object array that is used when the PropertyInfo references an indexed property. When using reflection to enumerate properties on a class that contains other classes, you must accomodate the case where a class might contain an indexed property:

public class Details
{
public Main.Model.DetailType this[int index]
{
get { return (Main.Model.DetailType) DetailCollection[index]; }
}
}

In this case, the Details class contains an indexer that is used to retrieve DetailType objects by index from the DetailCollection property. You can use the GetValue() function and pass in an object array that contains a single entry that is the value of the offset into the collection, which will reference the indexed item at that position within the collection.

public class Details
{
public override string ToString()
{
StringBuilder sb = new StringBuilder();

try
{
Type t = this.GetType();
string fmt;

PropertyInfo[] pInfo = t.GetProperties();


sb.Append(t.ToString() + "\r\n");

foreach (PropertyInfo p in pInfo)
{
if (p.Name == "Item")
{
for (int i = 0; i < Count; i++)
{
fmt = string.Format("{0} = {1}", p.Name, p.GetValue(this, new object[] { i }));
sb.Append(fmt + "\r\n");
}
}
else
{
fmt = string.Format("{0} = {1}", p.Name, p.GetValue(this, null));
sb.Append(fmt + "\r\n");
}
}
}
catch (Exception ex)
{
log.Error(ex.Message);
}

return sb.ToString();
}
}

The items in bold represent the changes to support the indexed properties. The Details class contains a DetailCollection class (which derives from ArrayList), and the Details class contains an indexer to retrieve an item from the collection as well as a property that returns the number of items stored in the collection. The modification looks for a property named Item in the Details class, and it then retrieves the count of objects in the collection and for each object in the collection it calls the GetValue(), passing in a reference to the Details class (this) and a new object[] array that contains a single member that stores the integer value of the item within the collection.

Tuesday, August 15, 2006

Retrieving class property values via reflection

Recently I was implementing some logging code for some legacy C# classes that contained many public properties. Instead of implementing each property in the overriden ToString() of the class, I decided to use reflection to get the list of properties and print out their values:


public override string ToString()
{
StringBuilder sb = new StringBuilder();
Type t = this.GetType();

PropertyInfo[] pInfo = t.GetProperties();

sb.Append(t.ToString() + "\r\n");

foreach (PropertyInfo p in pInfo)
{
string fmt = string.Format("{0} = {1}", p.Name, p.GetValue(this, null));

sb.Append(fmt + "\r\n");
}

return sb.ToString();
}

The code first gets the Type of the class that contains the properties. Then it retrieves an array of PropertyInfo objects that contains each property name and type. The GetValue method of the PropertyInfo class is used to retrieve the value of the property. It takes two arguments; the first argument is the pointer to the class that contains the property, and the second value is an object array in the case that the property is an indexed property (stores an indexed array). if the class does not contain any indexed properties, you can pass in null for the second parameter.

log4net setup for .NET 2.0

For some reason, even though setting up log4net is relatively simple, I always spend too much time trying to configure it for various types of applications (Web, Console, Web Service, Windows Service, Windows App), and after I figure it out, I forget to document what I did to get it working. Here's an attempt to do this.

Console Apps:
First, you need to download log4net. You can get it from the log4net Downloads page.

Once you've installed it, add a reference to it from your project that will perform the logging. The location of the log4net.dll for 2.0 on my machine is at C:\log4net\log4net-1.2.10\bin\net\2.0\release

Add a section in the configSections area of the hosting applications' app.config or web.config file:


<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>


Add the log4net configuration settings to the app.config:


<log4net>
<!-- RollingFileAppender looks after rolling over files by size or date -->
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="c:\\Logs\\RollingLogHelloWorld.log">
<param name="AppendToFile" value="true">
<param name="MaxSizeRollBackups" value="10">
<param name="MaximumFileSize" value="1000">
<param name="RollingStyle" value="Size">
<param name="StaticLogFileName" value="true">
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %-45c [%x] - %m%n">
</layout>
</appender>
<!-- FileAppender appends to a log and it is manually managed or size -->
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<param name="File" value="c:\\Logs\\LogHelloWorld.log">
<!-- Example using environment variables in params -->
<!-- <param name="File" value="${TMP}\\ApplicationKit.log"> -->
<param name="AppendToFile" value="true">
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n">
</layout>
</appender>
<!-- Setup the root category, add the appenders and set the default level -->
<root>
<level value="INFO">
<appender-ref ref="FileAppender"></appender-ref>
</level>
</root>
</log4net>


This configures log4net to use one or more appenders, either a RollingFileAppender or a FileAppender. The <root> element defines which file appender it will use.

The log files are created in the c:\Logs directory. Make sure that the process that hosts the classes that perform the logging (classes contained either within the exe or within a class library dll) has write access to the directory where files are created. For windows and console applications the user identity is the current logged in user that executes the console application. For windows services, the user identity is the user that the service is configured to run as. For ASP.NET applications, give the ASPNET user access Full control rights to the webroot folder (the physical folder location for the virtual directory of the app) for the application. This will allow the aspnet_wp.exe process to create/write/update the log file

You can also add a switch that will output log4net's debug information to the Visual Studio output debug window as an appSetting:


<appsettings>
<add key="log4net.Internal.Debug" value="true">
</add>
</appsettings>


If you have an AssemblyInfo.cs file in your project, you should add an entry to it which will configure the logging framework:


[assembly: log4net.Config.DOMConfigurator()]


Alternatively, you can put the initialization function into your code, you should execute the following line when the application first starts:

log4net.Config.XmlConfigurator.Configure();

In each class that will perform logging, add the following using statements:

using log4net;
using log4net.Config;

Add the following static member variable to each class, replacing <class name=""> with the name of the class:


private static readonly ILog log = LogManager.GetLogger(typeof (<class name="">));


when you want to log something, you can try this:


log.Info("Hello World.");

Friday, August 11, 2006

Good Read on writing maintainable code

here

Network Sequence Diagrams

I stumbled upon some HTTP and TCP sequence diagrams at the EventHelix site. They also have some interesting articles related to real time and embedded system design. You can find them here

Tuesday, August 01, 2006

Problems undeploying an assembly in BizTalk 2004

If you ever get this error when undeploying a pipeline or schema assembly in BizTalk 2004:

Some items in the removed assembly are still being used by items not
defined in the same assembly, thus removal of the assembly failed.
Make sure that items in the assembly you are trying to remove fulfill the
following conditions:

1. Pipelines, maps, and schemas are not being used by Send Ports or Receive
Locations
2. Roles have no enlisted parties.

Try the following:

Don't forget to write down what the current settings are, once you've undeployed and redeployed the assemblies, you'll need to update the settings that you changed to their original values.

* Change the send ports send pipeline in the Visual Studio BizTalk Explorer (Edit | Configuration | Send | General) to reference the default Microsoft.BizTalk.DefaultPipelines.PassThru
* Remove all outbound maps that are associated with the send port in the Visual Studio BizTalk Explorer (Edit | Configuration | Filters & Maps | Outbound Maps)
* Check that your roles do not have enlisted parties.

doing these steps should allow you to undeploy the assemblies.

This page is powered by Blogger. Isn't yours?