Wednesday, September 1, 2010

Audit/history tracking with EF 4.0

I have spent last two days investigating ways to track change history for an entity. And finally came up with a good idea, which I'd like to share with everyone.
There is a great feature in auto-generated entity code (in the entity data model designer file): support of partial methods.
For each property in an entity there are two partial methods generated:
On[PropertyName]Changed(), On[PropertyName]Changing({property type} value).


This is a great feature wich we are going to use.
Let's see first when to track the changes - what is the best point to keep the history. It's not good idea to make this in the OnXXXChanged method, cause this can be caused a lot, but most of those calls will never affect the entity data. So the best time to do it is when the SaveChanges() method for the Context is called. But how to handle that: The ObjectContext calss, which from our datacontext class is derieved, fires an event named SavingChanges, and also has a partial method, called OnContextCreated.


So first of all lets create a partial class with the same name and within the same namespace as the context class of our entities, and define a partial method named OnContextCreated in it:

public partial class MyModelEntities
{
partial void OnContextCreated()
{

}
}


Now let's create an interface IAuditableEntity, which the entities needing to track the history should implement.


internal interface IAuditableEntity
{
void AuditChanges(MyModelEntities argContext);
}

This interface defines a method, which should be called, when the SaveChanges() method should be called on the Context instance. In our partial context class add the following code:

public partial class MyModelEntities
{
partial void OnContextCreated()
{
this.SavingChanges += new EventHandler(MyModelEntities_SavingChanges);
}

private void MyModelEntities_SavingChanges(object sender, EventArgs e)
{
IEnumerable tmpEntries = this.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Modified);
foreach (ObjectStateEntry tmpEntry in tmpEntries)
{
if (tmpEntry.Entity is IAuditableEntity)
{
(tmpEntry.Entity as IAuditableEntity).AuditChanges(this);
}
}
}
}

This code will make the Context class to call the AuditChanges method of all the entities, implementing the IAuditableEntity interface before updating the datastore with new values. This means, that in the AuditChanges method body in the entity instance you will have control over the actions related to the history tracking. The other side is up to you - how to implement on the data layer the history tracking itself.
Have fun.

Saturday, March 27, 2010

ASP.Net Session lost when deleting folder

Hi there.
The last days of my coding brought me to a problem with loosing session state in my ASP.Net application, when deleting a folder during the request processing.
The thing is that when you delete a folder which is under the root folder of your application, then the structure of the application is being changed, and the IIS recycles that application. This means that the issue will be only in case of InProc Session State, which keeps the session state in memory.
Hope this will be helpfull.

Have a great weekend.

Friday, February 26, 2010

Working with WebBrowser Control

One of the most interesting issues I had experienced and which for I was not able to find a solution in inet - was problem related to WebBrowser control.
The thing is that when I was trying to access the Document property of the WebBrowser control instance, I was getting "Invalid cast exception".
The thing is that the WebBrowser control is designed to work in one thread. So to fix this you must only check the InvokeRequired property and if it's value is true, then call the logic from the delegate, given into browser.Invoke(...) method.
This is all the stuff.
Lucky coding ...

Monday, January 18, 2010

ASP.Net AJAX: Working with update panels

This post is for the people, who think that using update panels is nothing else but just add it to the page. This is not true !

I have noticed that a some developers are using update panels, as some kind of "metadata checkbox" - placing one update panel to wrap all the content of the page in its ContentTemplate. So in this post I will try to explain what exactly the UpdatePanels are for and how most from them.

First of all UpdatePanels are markers, which let you mark small, separate updateable areas on the page. Try to look at your page as a group of functionally independent areas. Decide which areas should be updated asynchronously and wrap those area code with UpdatePanel. Don't forget to include one <asp:ScriptManager runat="server" ... control on the page.

Job is done - you have the structure. But there is currently no difference from the page PV in what you had before (putting whole the content into one UpdatePanel) and what you currently got. Because by default The UpdateMode property of the UpdatePanel is set to Always, which makes the UpdatePanel to update its content on any postback. To fix this we just set the UpdateMode property of the needle UpdatePanel to Conditional. This makes the UpdatePanel to update its content by explicit requests (triggers, or just call to the Update() method of the UpdatePanel).

Now let's walk over a small example. Imagine you have a page with three UupdatePanels. All of them has some randomly generating content (random number for test). The first contains a button, which causes postback and has UpdateMode set to Always. The second also has UpdateMode set to always. The last UpdatePanel's UpdateMode is set to Conditional.

Now try to click the first button. This will update both update panels (which has UpdateMode set to Always). The third UpdatePanel whill keep it's content as was. Now click the third updatePanel's button. This will update all the three. Now add a handler to the first button's click event and call the Update() method of the third UpdatePanel). You will see that now after clicking the first button again all the updatePanels are being updated.

I have also attached a small code example (like the one described above). Hope it will help you to go deeper: http://www.sendspace.com/file/2lrs1w