Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,612
|
Comments: 51,243
Privacy Policy · Terms
filter by tags archive
time to read 2 min | 222 words

Okay, I think that I managed to dechiper most of the strange behavior in ASP.Net's Http Modules.
  • An AppDomain may hold zero or more instances of HttpApplication
  • A new instance of HttpApplication may be created (for reasons that I have not been able to figure out) - a set of all the http modules will be created as well.
  • An instnace of HttpApplication may be disposed (with its associted http modules) at any time.
  • A request will always be served by a fully initialized HttpApplication.
The result of this is that you cannot set/unset static variables from an HttpModule or HttpApplication.
Or, more correctly, you can't rely on unsetting a static varaible in Dispose() and setting it in Init() (or Application_Start and Application_End), since they may be called several times.
This mean that you either have to do a ref counting ( Bad ), or implement application level variables in Web secanrios. (Or just forgo about cleaning resources when the HttpApplication is going down).

I chose the first way, but it is not very clean, in my opion, check out the changes that I had to make:
Basically, this means that when running under Web context, it will use the current application as a global variable, and when running under non-web context, it will use a static variable.

time to read 2 min | 345 words

My web.config file defines the following Http Module:

<httpModules>
     <
add name="UnitOfWorkModule"
           
type="Rhino.Commons.HttpModules.UnitOfWorkModule, Rhino.Commons"/>
</
httpModules>

Yet, for some reason, I get two instances of the UnitOfWorkModule, and I can't quite figure out why. It looks like it is proccessed okay, when I look into the Http Application Initialization, I get the following registered modules:


But, if I put a break point on the Init() method in the Http Module, it is called twice! I run it many times, and the "secret" seems to be multiply requests in the application's start. It looks likes several HttpApplication instances are created, and this is what is causing the issue.

This may be related to the previous error, since my state is app-domain global. If the ASP.Net runtime initiate more than a single HttpApplication per app-domain, and clean it up after ward, it may cause the issues that I have seen, of Disposing an HttpModule which hold global state and then not calling the Init() again.

At the moment, I am going to assume that this is the case, which means that my life are ever more complicated than before.
At the moment, I am using a static variable to hold the container instance, but this static variable is shared among all the HttpApplication instances. This probably mean that I need to keep track of it in an Application level variable, but this gets into complicated code in non-web scenarios.
time to read 2 min | 329 words

I run into some very strange issues latelt with regard to Http Modules. I am using Http Modules to setup the environment for my application. In particular, I am using Unit Of Work Module to mange my Unit Of Work and the life time of application wide resources (like the Inversion Of Control container instnace).

The problem that I run into was that I began to get errors from the application, saying that the container was missing. That, of course, was not possible, since I registered the HttpModule correctly, and it certainly did it job, for a time.

The issue was mainly that after a while, never determenisticly, the application start throwing errors. But at first, it was smooth sailing. I butt my head against many walls, but I finally manage to get a stack trace of the issue.

Here is the call to Dispose(), which releases the resources required to my application:

> Rhino.Commons.DLL!Rhino.Commons.HttpModules.UnitOfWorkModule.Dispose() Line 37 C#
  System.Web.dll!System.Web.HttpApplication.DisposeInternal() + 0x93 bytes 
  System.Web.dll!System.Web.HttpApplicationFactory.TrimApplicationInstanceFreeList() + 0x96 bytes 
  System.Web.dll!System.Web.IdleTimeoutMonitor.TimerCompletionCallback(object state) + 0x34 bytes 
  mscorlib.dll!System.Threading._TimerCallback.TimerCallback_Context(object state) + 0x1a bytes 
  mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x81 bytes 
  mscorlib.dll!System.Threading._TimerCallback.PerformTimerCallback(object state) + 0x5b bytes 

The next request after this call, no call to Init() was made, and the application, predictably, crashed.

I googled and search and reflected for quite a while, but I can't figure out the reason for this. I'm pretty certain that if Dispose() is called on the HttpModule, the next request should call Init(), or create a whole new instnace (preferable), but in this circumstance, it looks like Dispose() is called just because it feels like it.

The server is Windows Server 2003, Enterprise, SP1, using ASP.Net 2.0. I have seen this behavior across several machines, including XP one, so I guess it is not the environment that is causing this issue.

At the moment, the only work around is to not use Dispose(), and let resource be cleaned by the Finalizer thread if neccecary.

Any thoughts?

time to read 3 min | 529 words

In response for my DDD in Hebrew, I was asked why it is not recommended to code in Hebrew. I decided to question my initial response, and give it a shot. I quickly gave it a try and created the following domain model. I don't expect you to be able to read it (although if you can, you'll find it hilarious).

Here is my DDD in Hebrew, the classes are Employee (right, top), Report (Left, Top), HoursReport (Middle, Bottom), WontBeHereReport (Left, Bottom) and Repository<T> (Right, Bottom):

(Image from clipboard).png

I run into a couple of issues just with designing this diagram:

  • Trying to specify a generic parameter in Hebrew cause issues because of alignments. Basically, the whole class name is presented in the wrong way (this is a common issue with mixing Hebrew & math together).
  • Intellisense is mostly useless, check out this, you may not be able to see it, but the Hebrew is half-way reversed.
    (Image from clipboard).png
  • For some reason Visual Studio is working a lot harder when I write code in Hebrew.

Let us move to more serious issues, take a look at this simple program:

(Image from clipboard).png

Main issues:

  • Hebrew is written right to left, the code here is structured left to right.
  • Hebrew doesn't have upper/lower casing, so words need to be seperated by "_".
  • I often need to switch keyboard setttings ( even something as simple as "<" has different orientetions in Hebrew and English).
  • I need to use primitives (such as DateTime) in English.
  • I need to mix English and Hebrew in the same line (see the "new" lines).
  • All control flow is in English.
  • You can't grep this source. At least not easily. Hebrew and the command line do not mix.

That is even beside the nice point of the enconding hell that you get yourself into. It is very easy to save this as ASCII (if you open it in an editor that doesn't support unicode, or simple use a tool to go over it) and lose all the hebrew characters.

Sorry Eliezer, but you will have to write Hebrew# and language pack, and write a translation layer for the framework if you really want me to use it.

time to read 10 min | 1984 words


One of the biggest problems with abstractions is that they may allow you to do stupid things without them being obvious. In OR/M-land, that usually means SELECT N+1 issues.
The problem is that you often develop a certain functionality first, and only then realize that while you tested, all was fine and dandy on the five items that you had, but on the real system, you have 5,000, and the DBA is on its way to ER...

Anyway, I am currently working with Web Applications, and I wanted to get a good indication about what pages are troublesome.
Being who I am, I immediately began to design a framework that would correlate page requests to trace data from SQL Server, and then another system that would analyze it and spit out a report saying: "Wow, that ScaryReport.aspx page is making 30% of the calls in the application, take a look at that".

Not wishing to spent the next two years on this project, I decided to do something a bit more modest, and utilize the already existing infrastructure.
In this case ,the infrastructure is NHibernate and lot4net.

The secret tidbit is that NHibernate logs all queries to a log4net logger named "NHibernate.SQL". From there, it was a simple matter of adding a logging helpers to Rhino Commons that would output the current page and the current request id (the request hash code, basically).
Then, It was a matter of defining the following table:

CREATE TABLE [dbo].[NHibernatePerPageQueries](
   
[Id] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL,
   
[RequestId] [int] NOT NULL,
   
[Date] [datetime] NOT NULL,
   
[Message] [nvarchar](max)  NOT NULL,
   
[PageURL] [nvarchar](max)  NOT NULL
)


Then, to define the appender:

<appender name="NHibernatePerPageAppender"
            
type="log4net.Appender.AdoNetAppender">
    
<
bufferSize value="10" />
    
<
connectionType value="System.Data.SqlClient.SqlConnection,
System.Data, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
" />
    
<
connectionString value="Data Source=localhost;Initial
Catalog=Logs;User ID=logger;Password=logger;
" />
    
<
commandText value="INSERT INTO dbo.[NHibernatePerPageQueries]
([Date],[Message],[PageUrl],[RequestId]) VALUES (@log_date, @message,
@pageUrl,@currentRequestId)
" />
    
<
parameter>
           <
parameterName value="@log_date" />
          
<
dbType value="DateTime" />
          
<
layout type="log4net.Layout.RawTimeStampLayout" />
    
</
parameter>
     <
parameter>
           <
parameterName value="@message" />
          
<
dbType value="String" />
          
<
size value="4000" />
          
<
layout type="log4net.Layout.PatternLayout">
               
<
conversionPattern value="%message" />
          
</
layout>
     </
parameter>
     <
parameter>
           <
parameterName value="@pageUrl" />
          
<
dbType value="String" />
          
<
size value="2000" />
          
<
layout type="log4net.Layout.PatternLayout">
               
<
conversionPattern value="%property{nhibernate_page_url}" />
          
</
layout>
     </
parameter>
     <
parameter>
           <
parameterName value="@currentRequestId" />
          
<
dbType value="String" />
          
<
size value="2000" />
          
<
layout type="log4net.Layout.PatternLayout">
               
<
conversionPattern value="%property{current_request_id}" />
          
</
layout>
     </
parameter>
</
appender>


And defining the logger:

<logger name="NHibernate.SQL">
    
<
level value="DEBUG" />
    
<
appender-ref ref="NHibernatePerPageAppender" />
</
logger>


We are still not done, though, we need the following in the Application_Start():

GlobalContext.Properties["nhibernate_page_url"] = WebLoggingHelper.CurrentPage;
GlobalContext
.Properties["current_request_id"] = WebLoggingHelper.CurrentRequestId;


This is it, now I can correlate the number of queries per page hits, and act accordingly.
Normally, I think that the following queries should be enough:

-- Get pages ordered by number of total queries made from them

SELECT COUNT(*) [Number Of Queries In Page], PageUrl
FROM
NHibernatePerPageQueries
WHERE
substring(Message,1,1) != '@' -- remove parameters logs
GROUP
BY PageUrl ORDER BY COUNT(*)

 

-- Get pages ordered by number of queries per page

SELECT AVG(countOfQueries) [Number Of Queries In Page Per Request], PageUrl FROM (
    
SELECT COUNT(*) countOfQueries, PageUrl
     FROM NHibernatePerPageQueries
     WHERE substring(Message,1,1) != '@' -- remove parameters logs
    
GROUP BY PageUrl, RequestId ) innerQuery
GROUP
BY PageUrl ORDER BY AVG(countOfQueries)

 

Enjoy,
time to read 10 min | 1834 words


I just added a small http module to Rhino Commons. It is a very simple module that times how long it takes to process a page.
It only times the server-side processing, of course, but it is a great way to tell you where you need to pay attention.
It is using log4net to log the data, so you can redirect the output to a database, and from there, you can get all the data you want.

Configurating the module is very simple. Create the following table:

CREATE TABLE [dbo].[PagePerformance](
    
[Id] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL,
    
[Date] [datetime] NOT NULL,
    
[Message] [nvarchar](max) NOT NULL,
    
[PageURL] [nvarchar](max) NOT NULL,
    
[Duration] [nvarchar](50) NOT NULL,
    
[StartRequest] [datetime] NOT NULL
)

Now, add the following to your <httpModules> tag in web.config:

<httpModules>
     <
add name="PagePerformanceModule"
          
type="Rhino.Commons.HttpModules.PagePerformanceModule"/>
</
httpModules>


Finally, we define in log4net.config the appender configuration:

<appender name="PagePerfAppender"
            
type="log4net.Appender.AdoNetAppender">
    
<
bufferSize value="10" />
    
<
connectionType value="System.Data.SqlClient.SqlConnection,
System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
" />
    
<
connectionString value="Data Source=localhost;Initial
Catalog=Logs;User ID=logger;Password=logger;
" />
    
<
commandText value="INSERT INTO dbo.PagePerformance
([Date],[Message],[PageUrl],[Duration],[StartRequest]) VALUES (@log_date, @message, @pageUrl, @duration, @startRequest)
" />
    
<
parameter>
           <
parameterName value="@log_date" />
          
<
dbType value="DateTime" />
          
<
layout type="log4net.Layout.RawTimeStampLayout" />
    
</
parameter>
     <
parameter>
           <
parameterName value="@message" />
          
<
dbType value="String" />
          
<
size value="4000" />
          
<
layout type="log4net.Layout.PatternLayout">
               
<
conversionPattern value="%message" />
          
</
layout>
     </
parameter>
     <
parameter>
           <
parameterName value="@pageUrl" />
          
<
dbType value="String" />
          
<
size value="2000" />
          
<
layout type="log4net.Layout.PatternLayout">
               
<
conversionPattern value="%property{page_url}" />
          
</
layout>
    
</
parameter>
     <
parameter>
           <
parameterName value="@duration" />
          
<
dbType value="String" />
          
<
size value="50" />
          
<
layout type="log4net.Layout.PatternLayout">
               
<
conversionPattern value="%property{page_duration}" />
          
</
layout>
     </
parameter>
     <
parameter>
           <
parameterName value="@StartRequest" />
          
<
dbType value="DateTime" />
           
<
layout type="log4net.Layout.PatternLayout">
               
<
conversionPattern value="%property{start_request}" />
          
</
layout>
     </
parameter>
</
appender>

The page_duration, start_request and page_url properties are added to log4net configuration by the http module.
Then, all that is left is defining the logger itself:

<logger name="Rhino.Commons.HttpModules.PagePerformanceModule">
    
<
level value="DEBUG" />
    
<
appender-ref ref="PagePerfAppender" />
</
logger>

If everything went well, you have now got yourself a table in the DB that measures
how much it takes to serve each page.

Note: There is a small buffer (10 page requests) defined, to reduce the cost of the logging, so you would need to hit refresh a couple of time before you see the results in the table.

DDD in Hebrew

time to read 2 min | 228 words

After reading Evan's Domain Driven Design book, I tried to develop software using the concepts describe in the book.

The problem is that the langauge that the client / spec talks and the langauge that I have to use to write the product are radically different. It is not just technical vs. business jargon. It is a different language with concepts that often cannot be directly translated.

Transliterating is a Bad Thing to do, and I speak from a lot of very painful experiance.

It gets to be more interesting when the business guys are using terms that has a direct technical meaning in English but not in Hebrew. One of the entities in the domain would be directly translated to EmployeeBase, and it is not the base class for the Employee class, the concept is actually very different

I managed to find reasonable alternative for most of the names (in the case above, EmployeeTemplate), but any question / talk about the code / model means that we are using both terms (in both langauges, actually) in order to talk about the same thing. Talk about confusing.

Hebrew (and Arabic) has the unique characteristic of being written right to left, so trying to write code in Hebrew is not practical (Although I would like to see anyone who can come up with a coherent system in Hebrew beyond the Hello World samples).

time to read 1 min | 150 words

It seems that every time I turn around I hear programming being compared to construction, engineering, precise sciences, etc. My view on the subject is quite different. I think that most of the industry is fooled to think that there are some hard rules about computers, than the field is something that belongs to engineering. (And it is probably better to say, I'm a software engineer than a software artist).

Nevertheless, art is just as precise and methodolical as programming, not for nothing a high precentage of programmers are musicians, and just ask your common painter just how mush science goes into making a good painting. I see a lot humane things that affect software projects than a technical ones. And the final result isn't some cold and metallic thing. It's something that you put quite a bit of creativity in.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. Recording (18):
    29 Sep 2025 - How To Run AI Agents Natively In Your Database
  2. Webinar (8):
    16 Sep 2025 - Building AI Agents in RavenDB
  3. RavenDB 7.1 (7):
    11 Jul 2025 - The Gen AI release
  4. Production postmorterm (2):
    11 Jun 2025 - The rookie server's untimely promotion
  5. RavenDB News (2):
    02 May 2025 - May 2025
View all series

Syndication

Main feed ... ...
Comments feed   ... ...
}