Saturday, January 12, 2008

Configure Log4Net To Log Different Files For Different Projects

Log4Net is a free logging helper running in .NET environment (ported from Log4j). By configuration setting you can log message to files, event log, console window, etc. The common usage is logging to one file, but you can also separate the log files for different projects if you want. Following configuration is an example to separate web UI project logs and backend class library logs:
  <log4net>
<appender name="RollingFileAppenderBackend" type="log4net.Appender.RollingFileAppender">
<file value="C:\inetpub\logs\Backend.log" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="100" />
<maximumFileSize value="1000KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d [%t] %-5p: %m%n" />
</layout>
</appender>
<appender name="RollingFileAppenderWebUI" type="log4net.Appender.RollingFileAppender">
<file value="C:\inetpub\logs\WebUI.log" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="100" />
<maximumFileSize value="1000KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d [%t] %-5p: %m%n" />
</layout>
</appender>
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<param name="Header" value="[Header]\r\n" />
<param name="Footer" value="[Footer]\r\n" />
<param name="ConversionPattern" value="%d [%t] %-5p: %m%n" />
</layout>
</appender>
<logger name="Backendlogger">
<level value="DEBUG" />
<appender-ref ref="RollingFileAppenderBackend" />
<appender-ref ref="EventLogAppender" />
<appender-ref ref="ConsoleAppender" />
</logger>
<logger name="UILogger">
<level value="DEBUG" />
<appender-ref ref="RollingFileAppenderWebUI" />
<appender-ref ref="ConsoleAppender" />
</logger>
</log4net>

Thursday, October 25, 2007

Javascript Random Text

Following javascript is to create some mock contacts for UI testing purpose:
    function createMockContacts(contactNumber) {
        var contacts = new Array();
        for (var i = 0; i < contactNumber; i++) {
            var contact = new Object();
            contact.Name = randomText(8);
            contact.Company = randomText(16);
            contact.Phone = randomText(9, "phone");
            contact.Email = randomText(9, "email");
            contact.Address = randomText(20);
            contacts.push(contact);
        }
        return contacts;
    }
    function randomText(length, type) {
        if ( type == "phone") 
            var chars = "1234567890";
        else 
            var chars = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        var text = "";
        for (var i = 0; i < length; i++) {
            text += chars.charAt(Math.floor(Math.random() * chars.length));
        }
        if (type == "email" && text.length > 3)
            text = text.slice(0, 3) + "@" + text.slice(3) + ".com";

        return text;
    }
Return is an array of javascript objects:
 contacts[0].Name = "7k15zlQQ"
 contacts[0].Company = "sTOX2EVFhsBXJFIn"
 contacts[0].Phone = "881414055"
 contacts[0].Email = "3Ic@Adu2N3.com"
 contacts[0].Address = "lN3kSwJCJC3m7gC8zdZy" 
 contacts[1].Name = "IZYkS3gI"
 ...

Thursday, October 11, 2007

.NET Repository Pattern

Domain Driven Design (DDD) attracts quite a lot of attentions in recent years. Repository pattern is one important pattern in DDD. It mediates between the domain and data mapping layers, or a simple delegation of responsibility away from the domain objects.

Consider reading GeoCode from database, we may have following code:
public class GeoCode
{
public double Latitude;
public double Longitude;
public GeoCode(double lat, double lon)
{
Latitude = lat;
Longitude = lon;
}

public GeoCode GetByPostalCode(string postalCode)
{
GeoCode gc = null;
string connectionString = "....";
string sqlQuery = "SELECT Latitude, Longitude FROM GeoCode WHERE PostalCode = @PostalCode";
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand DBCommand = new SqlCommand(sqlQuery, connection);
DBCommand.Parameters.AddWithValue("@PostalCode", postalCode);
using (SqlDataReader reader = DBCommand.ExecuteReader())
{
if (reader.HasRows)
{
gc = new GeoCode(Convert.ToDouble(reader["Latitude"]), Convert.ToDouble(reader["Longitude"]));
}
}
}
}
catch (Exception ex)
{
Logger.LogException(ex);
}
return gc;
}
}
Such code works but it's not flexible and it has direct dependency to the backend store. With repository pattern we need to declare an interface and have a separate implementation:
public class GeoCode
{
public double Latitude;
public double Longitude;
public GeoCode(double lat, double lon)
{
Latitude = lat;
Longitude = lon;
}
}

public interface IGeoCodeRepository
{
GeoCode GetByPostalCode(string postalCode);
}

public class SQLServerGeoCodeRepository : IGeoCodeRepository
{
private string ConnectionString;
public SQLServerGeoCodeRepository()
{
ConnectionString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
}
public SQLServerGeoCodeRepository(string connectionString)
{
ConnectionString = connectionString;
}

public GeoCode GetByPostalCode(string postalCode)
{
GeoCode gc = null;
string sqlQuery = "SELECT Latitude, Longitude FROM GeoCode WHERE PostalCode = @PostalCode";
try
{
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
connection.Open();
SqlCommand DBCommand = new SqlCommand(sqlQuery, connection);
DBCommand.Parameters.AddWithValue("@PostalCode", postalCode);
using (SqlDataReader reader = DBCommand.ExecuteReader())
{
if (reader.HasRows)
{
gc = new GeoCode(Convert.ToDouble(reader["Latitude"]), Convert.ToDouble(reader["Longitude"]));
}
}
}
}
catch (Exception ex)
{
Logger.LogException(ex);
}
return gc;
}
}
A wrapper class in service layer exposes all related functions:
public class GeoCodeService
{
private IGeoCodeRepository _repository;
public GeoCodeService(IGeoCodeRepository repository)
{
_repository = repository;
}

public GeoCode GetByPostalCode(string postalCode)
{
return _repository.GetByPostalCode(postalCode);
}
}

class Program
{
static void Main(string[] args)
{
IGeoCodeRepository repository = new SQLServerGeoCodeRepository();
GeoCodeService service = new GeoCodeService(repository);
GeoCode gc = service.GetByPostalCode("A1A1A1");
}
}
With repository pattern we can easily extend current implementation. For example, if we need to use web service to get the geo code, we can simply add a new implementation without changing any existing code:
public class WebServiceGeoCodeRepository : IGeoCodeRepository
{
private string WebServiceUrl;
public WebServiceGeoCodeRepository()
{
WebServiceUrl = ConfigurationManager.AppSettings["WebServiceUrl"];
}
public WebServiceGeoCodeRepository(string webServiceUrl)
{
WebServiceUrl = webServiceUrl;
}

public GeoCode GetByPostalCode(string postalCode)
{
GeoCode gc = null;
//Get GeoCode by web service
return gc;
}
}

public class Program
{
static void Main(string[] args)
{
IGeoCodeRepository repository = new WebServiceGeoCodeRepository();
GeoCodeService service = new GeoCodeService(repository);
GeoCode gc = service.GetByPostalCode("A1A1A1");
}
}
The other advantage of using repository pattern is the testability. For example we can create a fake data repository:
public class FakeGeoCodeRepository : IGeoCodeRepository
{
public GeoCode GetByPostalCode(string postalCode)
{
GeoCode gc = null;
double fakeCode = 111.111;
if (postalCode.StartsWith("A", StringComparison.InvariantCultureIgnoreCase))
fakeCode = 123.123;
gc = new GeoCode(fakeCode, fakeCode);
return gc;
}
}
The unit test becomes simple:
 [TestMethod()]
public void GetByPostalCodeTest()
{
IGeoCodeRepository repository = new FakeGeoCodeRepository();
GeoCodeService target = new GeoCodeService(repository);
string postalCode = "M1M1M1";
double expected = 111.111;
GeoCode actual;
actual = target.GetByPostalCode(postalCode);
Assert.AreEqual(expected, actual.Latitude);
Assert.AreEqual(expected, actual.Longitude);

postalCode = "A1A1A1";
expected = 123.123;
actual = target.GetByPostalCode(postalCode);
Assert.AreEqual(expected, actual.Latitude);
Assert.AreEqual(expected, actual.Longitude);
}
Related topics:
http://martinfowler.com/eaaCatalog/repository.html
http://martinfowler.com/articles/injection.html

Wednesday, September 26, 2007

ASP.NET Impersonate Application Pool Account To Access Database

In an ASP.NET web application, we use a fixed account to connect to SQL server. Although we could encrypt the user name and password in the connection string, admin still suggested to use Windows Authentication so that there's no any user credential information stored in the file system.

One simple way to achieve that is create an application pool for the web app with a service account, and grant the permission for that service account inside the SQL server, then wrap all ADO.NET code inside a System.Web.Hosting.HostingEnvironment.Impersonate() block:
    using (System.Web.Hosting.HostingEnvironment.Impersonate())
{
using (SqlConnection connection = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand(spStoredProcedureName, connection);
//... other ADO.NET code
}
}

Thursday, August 02, 2007

Array.ConvertAll and List.ConvertAll

Just noticed this handy method:
using System;
using System.Collections.Generic;

class Test
{
static void Main()
{
int[] numbers = new int[] { 65, 66, 67 };
char[] chars = Array.ConvertAll(numbers, delegate(int number)
{ return (char)number; });

//Print "ABC"
Array.ForEach(chars, delegate(char ch) { Console.Write(ch); });

Console.WriteLine();
List<int> numberList = new List<int>(numbers);
List<char> charList = numberList.ConvertAll(delegate(int number)
{ return (char)number; });

//Print "ABC"
charList.ForEach(delegate(char ch) { Console.Write(ch); });

Console.Read();
}
}

Saturday, July 07, 2007

Singleton Pattern - A Logger Example

The idea of a singleton is to have a class that has only one instance and a global point of access to the instance. Following code is a simple singleton C# implementation:
public class Singleton
{
private static Singleton instance = new Singleton();

private Singleton() { }

public static Singleton GetInstance()
{
return instance;
}
}
The above implementation creates a new static instance during the class initialization. The singleton instance is retrieved by a static GetInstance method. An alternative is expose the singleton object by read-only property without a setter. The code needs a little bit change if a lazy creation is required:
public class Singleton
{
private static volatile Singleton instance;
private static object syncObj = new Object();

private Singleton() {}

public static Singleton GetInstance()
{
if (instance == null)
{
lock (syncObj)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
SyncLock in above code is for thread-safe consideration. In addition, the singleton class could be sealed if you don't like people to inherit from it and break the singleton principle.

Singleton pattern is very useful in some use cases. Here's a real life example. I needed a file logger for a simple web service application used in a small company. Enterprise library, logging application block, and even log4Net are just too heavy for such small application. In addition, the client is rejective to third-party tools.

I decided to write a file logger by myself. A stream writer was used, but I don't want multiple instances of stream writers being created and used at the same time. The IO is expensive and multiple accesses to a single file is not safe. Singleton came to play and only one instance of logger and one stream writer is created:
using System;
using System.IO;
using System.Configuration;
using System.Diagnostics;

class Program
{
static void Main(string[] args)
{
Logger.WriteLog("Jus a test.");
Logger.WriteLog(LogSeverity.Info, "Another test.");
Console.Read();
}
}

// A helper static class to get access the logger
public static class Logger
{
private static readonly FileLogger _logger = FileLogger.GetInstance();

public static void WriteLog(String log)
{
_logger.Write(log);
}
public static void WriteLog(LogSeverity logLevel, String log)
{
_logger.Write(logLevel, log);
}
}

// Enumeration for log severity
public enum LogSeverity { Error, Warning, Info, Debug };

// FileLogger class with Singleton pattern
internal sealed class FileLogger : IDisposable
{
private static FileLogger _instance = null; // Singleton object
private static object _syncLock = new object(); // Sync lock

internal StreamWriter _writer; // Stream writer writting to the log file
internal string _path = "C:\\Logs"; // Default folder
internal string _absolutePath; // C:\Logs\MachineName.log
internal string _fileName; // MachineName.log
internal int _logFileSize = 2; // New log file when its size bigger than 2 MB
internal LogSeverity _defaultSeverity = LogSeverity.Error; // Default severity

// Private constructor
private FileLogger()
{
GetConfigSettings();

_fileName = string.IsNullOrEmpty(Environment.MachineName) ?
"LogFile.log" : Environment.MachineName + ".log";
_absolutePath = _path + "\\" + _fileName;

if (!Directory.Exists(_path))
{
Directory.CreateDirectory(_path);
}

_writer = new StreamWriter(_absolutePath, true);
}

// Public static method to get Singleton object
public static FileLogger GetInstance()
{
if (_instance == null)
{
lock (_syncLock)
{
if (_instance == null)
{
_instance = new FileLogger();
}
}
}
return _instance;
}

// Check if the log file exceeds the maximum size
private void CheckFileSize()
{
if (_writer.BaseStream.Length >= (_logFileSize * 1024 * 1024))
{
this.Dispose();
string backupFile = string.Format("{0}\\{1}-{2}.log",
_path, Environment.MachineName, DateTime.Now.ToString("yyyyMMdd-HHmmsss"));
try
{
while (File.Exists(backupFile))
{
backupFile = backupFile.Replace(".log", "_1.log");
}
File.Move(_absolutePath, backupFile);
this.Dispose();
_writer = new StreamWriter(_absolutePath, true);
}
catch (Exception ex)
{
WriteToEventLog(ex.Message);
}
}
}

// Get default setting from configuraiton file
private void GetConfigSettings()
{
string appSetting = ConfigurationManager.AppSettings["FileLogger_Path"];
if (!string.IsNullOrEmpty(appSetting))
{
_path = appSetting;
}
int maxFileSize;
appSetting = ConfigurationManager.AppSettings["FileLogger_MaxFileSizeInMB"];
if (!string.IsNullOrEmpty(appSetting) && int.TryParse(appSetting, out maxFileSize))
{
_logFileSize = maxFileSize;
}
appSetting = ConfigurationManager.AppSettings["FileLogger_DefaultSeverity"];
if (!string.IsNullOrEmpty(appSetting))
{
try
{
_defaultSeverity = (LogSeverity)Enum.Parse(typeof(LogSeverity), appSetting);
}
catch (Exception ex)
{
WriteToEventLog(ex.Message);
}
}
}

// Clean up the stream writer
public void Dispose()
{
lock (_syncLock)
{
if (_writer != null)
{
_writer.Dispose();
}
}
}

// Write with default log severity
public void Write(string msg)
{
Write(_defaultSeverity, msg);
}

// Write message to log file
public void Write(LogSeverity logSeverity, string msg)
{
lock (_syncLock)
{
try
{
if (_writer.BaseStream == null)
{
_writer = new StreamWriter(_absolutePath, true);
}
CheckFileSize();
_writer.WriteLine("[{0}] at {1} -- {2}",
logSeverity.ToString(), DateTime.Now.ToString(), msg);
_writer.Flush();
}
catch (Exception ex)
{
WriteToEventLog(ex.Message);
}
}
}

private void WriteToEventLog(string message)
{
string source = "Logger";
string log = "Application";

try
{
if (!EventLog.SourceExists(source))
EventLog.CreateEventSource(source, log);

EventLog.WriteEntry(source, message, EventLogEntryType.Error);
}
catch { }
}
}

Thursday, May 10, 2007

.NET Interface Serialization Issue

Interface can not be serialized or de-serialized. That's because interface is just a contract not detailed implementation. However, in some cases, we do want to expose interface so objects are not restricted by a specific type.

Look at a simple example:
    public interface IPriceable
{
double GetPrice();
}
[Serializable]
public class ProductA : IPriceable
{
public double GetPrice()
{
return 123.345;
}
}

[Serializable]
public class ProductB : IPriceable
{
public double GetPrice()
{
return 234.567;
}
}

[Serializable]
public class PromotionPackage
{
public List<IPriceable> Items = new List<IPriceable>();
double GetPromotePrice()
{
//return PromotionCaculator.GetPrice(_items);
return 567.89; ;
}
}
The PromotionPackage contains a list of IPriceable objects (ProductA, ProductB etc.). Everything is okay except that an exception will be thrown when we serialize the PromotionPackage object:
{"Cannot serialize member PromotionPackage.Items of type IPriceable because it is an interface."}
A workaround would be wrapping the interface to an abstract class:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

public class Program
{
public interface IPriceable
{
double GetPrice();
}

[XmlInclude(typeof(ProductA))]
[XmlInclude(typeof(ProductB))]
public abstract class ProductBase : IPriceable
{
public abstract double GetPrice();
}

[Serializable]
public class ProductA : ProductBase
{
public override double GetPrice()
{
return 123.345;
}
}

[Serializable]
public class ProductB : ProductBase
{
public override double GetPrice()
{
return 234.567;
}
}

[Serializable]
public class PromotionPackage
{
public List<ProductBase> Items = new List<ProductBase>();
double GetPromotePrice()
{
//return PromotionCaculator.GetPrice(_items);
return 567.89; ;
}
}

static void Main(string[] args)
{
PromotionPackage package = new PromotionPackage();
package.Items.Add(new ProductA());
package.Items.Add(new ProductB());

string xmlString = string.Empty;
XmlSerializer serializer = new XmlSerializer(typeof(PromotionPackage));

// Serialize
using (StringWriter sw = new StringWriter())
{
serializer.Serialize(sw, package);
xmlString = sw.ToString();
}

// De-serialize
PromotionPackage newPackage = null;
using (StringReader sr = new StringReader(xmlString))
{
XmlTextReader reader = new XmlTextReader(sr);
newPackage = (PromotionPackage)serializer.Deserialize(reader);
}

Console.WriteLine("Done.");
Console.Read();
}
}

Saturday, May 05, 2007

A Managed Way To Serialize & Deserialze DateTime field

public class MyEvent
{
public string Name;

[XmlIgnore]
public DateTime Time;
[XmlElement("Time")]
public string TimeString
{
get { return Time.ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture); }
set { Time = DateTime.ParseExact(value, "yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture); }
}

public MyEvent() { }
public MyEvent(string name, DateTime time)
{
Name = name;
Time = time;
}

static void Main(string[] args)
{
MyEvent evt = new MyEvent("event1", new DateTime(2007, 5, 5));

XmlSerializer serializer = new XmlSerializer(typeof(MyEvent));
TextWriter writer = new StreamWriter(@"c:\event.xml");
serializer.Serialize(writer, evt);
writer.Close();
}
}
Here TimeString is exposed as a public property. Can we make it private? The answer is yes, but it requires the DataContract new in .NET 3.0:
[DataContract]
public class MyEvent
{
[DataMember]
public string Name;

public DateTime Time;

[DataMember(Name="Time") ]
private string TimeString
{
get { return Time.ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture); }
set { Time = DateTime.ParseExact(value, "yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture); }
}

public MyEvent(string name, DateTime time)
{
Name = name;
Time = time;
}

static void Main(string[] args)
{
MyEvent evt = new MyEvent("event1", new DateTime(2007, 5, 5));

DataContractSerializer serializer = new DataContractSerializer(typeof(MyEvent));
XmlWriter writer = XmlWriter.Create(@"c:\event.xml");
serializer.WriteObject(writer, evt);
writer.Close();
}
}

Monday, April 16, 2007

.NET Class Library Get Configuration File

A class library is used by different kind of applications, like a test console, a WinForm or Web applications. And the class library needs to read a configuration file at run time. How to do that? The common way is copy the configuration file to the folder where the class library assembly is sitting. Then the configuration file can be located by reflection at run time. But this doesn't work in ASP.NET web site environment because of the .NET dynamic compilation process. One resolution is to handle the path differently in web environment. Let's say if We have a convention of copying the configuration file to the root folder of web site, then the code to retrieve the full path of configuration file is like:
    public static string GetConfigurationFile(string fileName)
{
string asmLocation = Assembly.GetExecutingAssembly().Location;
string asmFolder = asmLocation.Substring(0, asmLocation.LastIndexOf(@"\"));
string fileFullPath = asmFolder + @"\" + fileName;

// Fix the temporary folder issue when running in web environment
if (fileFullPath.Contains(@"\Microsoft.NET\Framework"))
{
fileFullPath = System.Web.Hosting.HostingEnvironment.MapPath("/") + fileName;
}

return fileFullPath;
}
(Updated 2008/2) Another easy way to get configuration file is using AppDomain.CurrentDomain.SetupInformation.ConfigurationFile property which maps to app.config for Cosole/WinForm applications, and maps to web.config in ASP.NET.

Tuesday, April 03, 2007

StringDictionary, NameValueCollection, Dictionary<TKey, TValue> and KeyedCollection<TKey, TItem>

How to store key/value data in .NET?

DictionaryEntry in .NET 1.0 and generic KeyValuePair<TKey, TValue> in .NET 2.0 both store key/value pair inside a struct (not class). How about many KeyValue pairs? One solution is to put Key/value objects inside a collection like Generic List. But there's a major problem of such use: search by key is expensive and you need to loop through the whole collection. HashTable is fast in search but it's limited to string/object pair, and it's not strongly typed.

Are there any out-of-box strongly-typed collections for key/value objects?

If the key and value both are strings, StringDictionary and NameValueCollection are options. They have been available since .NET 1.0 and both are under System.Collections.Specialized name space. The difference is that NameValueCollection can have duplicate keys (multiple values for the same key are allowed).

In .NET 2.0 we have generic Dictionary<TKey, TValue> that is efficient and easy to use. More importantly the key and value objects can be of any types, and are strongly typed. But one issue of generic dictionary is that it can not be serialized directly. Paul Welter provided a SerializableDictionary solution for the problem but it's just a workaround. The other drawback of generic dictionary is that index accessing is not supported.

Generic KeyedCollection<TKey, TItem> under System.Collections.ObjectModel name space does not have those two issues on generic dictionary. KeyedCollection<TKey, TItem> supports index and key search, just like a hybrid version of generic List and Dictionary. But KeyedCollection<TKey, TItem> is just an abstract class, and you have to inherit from it and implement at least one abstract method to tell what's the key in each object inside the collection:
protected abstract TKey GetKeyForItem(TItem item);
Following is a demo of how to use KeyedCollection, where the EmployeeCollection uses employee number as a key:
using System;
using System.Text;
using System.Collections.ObjectModel;

class Program
{
static void Main()
{
EmployeeCollection ec = new EmployeeCollection();
ec.Add(new Employee("123456", "Rob", 40));
ec.Add(new Employee("234567", "Steve", 45));

bool contained = ec.Contains("123456");
ec["123456"].Age = 44;
ec[1].Age = 45;

Console.Read();
}
public class Employee
{
public Employee(string empNumber, string name, int age)
{
EmployeeNumber = empNumber;
Name = name;
Age = age;
}
public string EmployeeNumber;
public string Name;
public int Age;
// other properties and memebers
}

public class EmployeeCollection : KeyedCollection<string, Employee>
{
protected override string GetKeyForItem(Employee item)
{
return item.EmployeeNumber;
}
}
}