Friday, August 7, 2009

ASP.NET Error Logging with ELMAH

Debugging production code is always a challenge. From my experience I have used the Windows event logs and the Apache log4net so far.

Most of the time log4net is the solution for all my needs and I like how flexible it is. But they were situations where the logging solution was not enough. The real problem occurs if in your application you get unhandled exceptions. You know - database connection broken, network downtime, system software updates - it's in many ways possible to throw the application into confusion without having even the near idea where to look for. And this is where ELMAH comes to the rescue.

You can include ELMAH in your projects with a little effort and even with the default configuration you take benefits. ELMAH can log errors for you to different places - from xml files to database servers but the easiest way is to just store error messages into memory. ELMAH will give you a way to check for unhandled exceptions from special URL on your ASP.NET site.

Addiding ELMAH to a project



Having heard for ELMAH from Hanselminutes I decided to give a try.
There was a project under active development where new versions uploaded on the staging server very frequently, even many times a day.

After the download of the binaries I just added a reference to Elmah.dll into the project. Then following the instructions on the ELMAH documentation I made few additions to the Web.config file.

a/ I added to "configSections":


<sectionGroup name="elmah">
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
<section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
</sectionGroup>


b/ Then added into "httpHandlers":

<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />


c/ and at the end into "httpModules":

<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>




I also added another configuration option to enable opening the ELMAH views from remote connection, not only on the server, into section "configuration" I added:


<elmah>
<security allowRemoteAccess="yes" />
</elmah>


That was everything necessary to include ELMAH to the project.



Did I say - ELMAH is wonderful!



Having ELMAH included to the web application with this configuration, we have got the error logging information accessible at http://APPHOME/elmah.axd.

We put into the staging server only well unit-tested code. Once as we did changes on the database schema we have forgotten to patch the database where the staging server connects.

During the integration tests the application raised an exception. On the browser the exception information was not very helpful (see: yellow screen of dead). Into the log files generated by log4net there was nothing mentioned. Then we opened the ELMAH page and we saw the reason for the exception:




ELMAH is a tool to help you with any ASP.NET project. Use it right now.

Monday, August 3, 2009

ASP.NET Globalization

I just finished a project where one of the requirements was to localize completely the input the user gave and the output of values (numbers, date) sent back to the user.

There is a nice way in dot.NET to set current culture information on a thread. You can for example examine the Request.UserLanguages - which is an array of strings and shows you which locales and languages the browser accepted - and then prepare CultureInfo object and assign that object to CurrentThread.

That way you set culture info for every request on the webserver. You use later the culture info information from CurrentThread to parse the user input and to write back localized values to the user.

Set CultureInfo for CurrentThread



The very first step is to set the culture information on CurrentThread on per page request basis. To do so edit function Application_BeginRequest from file Global.aspx.cs.


protected void Application_BeginRequest(object sender, EventArgs e)
{
// you could use Request.UserLanguages
// to set appropriate culture information
System.Globalization.CultureInfo ci = …;
System.Threading.Thread.CurrentThread.CurrentCulture = ci;
}



Set ASP.NET AJAX in your Master Page or View Page



Edit file Site.Master (or the MasterPage or ViewPage where the ScriptManager is.
Set EnableScriptGlobalization attribute to "true". Insert bug-fix for Number.parseLocal


<form id="frm" runat="server">
<asp:ScriptManager
ID="ScriptManager1"
runat="server"
EnableScriptGlobalization="true">
<Services>
<asp:ServiceReference Path="~/WebServices/Service.asmx" />
...
</Services>
</asp:ScriptManager>

<script type="text/javascript">
Number.parseLocaleFixed = function(value) {
return Number.parseLocale(value.replace(' ', ' '));
}
</script>



Parse User Input in ASP.NET Ajax


To parse user input of numbers use Number.parseLocaleFixed() javascript function. To parse user input of date use Date.parseLocale() javascript function.
Example:


Var numb = Number.parseLocaleFixed(
document.getELementById(‘txtNumb’).value);



Parse user input in ASPX page



Use the Parse() functions of the expected type. Specify the culture info in Parse(). Take the culture info from CurrentThread.


DateTime dt = DateTime.Parse(s,
System.Threading.Thread
.CurrentThread.CurrentCulture);




Write localized Information to the page



To write localized values to the page use the culture information from CurrentThread:


<%= dt.ToString(“d”, System.Threading.Thread
.CurrentThread.CurrentCulture) %>


To write localized pattern for validation of date input field you can use something like:



CultureInfo ci = System.Threading.Thread
.CurrentThread.CurrentCulture;

// validation of date input
string dSeparator = ci.DateTimeFormat.DateSeparator;
if (dSeparator == ".") dSeparator = @"\.";
string dPatternExpr = String.Format(@"^(|[0-9]{{1,4}}{0}[0-9]{{1,4}}{0}[0-9]{{1,4}})$",
dSeparator);

valSigningDate.ValidationExpression = dPatternExpr;

// validation of number input
string nDecimalSeparator = ci.NumberFormat.CurrencyDecimalSeparator;
if (nDecimalSeparator == ".") nDecimalSeparator = @"\.";
string nPatternExpr = String.Format(@"^[-+]?[0-9]*{0}?[0-9]*$",
nDecimalSeparator);

valSinglePayment.ValidationExpression = nPatternExpr;



Atanas Hristov

Saturday, August 1, 2009

Using Entity Framework with SQLite - Installation

SQLite is a simple but powerful open source database engine which you can use among everything else at development time and later connect your application to database server at run time.

Tools I have found to be pretty helpful to administer SQLite databases are: SQLite Expert Personal and sqliteadmin.

To use SQLite with the Entity Framework you need ADO.NET Provider. A complete provider is System.Data.SQLite.

Download file SQLite-1.0.65.0-setup.exe and install to appropriate location. I used directory C:\Programme\SQLite.NET as installation directory. In subdirectory bin into the installation directory you'll find two libraries - "System.Data.SQLite.Linq.dll", "System.Data.SQLite.dll" - which you optionally can register into the global assembly cache (gacutil -I ). To connect the Entity Framework to SQLite database you'll need to add references to these two assemblies.

Now, there is a nice dot.NET project on MSDN - EFQuerySamples - which demonstrates the Entity Framework with the well known Northwind database. You can use that application to learn the syntax of the Entity Framework queries and even to see the generated SQL. Download the project and unzip the file.

To get the EFQuerySamples running against SQLite database, there is a supplement to the MSDN project - EFQuerySamples_SQLite. You need to copy from this over the original project the following files.

Having the two projects unzipped next to each other copy:


file EFQuerySamples_SQLite\App.config to EFQuerySamples\App.config
file EFQuerySamples_SQLite\Entity Framework Query Samples.csproj to EFQuerySamples\Entity Framework Query Samples.csproj
file EFQuerySamples_SQLite\DB\northwindEF.db to EFQuerySamples\DB\northwindEF.db
file EFQuerySamples_SQLite\Schemas\NorthwindEFModel.SQLite.ssdl to EFQuerySamples\Schemas\NorthwindEFModel.SQLite.ssdl


Open the Visual Studio solution from EFQuerySamples.

Add references to the assemblies System.Data.SQLite and System.Data.SQLite.Linq.

Open file App.config and add new DbProviderFactory:




<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SQLite"/>
<add name="SQLite Data Provider" invariant="System.Data.SQLite"
description=".Net Framework Data Provider for SQLite"
type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite, Version=1.0.65.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139"/>
</DbProviderFactories>
</system.data>



Take care of the Version in attribute type, make sure equals the version of the System.Data.SQLite.dll you downloaded.

Also in App.config there should be addition to section connectionStrings coming with the supplement project:



<connectionStrings>
<add name="NorthwindEF (SQLite)" connectionString="provider=System.Data.SQLite;metadata=Schemas\NorthwindEFModel.csdl|Schemas\NorthwindEFModel.msl|Schemas\NorthwindEFModel.SQLite.ssdl;Provider Connection String='Data Source=DB\northwindEF.db'"
providerName="System.Data.EntityClient" />


...



Now you can run the EFQuerySamples application, choose the SQLite connection and run the various examples.

Enjoy!

Atanas Hristov