Tuesday, April 12, 2011

log4net in .NET 4.0 C# applications (.NET client profile)

Today's morning I decided to implement logging in my WPF C# 4.0 application.
I choosed log4net http://logging.apache.org/log4net/ as one of the most popular loggers.
After I included log4net.dll as a reference, I got a compilation error

Could not resolve assembly "System.Web". The assembly is not in the currently targeted framework ".NETFramework,Version=v4.0,Profile=Client". Please remove references to assemblies not in the targeted framework or consider retargeting your project.

The exception is pretty understandable, is says that your target Framework must be Full .NET 4.0 Framework, not limited client profile as now. System.Web assembly is a server component and Microsoft has not included it in lightweight .NET Client profile.
But what if I don't want to target my solely client application for Full .NET 4.0 Framework profile? Yes, the solution is simple. Just recompile log4net without System.Web references, and you're done!

I hadn't found recompiled log4net, and decided to do it by myself. After removing references to System.Web and solving a couple of small problems described here or here, I finally managed to compile it.
Compiled release version can be found here (in my Google Docs), so you can start using it. It misses some stuff related to web, but usable in overall.



Example of simple C# logger follows:


public class Logger
{
       static log4net.ILog _log;

       public static void LogException(Exception ex)
       {
             if (_log == null)
             {
                    log4net.Config.XmlConfigurator.Configure();
                    _log = log4net.LogManager.GetLogger(typeof(Logger));
             }
             _log.Error(ex);
       }
}



To have it writing to a text file Log/log.txt (related to your executable), you should make your app.config file look like (max log file size is 10 Mbytes, once you hit the limit, new file log.txt.1 will be created and so on):


xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
             <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
       configSections>


       <log4net>
             <root>
                    <level value="All" />
                    <appender-ref ref="LogFileAppender" />
             root>

             <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender" >
                    <param name="File" value="Log\log.txt" />
                    <param name="AppendToFile" value="true" />
                    <rollingStyle value="Size" />
                    <maxSizeRollBackups value="10" />
                    <maximumFileSize value="10MB" />
                    <staticLogFileName value="true" />
                    <layout type="log4net.Layout.PatternLayout">
                           <conversionPattern value="%date %-5level - %message%newline" />
                    layout>
             appender>
       log4net>
configuration>



Thursday, March 31, 2011

How to specify connection string to SQL CE 4.0 for DbContext

Recently I've started playing with Entity Framework 4.1 RC.

I've faced a question on how to specify DbContext's connection string to SQL CE 4.0 at runtime. I managed to do it in app.config like this:



   
       
          name="MyContext"
          providerName="System.Data.SqlServerCe.4.0"
          connectionString="Data Source=C:\database.sdf;Encryption mode=platform default;password=123;" />
   


Assuming that my context is named MyContext.

But it appeared to be a difficult task if I don't want to store my connection string in config file. I wished to construct it on runtime to set a password. Passing Provider in connection string did not help.

The solution is to create Sql CE connection by the function from System.Data.SqlServerCe.dll (can be found in C:\Program Files\Microsoft SQL Server Compact Edition\v4.0\Desktop as follows:


            var connection = System.Data.SqlServerCe.SqlCeProviderFactory.Instance.CreateConnection();
            connection.ConnectionString = "Data Source=C:\database.sdf;Encryption mode=platform default;password=123;";


            
            var db = new MyContext(connection); // MyContext: DbContext




You also need to modify MyContext's constructor to pass connection to protected constructor of DbContext.