Category: HowTo

short tutorials

TT files – generate enum from database

Many times you will program against a table that contains something like an enum , like Status( open=1 , close=2, sent=3, approved=4 )  .

It is peculiar to wrote those status as text in the other tables – and you do not like also to have update their codes in the C# (VB.NET) code source each time you will add another one.

Rather , it is convenient to auto-generate from database at once.

But how to do it in Visual Studio ? The answer is .tt files – the files that generates also POCO

So here it is my own template for such enum from database .

To use ,unzip, add to your project that contains the edmx and do what is says below- and you will see as many  .cs file as tables want to put.

<#
//*********************************************************
//
//    NO Copyright .Use at your own risk.
//    Please modify :
//    1) the names of tables to generate enums : string nameforenum
//    2) the connection to the database : string connectionstring
//    3) the name of the model : string inputFile
//    Then save the file and you will have an enum …
//*********************************************************
#>

GenerateEnum

My standard way to work with dropdown box in ASP.NET MVC – 2 steps (or 3 if you want to add long description)

I have written a small post about dropdownlist template in ASP.NET MVC here : http://msprogrammer.serviciipeweb.ro/2010/05/30/mvc-helper-templates/

I think that the dropdownlist should be explained more – aand the example will be :

First, let’s say we have Employee and Department. And we have Employee that has a field, named IDDepartment.

When edit/create a user we want to display a dropdownlist for Department in order for the user to choose the department.

Step 1 : obtain from database a list of departments and transform into List<KeyValuePair<string,string>>  – where the first string is DepartmentID and the second is Department Name.

Let’s say there is a method to do that : deptList.Values

Step 2 : display into the aspx/ascx file with List_KVP template

<%: Html.EditorFor(model => model.deptList.Values, “List_KVP”, “IDDepartment”, new { SelectedValue = Model.emp.IDDepartment })%>

Here is the weak part: the “IDDepartment” is not strongly typed. You can transform that …but it requires writing another extension. However, when you modify the code for

SelectedValue = Model.emp.IDDepartment

it is right nearby…

For reference, here is the List_KVP.ascx

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<List<System.Collections.Generic.KeyValuePair<string,string>>>" %>
<%
    string Val = "",style="";
    if(ViewData.Values != null && ViewData.Values.Count > 0)
    {
        Val = (ViewData["SelectedValue"]??"").ToString();
        style = (ViewData["Style"] ?? "").ToString();
    }
    if (style.Length > 0)
    {

    }
    var id=ViewData.TemplateInfo.GetFullHtmlFieldId("") ;
    id = id + "";
    %>

<select id="<%:id %>" name="<%:ViewData.TemplateInfo.GetFullHtmlFieldName("") %>" style="<%: style %>">
    <% foreach (var val in Model)
       { %>
            <option  value='<%: val.Key %>' <%:(val.Key == Val)?"selected=selected":"" %>><%: val.Value %></option>
    <%} %>
</select>
<% if(Model.Exists(x=>x.Key ==Val) )
{
       %>
       <script type="text/javascript">
   $(document).ready(function () {

       $('#<%:id  %>').change();
   }     );
      </script>
      <%
}
    %>

Oh, and if you ask how to add a description , nothing more simple :
Step1 : add to dropdown an onchange event : onchange=’javascript:funcDepartmentRetrieve(this)”
Step 2: create a java script function that retrieves the long description from the id

 <script type="text/javascript">
         <%: Html.JavaScriptFind( Model.deptList.LongDescriptionValues, "funcDepartmentLong","notfoundDepartment") %>
        </script>
  

Step 3 : Mix the 2 javascript functions

For your reference, the code for JavaScriptFind is

 public static MvcHtmlString JavaScriptFind(this HtmlHelper hh, ICollection<KeyValuePair<string,string>> values, string Name, string NotFound)
        {
            string s = "function " + Name + "(value){  switch(value){";
            string ret = "case '{0}' : return '{1}';" + Environment.NewLine;
            foreach (var item in values)
            {
                //TODO : compensate for '
                s += string.Format(ret, item.Key, item.Value);
            };
            s += string.Format("default : return '{0}' ;//+ value;"  + Environment.NewLine, NotFound);
            s += "};";//switch
            s += "}";//function
            return MvcHtmlString.Create(s);
        }

ASP.NET MVC pass data from a view to master

One of recurring questions in MVC is how to share data between views and master. The question must be reformulated : how to share data between ACTION and master.

The short answer is : Model of the View returned from Action have to put some data to the Model of the Master

The long answer here in 4 steps

Step 1: ensuring error.aspx page works fine

a)copy \Views\Shared\Site.Master into siteerror.master( the error.aspx inherits from a specialized model)

b) change in \Views\Shared\Error.aspx

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<System.Web.Mvc.HandleErrorInfo>" %>

to

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/SiteError.Master" Inherits="System.Web.Mvc.ViewPage<System.Web.Mvc.HandleErrorInfo>" %>

Step 2 : make the master strongly typed :

add a ModelMaster class

public class ModelMaster
{
public ModelMaster()
{
DataFromAction = "default data";
}
public string DataFromAction { get; set; }
}
 

and display this data to the html of \Views\Shared\Site.Master

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<MasterDataFromAction.Models.ModelMaster>" %>

//code

<h1>This is data shared from View : <%= Model.DataFromAction%></h1>

Step 3. Make the action return a strongly typed view. We will make , for example, the Index action from Home controller.

Add the ViewModelIndex class

public class ViewModelIndex :ModelMaster
{
public ViewModelIndex()
: base()
{
base.DataFromAction = "data from index";
}
}

and modify controller action and view

First Index action in \Controllers\HomeController.cs

public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
ViewModelIndex vmi = new ViewModelIndex();
vmi.DataFromAction = "here comes data from index action";
return View(vmi);
}
 

Then the view :

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MasterDataFromAction.Models.ViewModelIndex>" %>

The result is here :

When do you do this things? The sooner, the better 😉

Please find attached the project

ASP.NET MVC editing fast a property

There are some moments when you want to fast edit a property ( like a status or a name) and you do not want to load the entire “Edit” form for this.More, you are in an edit formula and do not want to add a form.

So here is the solution in ASP.NET MVC  with jquery-1.4.2.min , jquery-ui-1.8.1.custom.min for a modal dialog and some controllers. The most difficult were the javascript, so I let to the final.

We will be editing the name for an employee in 4 steps.The most difficult to understand is the step 4(javascript) , however, it can be re-used with any other object- so you can put it in a common js file.

Step 1

create a view for editing the name , named FastEditEmp


<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<BusinessLogic.Employee>" %>
<!-- edit inline the name -->
<%= Html.HiddenFor(Model=>Model.ID) %>
<%= Html.LabelFor(model=>model.Name) %>
<%= Html.EditorFor(model=>model.Name) %>

Step 2

Create the controllers and verify it works – at least the get  action .


public ActionResult FastEditEmp(int id)
 {
 var emp=EmployeeList.LoadFromID(id);
 return View(emp);
 }
 [HttpPost]
 public ActionResult FastEditEmp(BusinessLogic.Employee emp)
 {
 try
 {

 var dbid = EmployeeList.LoadFromID(emp.ID);
 UpdateModel(dbid);
 dbid.Save();
 return new JsonResult() { Data = new { ok = true, message = "succes" } };

 }
 catch (Exception ex)
 {
 //TODO : log
 return new JsonResult() { Data = new { ok = false, message = "error : " + ex.Message } };

 }
 }

Step 3
Create the hyperlink to edit the name of an employee (emp) :

<a href=’javascript:EditModal(<%= emp.ID%>,”<%=Url.Action(“FastEditEmp”,new {id=emp.ID}) %>”)’>Edit name</a>

Step 4

This is the most difficult one, the javascript. However, more of the code is common no matter what you want to edit fast modal :


var wait = '<%= ResolveUrl("~/Content/Images/wait.gif") %>';
function EditModal(empID,url)
{
// load a please wait dialog
 var $dialog1 = $('<div></div>')
 .html("Loading data <br /> <img src='" + wait + "'></img>")
 .dialog({ autoOpen: false,
 title: 'please wait'
 });
 $dialog1.dialog('open');
// so the please wait dialog was shown to the user. Now load the content of the action specified in url
 $.get(url,
 {
 ID: empID
 },
 function(txt) {

 var $dialog = $('#dialog');
 $dialog.html('');
 $dialog.html(txt)
 .dialog({
 autoOpen: false,
 title: 'Edit',
 modal: true,
 show: 'blind',
 hide: 'explode',
 closeOnEscape: false,
 buttons: {

 "Close": function() {
//just cleanup - no saving
 var allInputs = $(":input:not(:button)");
 var ser = allInputs.serialize();
 allInputs.remove();
 allInputs.empty();
 $(this).dialog("close");
 $(this).dialog('destroy');

 },
 "Save": function() {
//now saving data : serializing and posting
 var allInputs = $(":input:not(:button)");
 var ser = allInputs.serialize();
 allInputs.remove();
 allInputs.empty();

 window.alert(ser); -- debug mode
 $(this).dialog('close');
 $(this).dialog('destroy');
//saving data by posting to same url!
 $.post(url,
 ser,
 function(text) {
 $(this).dialog("close");
 $(this).dialog('destroy');
 if (text.ok) {

 window.alert("Saved - you can change here the display id with jquery");
 window.location.reload(true);
 }
 else {
 window.alert(text.message);
 }

 }
 );

 }

 }

 });

 $dialog1.dialog('close');//closing the wait dialog
 $dialog.dialog('open'); // show main editing dialog
 });

}

 </script>

As always, please find here the saving modal files. Please execute first the emp.sql file, then modify the connection string into the web.config .

Asp.NET MVC and DOS – re-using the ViewModels

(Please read first : http://msprogrammer.serviciipeweb.ro/2010/03/29/asp-net-mvc-orm-and-viewmodels/ )

One of the biggest challenges in programming was write once- GUI everywhere ( Ok, ORM impedance mismatch is another story)

I mean by that re-using the logic from an application in another application. ASP.NET MVC , with the commitment to strongly viewmodels, make me think that it will be now easier to transfer the viewmodels to an console application.

Let’s see the usual Employee-Department and creation.

First the Database :

Then the ViewModel for creating an employeeand for list of employees


public class ViewModelEmployee
 {
 public static DepartmentList ListOfDepartments
 {
 get
 {
 //TODO : put this into cache to not load every time
 DepartmentList dl = new DepartmentList();
 dl.Load();
 return dl;
 }
 }
 }
 public class ViewModelEmployeeCreate : ViewModelEmployee
 {
 public Employee emp = new Employee();

 public static void SaveNew(Employee emp)
 {
 emp.SaveNew();
 }
 }
 public class ViewModelEmployeeList : ViewModelEmployee
 {
 public EmployeeList employees;
 public void Load()
 {
 employees = new EmployeeList();
 employees.Load();
 }
 }

And now the magic :

ASP.NET MVC DOS

[HttpPost]
 public ActionResult Create(Employee emp,long DepartmentID)
 {
 try
 {

 emp.Department = new Department() { ID = DepartmentID };
 ViewModelEmployeeCreate.SaveNew(emp);

 return RedirectToAction("Index");
 }
 catch(Exception ex)
 {
 ModelState.AddModelError("", ex.Message);
 return View(new ViewModelEmployeeCreate(){emp=emp});
 }
 }


Console.WriteLine("choose department");
 var listdep=ViewModelEmployee.ListOfDepartments;
 foreach (var item in listdep)
 {
 Console.WriteLine(item.ID + ")" + item.Name);

 }
 string s=Console.ReadLine();
 long DepartmentID;
 if (!long.TryParse(s, out DepartmentID))
 {
 Console.WriteLine("exit : not a long :" + s);
 return;
 }
 if (!listdep.Exists(item => item.ID == DepartmentID))
 {
 Console.WriteLine("not a valid id:" + s);
 return;
 }
 Employee emp = new Employee();
 emp.Department = new Department() { ID = DepartmentID };
 Console.Write("employee name ?");
 emp.Name= Console.ReadLine();
 ViewModelEmployeeCreate.SaveNew(emp);

Now for listing employees:

ASP.NET MVC DOS
public ActionResult Index()
        {
            ViewModelEmployeeList vmel = new ViewModelEmployeeList();
            vmel.Load();
            return View(vmel);
        }

  ViewModelEmployeeList vmel = new ViewModelEmployeeList();
            vmel.Load();
            foreach (var item in vmel.employees)
            {
                Console.WriteLine(item.Name);
            }

As you can see , the codes are really similar ( although the console application is filled with first verification and the MVC is not )

Please download the application from testaddropdownlist

To install : run the emp.sql file, change in the app.config/web.config the connection string to point to the real database/sql server.

Summary : This simple application shows how to re-use ViewModels from an ASP.NET MVC and a DOS Console Application

Homework : Add  WindowsForms application and do the same.

EF , automatic history of table and T4 files (TT files)

Usually the data of the tables should be tracking for who modified it.

Think about inserting/updating/deleting an employee :   you must know who did those actions and when. So you create another table, identically as structure, and you add another 3 fields , such as [ModifiedDate](when), [ModifiedBy](who), [ModifiedType] (what : insert, update, delete).

There are several methods to do it :

  1. from database :
  2. from programming code  – every time you modify an object, you remember to modify the history object with appropiate data.

The drawback with the database approach is that you can not retrieve who done the modifications ( usually the applications connect under a single account and have a roles table)

The drawback with the programming approach is that the programmer must REMEMBER doing so…If he does not(and does not wrote tests for history), you are stuck…

In the following I propose an automatically history – that maps convention over configuration in my template, but it is easy for you to modify.

The solution works with Entity Framework 4.0 and, for more easily spearation of concerns , with POCO generators.

Let’s say you have the following tables :

database diagram

As you see we have a Employee and a employee_history, an Department and Department_history

The conventions are:

the history table name = “object” table name  +  “_history” suffix

the history table fields = “object” table name  fields +[ModifiedDate], [ModifiedBy], [ModifiedType]

(if you change those conventions , please change the modelhistory.tt file)

If you want to see in action , please  download code history and do the following
1. create database tests
2. run history.sql
3. run project
4. if necessay, re-create the model1.edmx with the same name and replace the console application app.config with the new connection string

After works, please add any fields to department table  and to department_history table(same field names/type) .  Re-compile the application and modify the new field in department. You will see the modifications in the department_history table.

Ok,now how we do the magic :

We create two new tt file that points to the model.edmx .

The first one ModelHistory.tt , takes care of  creating the constructor for history entities by taking a parameter from the original entity :

public Department_History(Department original):this()
{
this.IDDepartment=original.IDDepartment;
this.Name=original.Name;
}

How it do this magic ? Simple : the ModelHistory.tt recognize the model and history in the name of tables:

</pre>
string inputFile = @"Model1.edmx";
string History = "_History";
<pre>

then it generate code for constructor :

	#>
		public <#=code.Escape(entity)#>():base()
		{
		}
		public <#=code.Escape(entity)#>(<#=NameEntityOriginal #> original):this()
		{
		<#
	foreach (EdmProperty edmProperty in entityOriginal.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entityOriginal))
	{
		#>
				this.<#= code.Escape(edmProperty.Name) #>=original.<#= code.Escape(edmProperty.Name) #>;
		<#

	}
	#>
		}
	<#
</pre>

Ok, and then how to create the history entity ? I wish that the POCO template has had an event “Database saving” – but the only thing I can have is SaveChanges from the ObjectContext – so I create a new ObjectContext , derived from the default one that comes with the project, and creates a new history object :


public override int SaveChanges(SaveOptions options)
{
this.DetectChanges();
DateTime dtModified=DateTime.Now;
string UserModified=clsUser.UserName;
foreach (ObjectStateEntry ose in this.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified))
{

//could do this way too
//if (ose.Entity != null && ose.Entity.GetType() == typeof(...))
//{
//}
if (ose.Entity != null)
{
string NameType=ose.EntitySet.ElementType.Name;

switch(NameType)
{

case "Department":
var itemDepartment_History = new Department_History(ose.Entity as Department);
//if compile error here, that means you keep tracking
//of which modified with another properties
//please modify the tt accordingly
itemDepartment_History.ModifiedType= ose.State.ToString();
itemDepartment_History.ModifiedDate= dtModified;
itemDepartment_History.ModifiedBy= UserModified;
base.Department_History.AddObject(itemDepartment_History);
break;

case "Employee":
var itemEmployee_History = new Employee_History(ose.Entity as Employee);
//if compile error here, that means you keep tracking
//of which modified with another properties
//please modify the tt accordingly
itemEmployee_History.ModifiedType= ose.State.ToString();
itemEmployee_History.ModifiedDate= dtModified;
itemEmployee_History.ModifiedBy= UserModified;
base.Employee_History.AddObject(itemEmployee_History);
break;

}
}
}

return base.SaveChanges(options);
}

Now all is ready and I made a console application for testing manually (ok, should make a NUnit / MSTest / xUnit )

 using (var ctx = new testsEntitiesHistory())
            {
                var dep = new Department();
                dep.Name = "IT";
                ctx.Departments.AddObject(dep);
                ctx.SaveChanges();
                id = dep.IDDepartment;
            }
            using (var ctx = new testsEntitiesHistory())
            {
                var dep = ctx.Departments.Where(depart => depart.IDDepartment == id).FirstOrDefault();
                dep.Name = "Information tehnology";
                ctx.SaveChanges();
                //
            }
            using (var ctx = new testsEntitiesHistory())
            {
                var dep = ctx.Departments.Where(depart => depart.IDDepartment == id).FirstOrDefault();
                ctx.Departments.DeleteObject(dep);
                ctx.SaveChanges();

            }
            using (var ctx = new testsEntitiesHistory())
            {
                foreach (var dephist in ctx.Department_History)
                {
                    Console.WriteLine("Found {0} with state {1}", dephist.Name,dephist.ModifiedType);
                }
            }

And the output is :

history saving
automatically saving history department

Now you can add more tables to the edmx or change the fields – all is done automatically when compiling

If you want to see in action , please download code history

Update : for another way to do it( generating trigger and tables ) please see : http://msprogrammer.serviciipeweb.ro/2010/09/27/generating-history-trigger-with-ef-edmx-and-tt-files/

Caching in .NET

In every application you have some data that is more read-more, write-once or twice. For example you can have the list of Cities of a country, the list of Countries of the world or list of exchange currency. This data is modified rarely. Also, you can have data that is not very sensitive to be real-time , such as the list of invoices for the day.
In .NET 3.5 you have several options
1. ASP.NET caching – and implementing in other applications with HttpRuntime  ( even if MS says “The Cache class is not intended for use outside of ASP.NET applications”)

2. Enterprise caching block : hard to configure

3. memcached , velocity, sharedcache and other third party providers – that comes with their options and configuration

In .NET 4.0 you have a new kid : objectcache and , more important , an implementation : MemoryCache

http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache%28v=VS.100%29.aspx

What is very good is that now you can cache in Memory what do you want – and apply easily to your Business Layer. More, the object is a singleton for the application – that is even better (see the test on the final of the post)

What it is missing is an easy implementation for List and an implementation to remove data after a defined time.

So I decided to do my implementation for that (ok, it is wrong to have both implementations in a single class – but you can separate easily )

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Caching;

namespace CachingData{

    /// <summary>
    /// List<int> i = new List<int>() { 1, 10, 100 };
            //CacheData_List<List<int>, int> data = new CacheData_List<List<int>, int>(2);
            //data.Add(i);
            //Assert.AreEqual(3, data.Items().Count, "must be 3");
            //data = new CacheData_List<List<int>, int>();
            //Assert.AreEqual(3, data.Items().Count, "must be 3");
            //Assert.IsTrue(data.ContainsData, "must have data");
            //Thread.Sleep(1000 * 3);
            //Assert.IsFalse(data.ContainsData, "must not have data");
    /// </summary>
    /// <typeparam name="T">and generic ILIST </typeparam>
    /// <typeparam name="U"></typeparam>
    public class CacheData_List<T, U>
        where T:class,IList<U>, new()

    {
        /// <summary>
        /// use this for adding in cache
        /// </summary>
        public event EventHandler RemovedCacheItem;

        private System.Timers.Timer timerEvent;
        private MemoryCache buffer;
        private int TimeToLiveSeconds;

        private DateTimeOffset dto;
        private string Key;
        /// <summary>
        /// default constructor - cache 600 seconds = 10 minutes
        /// </summary>
        public CacheData_List()
            : this(600)
        {
        }
        /// <summary>
        /// constructor cache the mentioned TimeSeconds time
        /// </summary>
        /// <param name="TimeSeconds">value of time for cache</param>
        public CacheData_List(int TimeSeconds)
        {
            TimeToLiveSeconds = TimeSeconds;
            timerEvent=new System.Timers.Timer(TimeToLiveSeconds * 1000);
            timerEvent.AutoReset = true;
            timerEvent.Elapsed += new System.Timers.ElapsedEventHandler(timerEvent_Elapsed);
            dto = new DateTimeOffset(DateTime.UtcNow.AddSeconds(TimeToLiveSeconds));
            Key = typeof(T).ToString();
            buffer = MemoryCache.Default;
        }

        void timerEvent_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (RemovedCacheItem != null)
            {
                RemovedCacheItem(this, EventArgs.Empty);
            }
        }
        /// <summary>
        /// remove item from cache
        /// </summary>
        public void Remove()
        {
            if (buffer.Contains(Key))
            {
                buffer.Remove(Key);

            }
            dto=new DateTimeOffset(DateTime.UtcNow.AddSeconds(TimeToLiveSeconds));
        }
        /// <summary>
        /// add multiple items to cache
        /// </summary>
        /// <param name="items">items to add to the cache</param>
        public void Add(T items)
        {

            if (buffer.Contains(Key))
            {
                T data = Items();
                foreach (var t in data)
                {
                    items.Add(t);
                }
                buffer.Remove(Key);
            }
            buffer.Add(Key, items, dto);
        }
        /// <summary>
        /// add a item to the IList of the cache
        /// </summary>
        /// <param name="item">an item to add</param>
        public void AddItem(U item)
        {

            T data=new T();
            if (buffer.Contains(Key))
            {
                data = buffer.Get(Key) as T;
                buffer.Remove(Key);
            }

            data.Add(item);
            buffer.Add(Key, data,dto);
        }
        /// <summary>
        /// usefull if you do not intercept the removed event
        /// </summary>
        public bool ContainsData
        {
            get
            {
                return buffer.Contains(Key);
            }

        }
        /// <summary>
        /// retrieve items
        /// </summary>
        /// <returns></returns>
        public T Items()
        {
            if (!buffer.Contains(Key))
                return null;

            return buffer.Get(Key) as T;
        }
    }
}

Please note that the test for usage is in the summary :

</pre>
List i = new List() { 1, 10, 100 };
CacheData_List <List<int>, int> data = new CacheData_List<List<int>, int>(2);
data.Add(i);
Assert.AreEqual(3, data.Items().Count, "must be 3");
data = new CacheData_List<List<int>, int>();
Assert.AreEqual(3, data.Items().Count, "must be 3");
Assert.IsTrue(data.ContainsData, "must have data");
Thread.Sleep(1000 * 3);
Assert.IsFalse(data.ContainsData, "must not have data");

You can download the file from

http://msprogrammer.serviciipeweb.ro/wp-content/uploads/2010/05/CachingData.zip

(Last Note : for synchonization maybe it was better to lock on readerwriterlockslim

Intercept errors

Errors interception and rising

Description

We will speak here about the errors raised by external conditions (bugs) and the errors rose by the application.

There is not application without bugs. The bugs are not desired for an application – but programmers are human beings and, by consequence, they cannot verify every possible path that go an application to the failure. Maybe the space on hard is too little, other time the network between database and application is broken – there are many conditions to bring failure to an application. And you have to manage priority between

· repairing bugs

· evolving the application

· Resolving failure cases.

The errors raised by the application are usually logical errors, like the fact that a birthday date for a person cannot be tomorrow. Sometimes you will intercept errors from other components and raise your own error (like the fact that a component should have a unique name – you will intercept the index failure raised by your database and then raise your own error).

How to intercept error in applications

We will discuss here how and where to intercept errors. There are two principles that I guide my interception of errors:

1. Occam’s razor : in components(business layer, repository) intercept only the errors that you are sure to know what to do with (such as an ID is missing from a database). Usually here you can raise your own exception and let the GUI handle it. In

2. In GUI layer intercept all exception and , if possible, suggest to the user an alternative way to do.You must also log the error in order to can be retrieved later.

Please read the logging and instrumentation to see a common way to describe the path that a error has been flow through the application

Examples

First example is how to intercept an error

Second will be how to intercept and raise own errors

Third will be about intercepting errors in a Console application

1)We will first intercept an error and write a custom message for this error .

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Data.SqlClient;

namespace exceptionintercept

{

class Program

{

static void Main(string[] args)

{

using (SqlConnection sc = new SqlConnection())

{

sc.ConnectionString = "Data Source=(local);Initial Catalog=adaad!@#$%^;Trusted_Connection=true";

try

{

sc.Open();

}

catch (SqlException ex)

{

if (ex.Number == 2)

{

Console.WriteLine("no database connection : “+ ex.Message);

return;

}

throw;

}

}

}

}

}

As you see we will intercept only the SqlException and put the custom error message only if error message number for the SqlException is 2 – no network access. Usually it is not a good idea to show your connection string in the output shown to the user.

Download project from http://msprogrammer.serviciipeweb.ro/wp-content/uploads/exception.zip

2) Intercept and raise error

We will do now a more advanced interception of connection : we will see if the machine that has the database answers to the ping. If yes, probably only the database is down , not the PC or the connection.

public void VerifyConnection(string MyConnection)

{

using (SqlConnection sc = new SqlConnection())

{

sc.ConnectionString = MyConnection;

try

{

sc.Open();

}

catch (SqlException ex)

{

//TODO : log the exception

Ping p = new Ping();

try

{

PingReply pr = p.Send(sc.DataSource);

}

catch (PingException)

{

//TODO : log the exception

throw new PCException(sc.DataSource, ex);

}

throw new BasicDatabaseException(sc.DataSource,ex);

}

}

}

3) Any application should intercept globally errors, in order to log / save state if there is something that works not well and it is not handled.

static void Main(string[] args)

{

System.AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

int i = 1;

i = 1 / (i - 1);

}

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)

{

//TODO : log

Console.WriteLine("from program : unexpected error occured " + e.ExceptionObject);

}

Download project from http://msprogrammer.serviciipeweb.ro/wp-content/uploads/exception.zip

TODO

intercept global errors in WinForms, ASP.NET , WPF, Silverlight application

Other resources

ELMAH – intercept ASP.NET errors , http://code.google.com/p/elmah/

Logging : http://msprogrammer.serviciipeweb.ro/2010/04/19/logging-and-instrumentation/

Logging and instrumentation

Why

There are at least two reasons for an application to register what tfhe user do.

The first one and the most important is to see what is happening when a user has an error: what have been done, on which path did he go and what additional data(method parameters, usually) do you need for reproducing the bug.

The second one is to provide the application a way to record in-obtrusive messages for same actions that may seems not so right(check the event log for your computer for more examples 😉 )

Requirements for a logging system

The logging system should be:

1. Robust – if it can not write the message, it should not fail the entire app

2. Multi-write-data : it can write easily to multiple systems(such as databases, files on disk, send emails and so on)

3. Flexibility : the configuration of the logging system should be easy to modify. More, the modifications should be applied and “re-loaded” without re-compiling or re-starting the application

An implementation

For the implementation I will use log4net , http://logging.apache.org/log4net/ that it is satisfies all three conditions.

We will do a console application that sends a random error

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace ConsoleDemo1

{

class Program

{

static void Main(string[] args)

{

long ticks = DateTime.Now.Ticks;

FirstFunction(ticks);

}

static void FirstFunction(long i)

{

if (i % 2 == 0)

{

throw new ArgumentException("from first function");

SecondFunction(i);

}

static void SecondFunction(long i)

{

if (i % 2 == 1)

{

throw new ArgumentException("from second function");

}

}

}

}

As you see this application will have an error no matter if the ticks are even or odd. Download project from here : http://msprogrammer.serviciipeweb.ro/wp-content/uploads/loggingDemo.zip

Now we will see how the log4net writes data and error to a physical storage, in order to can be retrieved later.

Download log4net, add reference to it and make the following 4 steps

1. add a config file (I will name it log4net.config ) and in properties put “Copy to output Directory” to “Copy always” .

clip_image002[4]

Examples of log4net config files you will find everywhere on internet . If you look at the project you will see a bunch of “appenders” : ConsoleAppender, RollingLogFileAppender , SmtpAppender . The appender appends the log to the storage provided (Console, File, Email ). You will find a list of appenders at http://logging.apache.org/log4net/release/sdk/log4net.Appender.html and, if you do not found some appender you can wrote your own – just look at the source code.

For this application I want to use just ConsoleAppender and RollingFileAppender

<root>

<level value=”DEBUG” />

<appender-ref ref=”ConsoleAppender” />

<appender-ref ref=”RollingLogFileAppender” />

</root>

2. In order to see the file, put


log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo("log4net.config"));

(for asp.net application ,put


log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(Server.MapPath("~/log4net.config")));

)

3. Add a variable to log the errors :


private static readonly log4net.ILog _logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

4. Add a try/catch to log errors :

try

{

FirstFunction(ticks);

}

catch (Exception ex)

{

if (_logger.IsErrorEnabled)

{

_logger.Error("see an error!", ex);

}

throw;

}

Now, if you run the ConsoleDemoLog4net project, then you will see how to exception is logged twice and you will find the currentlog.txt in the same folder as your application executable.

Automatically instrument an application(dll, exe, asp.net)

This was pretty good – but what about putting a log to every method to see where the application flow has been gone and with which arguments?

You can do this with postsharp / log4postsharp. Postsharp is … Log4Postsharp is …

Let’s make the application do this automatically.

We download Postsharp 1.0 (not 1.5!) from http://www.softpedia.com/progDownload/PostSharp-Download-114994.html (you can found a more good paid version at http://www.sharpcrafters.com/downloads/ )

Now we will do the following :

1. Add the log4net.config from the previous project

2. Add log4net , PostSharp.Public and PostSharp reference

3. Add to the main just:

log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo("log4net.config"));

Do NOT add the log4net code to intercept!

4. Modify AssemblyInfo.cs and put

using Log4PostSharp;

[assembly: Log(AttributeTargetTypes = "*", EntryLevel = LogLevel. Error, EntryText = "postsharp :entering {signature} {paramvalues}", ExitLevel = LogLevel. Error, ExceptionLevel = LogLevel.Error, ExitText = "postsharp :exit {signature} {paramvalues} =&gt; {returnvalue}", ExceptionText = "postsharp : error in {signature} ")]

5. Add a text file named <yourprojectname>.psproj (in this case, ConsoleDemoPostSharp.psproj ) with the following content:

<?xml version=”1.0″ encoding=”utf-8″ ?>

<Project xmlns=”http://schemas.postsharp.org/1.0/configuration”>

<SearchPath Directory=”bin/{$Configuration}”/>

<SearchPath Directory=”{$SearchPath}” />

<SearchPath Directory=”lib” />

<Tasks>

<AutoDetect />

<Compile TargetFile=”{$Output}” IntermediateDirectory=”{$IntermediateDirectory}” CleanIntermediate=”false” />

</Tasks>

</Project>

6. Edit by hand the csproj file and add this :

<PropertyGroup>

<DontImportPostSharp>True</DontImportPostSharp>

<PostSharpDirectory> ..\libs\ postsharp\</PostSharpDirectory>

<PostSharpUseCommandLine>True</PostSharpUseCommandLine>

</PropertyGroup>

<Import Project="$(PostSharpDirectory)PostSharp.targets" Condition=" Exists('$(PostSharpDirectory)PostSharp.targets') " />

7. If there is a screen to ask you about a project modification, please tell “Load project normally”

So now , when it’s compiling , it says :

“D:\programe\youtube\loggingDemo\libs\postsharp\PostSharp.exe” “D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\ConsoleDemoPostSharp.psproj” “D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\obj\Release\Before-PostSharp\ConsoleDemoPostSharp.exe” “/P:Output=obj\Release\ConsoleDemoPostSharp.exe ” “/P:ReferenceDirectory=D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp ” “/P:Configuration=Release ” “/P:Platform=AnyCPU ” “/P:SearchPath=bin\Release\,obj\Release\, ” “/P:IntermediateDirectory=obj\Release\PostSharp ” “/P:CleanIntermediate=False ” “/P:MSBuildProjectFullPath=D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\ConsoleDemoPostSharp.csproj ” “/P:SignAssembly=False ” “/P:PrivateKeyLocation= ”

PostSharp 1.0 [1.0.12.469] – Copyright (c) Gael Fraiteur, 2005-2008.

EXEC : warning PS0064: A new version of PostSharp 1.0 is available. You have currently 1.0.12.469 and you could download the version 1.0.13.630 from http://www.sharpcrafters.com/postsharp/download.

info PS0035: C:\Windows\Microsoft.NET\Framework\v2.0.50727\ilasm.exe “D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\obj\Release\PostSharp\ConsoleDemoPostSharp.il” /QUIET /EXE /PDB “/RESOURCE=D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\obj\Release\PostSharp\ConsoleDemoPostSharp.res” “/OUTPUT=D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\obj\Release\ConsoleDemoPostSharp.exe” /SUBSYSTEM=3 /FLAGS=1 /BASE=19595264 /STACK=1048576 /ALIGNMENT=512 /MDV=v2.0.50727

ConsoleDemoPostSharp -> D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\bin\Release\ConsoleDemoPostSharp.exe

Done building project “ConsoleDemoPostSharp.csproj”.

We then run the program and enjoy the power of PostSharp :

2010-04-17 23:29:12,705 [1] ERROR 2010-04-17 23:28:43,265 [1] ERROR D:\programe\youtube\loggingDemo\ConsoleDemoPostSharp\Program.cs ConsoleDemoPostSharp.Program [(null)] – postsharp :entering Void FirstFunction(Int64) “634071437232634478

[more data]

So , as you see it gives you not only the trace , but also the value : 634071437232634478

You can download code from http://msprogrammer.serviciipeweb.ro/wp-content/uploads/loggingDemo.zip

Additional resources

Tracing : http://www.15seconds.com/Issue/020910.htm

Enterprise logging : http://msdn.microsoft.com/en-us/library/cc309257%28v=MSDN.10%29.aspx

VS2010 with Dotfuscator : http://msdn.microsoft.com/en-us/library/ff460257.aspx

CCI metadata : http://ccisamples.codeplex.com

Postsharp 2.0 improvements over 1.0 : one of many examples here : http://www.sharpcrafters.com/blog/post/introducing-postsharp-2-0-1-notifypropertychanged.aspx

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.