Asp.Net 2.0 session stored in Sql

Sometimes it is preferable to store the session of asp.net in sql, I prefer to use a distinct database for each application, the command to create such database is

aspnet_regsql.exe -S localhost\isntancename -U sa -P sapwd -d databasename -ssadd -sstype c

Notice the use of –sstype c parameter that forces the script to create a custom database, without that argument the scritp does not permit you to use a custom database name to store the session. In web.config you should also state that you want to use a custom type sql database with allowCustomSqlDatabase=”true”.

   <sessionState 
            timeout=60 
            allowCustomSqlDatabase=true 
            mode=SQLServer 
            sqlConnectionString=Database=EasyCVSessionStore;Server=localhost\SQL2000;…/>

Also avoid to copy session database around, and recreate always with aspnet_regsql.exe, it avoid you some headache.

Alk.

NHibernate, session per request and HTTPSEssion

In an old post I talked about a strange error I had in a web site. The last time I simply changed the logic not storing entities in httpsession anymore, now I face this error again and I decided to solve it. The problem is in the session per request pattern that I use to share nhibernate session for a whole request. My implementation of Session Per Request simply create a nhibernate session, start a transaction and commit or rollback the transaction with an HTTP Module that intercepts EndRequest Event. The error happended when I store entities in httpsession and the sessionstate is stored into sql server.

I have two entities, let’s call them Section and SectionLocalization. The section entity has a dictionary of SectionLocalization objects, indexed by a string that represent a langcode. The SectionLocalization objects are value object, so their lifecycle is determined by the owning Section. In a page I need to work a lot with a list of Section, to maximize performance I retrieve the list of Section from the database with a Nhibernate criteria, then I store the IList<Section> object in HTTP section since it will be used in read only mode for several postback. The problem arise when I add a new Section: I simply create a new Section, put into it some SEctionLocalization objects, then use session.Save() to persist and I also add the section to the IList<Section> actually stored in httpsession. When I need to modify a section object I simply reattach the object to nhibernate session with Session.Lock() since I’m sure that the object is not modified, then I modify the object and when EndRequest fires the changes are propagated to the database. When I try to change the new object I get “Reassociated object has dirty Collection” exception.

The problem is not showing if I use in memory asp.net session, so it should be caused by session serialization. The problem turns to be caused by the Session Per Request pattern. When I create new section object and save it into session this is the general flow of the operation.

The problem is the following, when I call session.save() nhibernate saves into database the section object because it has an autogenerated id, but section localization objects are value object and gets not saved at that time. Then I add the section into the list stored into HTTPSession and then this list gets serialized to store it into SQLServer, at that time the SectionLocalization objects of the new section are still unsaved, and they gets serialized in this state. When EndRequest fires the session per request pattern commits the transaction, nhibernate session flushes all pending operations and SectionLocalization objects contained in the new section gets saved into db. At the next request, the list of section gets deserialized from the database, and the Section object created in the previous request still have the SectionLocalization objects in new state, because they were serialized before nhibernate persists them to database. When I try to reattach the object with Session.Lock() the collection is found to be dirty.

After some investigation it turns out that to implement correctly the session per request pattern I need also to intercept the PostRequestHandlerExecute event, that gets fired immediately after the end of the execution of the page, and before serialization of the http session takes place. In this event I simply call session.flush() to be sure that all pending operation are completed before the serialization of the HTTPsession.

The conclusion is to pay great attention to “open in request pattern” when you store some entities into the httpsession that gets serialized (Sql server, out of proc), because the entities stored in httpsession get serialized while nhibernate session has still pending operations, so they will be stored with an inconsistent state.

Alk.

When older is better

Yesterday I was called to solve a problem. There is a web application that works with a ActiveX control packaged in a .Cab file, but client machine have standard user logged. What we needed was the following, when a user navigate to a page that contain a reference to that control, IE should automatically download and install the control even if the user have not administrative rights on the machine.

Microsoft explain how to use Active Directory to do this, it is really useful and I found another article that explain how to create a valid msi installer file to achieve the result. What I did not like is that if I create the .msi file with the old “visual studio installer” everything is good, but I did not found a way to make a valid installer in Visual Studio 2005 installer projects. The problem with visual studio installer is that is a old product that can be installed only if you have installed visual studio 6 on your machine. Since the problem can be solved there was no need to investigate further, but I really like to understand how to make a valid installer to use with UseCoInstall with visual studio 2005

Alk.

Intercept events from HttpModule

This morning I was reading an interesting article (http://msdn2.microsoft.com/en-us/library/9z52by6a.aspx) on how to perform custom authentication in a webservice. This article is interesting but actually does not run “as is”, it miss a little part, the Global.Asax code that listen for the HttpModule Event. The question is “How can I listen to an event raised from an Http module if the instance of that module is created by asp.net engine?”. The answer is not so intuitive, because each event raised from an httpmodule can be intercepted by global.asax with a not so evident autowiring. It turns out that if you want to listen for an event raised from httpmodule you have to create a method in global.asax that match the signature of the event and name it with this pattern modulefriendlyname_eventname. In the example of the above article I enabled the event with this code in web.config

<httpModules>
  <add name=Auth type=Microsoft.WebServices.Security.WebServiceAuthenticationModule/>
</httpModules>

It turns out that in my global.asax I can listen for the event with this code.

protected void Auth_Authenticate(Object sender, WebServiceAuthenticationEvent e) {
 
  //Your code here
}

Alk.

Â

Reference a user control from app_code

User controls are one of the most useful features of ASP.NET, but they can generate problems with dynamic generation. Suppose you create a user control and then wants to dynamically create instances of that control and reference some specific properties or method of the control itself. If the code is in another user control there is no problem, just use a @register page directive and no problem, here is an example

<%@ Register 
   Src=”~/BackOfficeControls/ModularData/ModularDataSection.ascx”      
   TagName=”ModularDataSection”
   TagPrefix=”mdc” %>

Whith this directive I’m telling to ASP.NET that in this control I will reference ModularDataSection.ascx user control, this permits me to write code like this in code behind file

Dim cnt As Control = page.LoadControl(“~/BackOfficeControls/ModularData/ModularDataSection.ascx”)
Dim
 modcont As BackOfficeControls_ModularData_ModularDataSection
modcont = TryCast(cnt, BackOfficeControls_ModularData_ModularDataSection)

I can reference the class that implements the control with the name BackOfficeControls_ModularData_ModularDataSection because the @register directive put that class in scope. The problem arise when I try to move the previous snippet in a class in app_code directory. Code in app_code directory cannot use @register directive, nor it can reference class behind code for user control. A solution of this problem is to define an interface in app_code directory that contains all the properties and methods that you need to access on the user control

Public Interface IModularDataSectionUserControl
   
Property BaseControlDir() As String
   
Sub InitData(ByVal sectionId As Integer, ByVal linkId As Nullable(Of Integer))
End Interface

Then you make your user control implement this interface, and in app_code you can write classes that dynamically instantiate the control and works through the interface.

Dim cnt As Control = page.LoadControl(tab.ControlPath)
Dim modcont As EasyCv.UserControl.IModularDataSectionUserControl
modcont = 
TryCast(cnt, EasyCv.UserControl.IModularDataSectionUserControl)
If modcont IsNot Nothing Then
  
Dim sect As Actvalue.ModularData.Entities.Section = DirectCast(tab.Tag, Actvalue.ModularData.Entities.Section)
  modcont.BaseControlDir = 
“~/BackOfficeControls/ModularData/”
  modcont.InitData(sect.Id, cvid)
End If

In this way you can access specific properties and method of the user control because they are exposed through an interface shared in the app_code directory.

Alk.