20100531

WCF service consumed by jOuery on IIS7

For this example assume you need to return Info structure (that consists of two strings: Title and Body) that can be queried using it's Id.

First you have to define data contract:

namespace Example
{
    [DataContract]
    public class Info
    {
        [DataMember]
        public string Title;

        [DataMember]
        public string Body;
    }
}

Then interface of the service - it also defines request and response format as JSON (which can be easily consumed in JavaScript).

namespace Example
{
    [ServiceContract(Namespace = "")]
    public interface IGetInfoService
    {
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        Info GetInfo(int id);
    }
}

Service logic just to provide full example :)

namespace Example
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]    
    public class GetInfoService: IGetInfoService
    {       
        public Info GetInfo(int id)
        {
            return
                new Info 
                    {
                        Title = id.ToString(),
                        Body = "Lorem ipsum"
                    });
        }
    }
}

WCF service requires also web.config section:

<system.serviceModel>
        <services>                        
                <service behaviorConfiguration="GetInfoServiceBehavior" name="GetInfoService">
                        <endpoint address="" behaviorConfiguration="GetInfoEndpointBehavior" binding="webHttpBinding" contract="Example.IGetInfoService">                                       
                                </endpoint>
                                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
                </service>
        </services>
               
        <behaviors>
                <serviceBehaviors>
                        <behavior name="GetInfoServiceBehavior">
                                <serviceMetadata httpGetEnabled="true" />
                                <serviceDebug includeExceptionDetailInFaults="false" />                                                                    
                        </behavior>
                </serviceBehaviors>
                <endpointBehaviors>
                        <behavior name="GetInfoEndpointBehavior">
                                <enableWebScript />
                        </behavior>
                </endpointBehaviors>
        </behaviors>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>

Consume service using jQuery $.ajax call.
Params is object that handles all parameters and msg in success function

var params = new Object;
params.id = 10;

$.ajax({
 type: "GET",
 url: "/Services/GetTheFactsService.svc/GetNextFact",
 data: params,
 dataType: "json",
 success: function (msg) {
  $(".info h3").html(msg.d.Title);
  $(".info p").html(msg.d.Body);
 },
 error: function (msg) {
  alert(msg);
 }
});

If ISS reports 404 or 500 error results you probably need to register WCF:

c:
cd "C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation"
servicemodelreg -i
Command above registers *.svc handlers for host so if you have other defined for site you have to remove them or go to Handler Mappings section and use Revert To Inherited action.

20100423

Lucene large queries efficiency

Reading large data sets from Lucene even after adding document cache can still be slow due to algorithm that loads only 100 results and queries again each time loaded amount is smaller than required. Documentation advises to use HitCollector to speed up but it's hard to find an example. Big disadvantage of this approach is no sorting support when HitCollector is used.
Below you can find example of LuceneHitCollector storing items in LuceneHitCollectorItems and using LuceneSorter.
LuceneSorter is based on internal Lucene sort algorithm and therefore uses it's dictionaries built while directory is created. It implements only subset of Lucene capabilities:
  • sorting by rank (when empty string is passed to Sort method)
  • sorting by string field
  • reverse order sorting

Last code example shows how to use HitCollector. It's as easy as using Lucene itself and again much faster.

public class LuceneHitCollectorItem
{
    public float Score;
    public int DocId;
    public Document Doc;
}

public class LuceneHitCollector : HitCollector
{        
    private readonly IndexReader reader;
    private List<LuceneHitCollectorItem> docs = new List<LuceneHitCollectorItem>();

    public LuceneHitCollector(IndexReader reader)
    {
        this.reader = reader;
    }

    public override void Collect(int doc, float score)
    {
        Document document = reader.Document(doc);
        docs.Add(
            new LuceneHitCollectorItem
                {
                    DocId = doc,
                    Doc = document,
                    Score = score
                }
            );
    }

    public void Sort(string field, bool reverse)
    {
        LuceneSorter sorter = new LuceneSorter(reader, field, reverse);
        sorter.Sort(docs);
    }

    public int Count
    {
        get
        {
            return docs.Count;
        }
    }

    public LuceneHitCollectorItem Doc(int n)
    {
        return docs[n];
    }
}

public class LuceneSorter
{
    private string field;
    private bool reverse;
    private StringIndex index;

    public LuceneSorter(IndexReader reader, string field, bool reverse)
    {
        if (field != "")
        {
            String fieldName = String.Intern(field);
            index = FieldCache_Fields.DEFAULT.GetStringIndex(reader, fieldName);
        }
        this.field = field;
        this.reverse = reverse;
    }

    public void Sort(List<LuceneHitCollectorItem> docs)
    {
        if (String.IsNullOrEmpty(field))
        {
            docs.Sort(CompareScore);
        }
        else
        {
            docs.Sort(CompareField);
        }
    }

    private int CompareField(LuceneHitCollectorItem a, LuceneHitCollectorItem b)
    {
        int result = index.order[a.DocId] - index.order[b.DocId];
        if (result == 0)
        {
            result = a.DocId - b.DocId;
        }
        return (reverse) ? -result : result;
    }

    private int CompareScore(LuceneHitCollectorItem a, LuceneHitCollectorItem b)
    {
        int result = a.DocId - b.DocId;
        if (a.Score != b.Score)
        {
            result = (a.Score > b.Score) ? 1 : -1;
        }
        return (reverse) ? -result : result;
    }
}

LuceneHitCollector collector = new LuceneHitCollector(reader);
searcher.Search(query, collector);
collector.Sort(field, reverse);
for (int index = 0; index < hits.Count; index++)
{
    LuceneHitCollectorItem item = hits.Doc(index);
    Document doc = item.Doc;
    double rank = item.Score;
    //process document
}

Speeding up Lucene Index

Lucene is indexing and search technology, as well as spellchecking, hit highlighting and advanced analysis/tokenization capabilities. .NET version is automatic Java Lucene port.
Solution works perfect in most cases but recently I've found it too slow. Directory can be stored in file system or in memory. While search indexes are cached in memory document contents are loaded each time from directory. I haven't checked Java implementation but .NET seems to parse file very slow. File system version requires additionally lots of disc access, which is probably well cached by operating system but not efficent for large indexes (in my case file size is over 500MB). Memory directory implementation tends to leak which is unacceptable.
Solution below demonstrates how to enable document caching in Lucene.
Cache needs to be added to FieldsReader class. Code below shows only changes that needs to be made:
  • Cache directory needs to be added.
  • Cache needs to be clear at the end of Close() method.
  • Document is returned from cache if already loaded at the beginning of Doc() method.
  • Document is added to cache after read in Doc() method.
This change has big memory cost but speeds up large queries even up to 10 times.
Further optimization can be found here.

public sealed class FieldsReader
{
    private SortedList<int,Document> cache=new SortedList<int, Document>();
//---------
    public void Close()
    {
//---------
        cache.Clear();
    }
//---------
    public Document Doc(int n)
    {
        if (cache.ContainsKey(n))
        {
            return cache[n];
        }
//---------
        if (!cache.ContainsKey(n))
        {
            cache.Add(n, doc);
        }
        return doc;
    }
//---------

20100326

Listing your Twitter messages by RSS

Frequently it's useful to list your Twitter messages on web other website or process them in some other way. There are billions of plugins that will allow you to do it but if you need to download them manually it's best to use RSS. You don't need to use API so you don't need to register. Only disadvantage is that you need user ID not his name. You can obtain it from user page - there is a RSS link in right hand column - number in that link is user ID that needs to be passed to the code.

Code below consists of three classes that will get twitts for you. There is also caching so remember that new messages will be fetched only every UPDATE_EVERY_MINUTES minutes.

Single message:

public class TwitterCacheItem
    {
        public string Title {get;set;}
        public string Link {get;set;}
        public string Description {get;set;}
    }

All of them:

public class TwitterCacheChannel : TwitterCacheItem
    {
        public TwitterCacheChannel()
        {
            Items = new List();
            Loaded = false;
        }

        public DateTime NextUpdateTime { get; set; }
        public bool Loaded { get; set; }
        public List Items { get; private set; }
    }

And finally the code:

public class TwitterCache
    {
        private const int UPDATE_EVERY_MINUTES = 60;

        private static SortedList cache = new SortedList();
        private static object cacheLock = new object();


        public static TwitterCacheChannel GetTwitts(int id)
        {
            TwitterCacheChannel result = null;
            lock (cacheLock)
            {
                if (cache.ContainsKey(id))
                {
                    result = cache[id];
                }
            }
            if ((result==null)||
                (result.NextUpdateTime<DateTime.Now))
            {
                result = FetchTwitts(id);
            }
            return result;
        }

        private static string FetchTwittsUrl(int id)
        {
            return String.Format("http://twitter.com/statuses/user_timeline/{0}.rss", id);
        }

        private static TwitterCacheChannel FetchTwitts(int id)
        {
            TwitterCacheChannel result = new TwitterCacheChannel();
            if (id > 0)
            {
                try
                {
                    string url = FetchTwittsUrl(id);
                    string rssText = DownloadWebPage(url);
                    XmlDocument rss = new XmlDocument();
                    rss.LoadXml(rssText);
                    XmlElement channel = rss["rss"]["channel"];
                    result.Title = channel["title"].InnerText;
                    result.Link = channel["link"].InnerText;
                    result.Description = channel["description"].InnerText;
                    foreach (XmlElement node in channel.SelectNodes("item"))
                    {
                        TwitterCacheItem item = new TwitterCacheItem();
                        item.Title = node["title"].InnerText;
                        item.Link = node["link"].InnerText;
                        item.Description = node["description"].InnerText;
                        result.Items.Add(item);
                    }
                    result.Loaded = true;
                }
                catch
                {
                }
            }
            result.NextUpdateTime = DateTime.Now.AddMinutes(UPDATE_EVERY_MINUTES);
            lock (cacheLock)
            {
                if (cache.ContainsKey(id))
                {
                    cache[id] = result;
                }
                else
                {
                    cache.Add(id, result);
                }
            }
            return result;
        }

        private static string DownloadWebPage(string url)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            request.UserAgent = ".NET Framework/2.0";
            request.Referer = "http://www.example.com/";
            WebResponse response = request.GetResponse();
            Stream webStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(webStream);
            string result = reader.ReadToEnd();
            reader.Close();
            webStream.Close();
            response.Close();
            return result;
        }
    }

20100318

Debugging Deadlocks in ASP .NET

Deadlock detection

Deadlock is reported in Event Viewer

Section: Application
Source: W3SVC-WP
ID: 2262
Desc: ISAPI 'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll' reported itself as unhealthy for the following reason: 'Deadlock detected'.

and

Section: System
Source: W3SVC
ID: 1013
Desc: A process serving application pool 'xxx' exceeded time limits during shut down. The process id was 'xxx'.

Server configuration

After detecting deadlock IIS kills old and creates new process.
To prevent it enable the Orphan Worker Process feature.

WARNING: Orphaned Worker Processes must be killed manually to free resources and memory.

cd \Inetpub\adminscripts
adsutil.vbs SET W3SVC/AppPools/DefaultAppPool/OrphanWorkerProcess TRUE

where DefaultAppPool should be replaced with proper Application Pool name
List of Application Pools together with Process Ids can be obtained by IISAPP tool (type iisapp in cmd).

You can use automatic dump collector but it seems that better get it by hand.

Dump collecting

Best way to get dump is using DebugDiag tool.
Go to Processes tab right-click on selected process and select Create Full Userdump.

Quick dump analysis

Using DebugDiag you can quickly get info from created dump.
Right-click on .dmp file and select Analyze Crash/Hang Issue it will show you

Stack trace of each Thread
All current requests
But it won't load symbols for your application.
Better way is to use WINDBG described below.

Detailed dump analysis

Procedure is described here.

1. Install Debugging Tools.
2. Run C:\Program Files\Debugging Tools for Windows\windbg.exe.
3. Open Crash Dump (form File menu)
4. Important commands:
.symfix binpath
.reload
.loadby sos mscorwks
.cordll -ve -u -l
!threads
~* e !clrstack
Last line should display all threads with call stacks and symbols resolved.

System.Threading.Monitor.Enter means that thread waits on lock (...) {...} statement.

What can possibly go wrong?

Wrong CLR version

!threads command says:

CLRDLL: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscordacwks.dll:2.0.50727.3053 f:0
doesn't match desired version 2.0.50727.3082 f:0
CLRDLL: Unable to find mscordacwks_x86_x86_2.0.50727.3082.dll by mscorwks search
CLRDLL: Unable to find 'mscordacwks_x86_x86_2.0.50727.3082.dll' on the path
CLRDLL: Unable to find mscorwks.dll by search
CLRDLL: ERROR: Unable to load DLL mscordacwks_x86_x86_2.0.50727.3082.dll, Win32 error 0n2
Failed to load data access DLL, 0x80004005

Solution

Install all Service Packs from here.

.NET Framework 2.0 Service Pack 2
.NET Framework 3.0 Service Pack 2
.NET Framework 3.5 Service Pack 1

20100317

EpiServer - Itera.MultiProperty examples

MultiProperty by Itera is very useful EpiServer extension.

Two basic ways of using MultiProperty are described on a blog by Anders Hattestad.

Basics

Most common way to use MultiProperty is to create set of fields and then create second property that allows user to create list of those items.

Let's assume user needs to provide list of ExampleItem.

public class ExampleItem
    {
        public string Field { get; set; }
        public string Regex { get; set; }        
        public string Default { get; set; }
    }

First you have to create property that lets user enter single item.

public class PropertyExampleField : PropertySingleBase
    {
        protected const string PROPERTY_NAME_FIELD = "Field";
        protected const string PROPERTY_NAME_REGEX = "Regex";
        protected const string PROPERTY_NAME_DEFAULT = "Default";

        PropertyDataCollection _innerPropertyCollection;
        protected override PropertyDataCollection InnerPropertyCollection
        {
            get
            {
                if (_innerPropertyCollection == null)
                {
                     _innerPropertyCollection =
                        new PropertyDataCollection
                            {
                                {PROPERTY_NAME_FIELD, new PropertyString()},
                                {PROPERTY_NAME_REGEX, new PropertyString()},
                                {PROPERTY_NAME_DEFAULT, new PropertyString()},
                            };
                }
                return _innerPropertyCollection;
            }
            set { _innerPropertyCollection = value; }
        }

        public string Field
        {
            get { return (PropertyCollection[PROPERTY_NAME_FIELD].Value as string) ?? ""; }
            set { PropertyCollection[PROPERTY_NAME_FIELD].Value = value; }
        }

        public string Regex
        {
            get { return PropertyCollection[PROPERTY_NAME_REGEX].Value as string; }
            set { PropertyCollection[PROPERTY_NAME_REGEX].Value = value; }
        }    

        public string Default
        {
            get { return PropertyCollection[PROPERTY_NAME_DEFAULT].Value as string; }
            set { PropertyCollection[PROPERTY_NAME_DEFAULT].Value = value; }
        }

        public ExampleItem ExampleItem
        {
            get
            {
                return new ExampleItem
                           {
                               Field = Field,
                               Regex = Regex,
                               Default = Default
                           };
            }
        }
    }

Then you have to create property that lets user create list of items.

[Serializable]
    [PageDefinitionTypePlugIn(DisplayName = "List of ExampleField")]
    public class ExampleFieldList : PropertyMultiBase
    {
        PropertyDataCollection baseProperties;
        public override PropertyDataCollection BaseProperties
        {
            get
            {
                if (baseProperties == null)
                {
                    baseProperties = new PropertyDataCollection { { "ExampleField", new PropertyExampleField() } };
                }
                return baseProperties;
            }
        }

        public List ExampleItems
        {
            get
            {
                List result = new List();
                foreach (PropertyExampleField item in PropertyCollection)
                {
                    result.Add(item.ExampleItem);
                }
                return result;
            }
        }

    }

Advanced

You can sort fields on save - it will help users to deal with long lists. You can remove empty fields - but you have to remember to let user have one empty so he can add new items. To achieve it override SerializeToXmlNode method in ExampleFieldList class.

public override System.Xml.XmlNode SerializeToXmlNode(PropertyDataCollection propCollection, PropertyDataCollection basePropertys, Dictionary newGuids)
        {
            List fields = new List();
            bool firstEmpty = true;
            foreach (PropertyData data in propCollection)
            {
                PropertyExampleField field = data as PropertyExampleField;
                if (field == null)
                {
                    continue;
                }
                if (field.Field != "")
                {
                    fields.Add(field);
                }
                else
                {
                    if (firstEmpty)
                    {
                        fields.Add(field);
                        firstEmpty = false;
                    }
                }
            }
            fields.Sort((a, b) => a.Field.CompareTo(b.Field));
            PropertyDataCollection newPropCollection = new PropertyDataCollection();
            foreach (PropertyExampleField data in fields)
            {
                newPropCollection.Add(data);
            }
            return base.SerializeToXmlNode(newPropCollection, basePropertys, newGuids);
        }

You an also force some mandatory items to be placed on the list each time user enters edit mode. To achieve it override ParseToSelf method in ExampleFieldList class.

Example below adds 3 fields named aaa, bbb and ccc.
Even if user removes any of them they will be recreated next time anyone enters edit mode.

public override void ParseToSelf(string xml, PropertyDataCollection propCollection, PropertyDataCollection basePropertys)
        {
            base.ParseToSelf(xml, propCollection, basePropertys);            
            string fieldList = "aaa,bbb,ccc";
            foreach (string part in fieldList.Split(",".ToCharArray()))
            {
                string fieldName = part.Trim();
                if (fieldName == "")
                {
                    continue;
                }
                bool found = false;
                foreach (PropertyData data in propCollection)
                {
                    PropertyExampleField field = data as PropertyExampleField;
                    if (field == null)
                    {
                        continue;
                    }
                    if (field.ExampleItem.Field == fieldName)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    propCollection.Add(
                        new PropertyExampleField 
                                           {
                                               Name = String.Format("ExampleField_{0}", Guid.NewGuid()),
                                               Field = fieldName,
                                               Regex = "",
                                               Default = ""
                                           });
                }
            }
        }

20100316

Binding Fluent NHibernate session to WCF call

First you should read previous post about WCF Session.

You have to modify the example provided in mentioned post. While binding the Endpoint Extension to the Call Context you need to open and close session.

public class ExampleEndpointContextInitializer : ICallContextInitializer
    {
        public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
        {
            bool found = false;
            foreach (IExtension extension in OperationContext.Current.Extensions)
            {
                if (extension is ExampleEndpointExtension)
                {
                    found = true;
                    break;
                }
            }
            if (!found)
            {
                OperationContext.Current.Extensions.Add(new ExampleEndpointExtension());
            }
            return ExampleSessionProvider.Instance.OpenSession();
        }

        public void AfterInvoke(object correlationState)
        {
            ExampleSessionProvider.Instance.CloseSession(((ISession)correlationState));
            ((IDisposable)correlationState).Dispose();
        }
    }

The class below will bind Fluent NHibernate session to HttpContext if exists otherwise it will try to bind to WCF context.

public class ExampleSessionProvider
    {
        private const string SESION_KEY = "SESSION_KEY";

        private ExampleSessionProvider()
        {

        }

        private static ExampleSessionProvider instance;

        public static ExampleSessionProvider Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new ExampleSessionProvider();
                }
                return instance;
            }
        }

        private ISessionFactory sessionFactory;

        public void CreateSessionFactory()
        {
            sessionFactory = Fluently.Configure();                
                .ExposeConfiguration(BuildSchema)
                .BuildSessionFactory();
            // add more configuration options above !!!
        }

        public ISession GetSession()
        {
            if (HttpContext.Current != null)
            {
                return sessionFactory.GetCurrentSession();
            }
            if (OperationContext.Current != null)
            {
                foreach (IExtension extension in OperationContext.Current.Extensions)
                {
                    if (extension is ExampleEndpointExtension)
                    {
                        if (((ExampleEndpointExtension)extension).State.ContainsKey(SESION_KEY))
                        {
                            return (ISession)((ExampleEndpointExtension)extension).State[SESION_KEY];
                        }
                    }
                }
            }
            return null;
        }

        public ISession OpenSession()
        {
            ISession session = sessionFactory.OpenSession();

            if (HttpContext.Current != null)
            {
                ManagedWebSessionContext.Bind(
                    HttpContext.Current, session);
            }
            else if (OperationContext.Current != null)            
            {
                foreach (IExtension extension in OperationContext.Current.Extensions)
                {
                    if (extension is ExampleEndpointExtension)
                    {
                        if (((ExampleEndpointExtension)extension).State.ContainsKey(SESION_KEY))
                        {
                            ((ExampleEndpointExtension)extension).State.Remove(SESION_KEY);
                        }
                        ((ExampleEndpointExtension)extension).State.Add(SESION_KEY, session);
                    }
                }
            }
            return session;
        }

        public void CloseSession()
        {
            CloseSession(null);
        }

        public void CloseSession(ISession session)
        {
            if ((session != null) && (HttpContext.Current != null))
            {
                session = ManagedWebSessionContext.Unbind(HttpContext.Current, sessionFactory);
            }
            if (session != null)
            {
                if (session.Transaction != null &&
                    session.Transaction.IsActive)
                {
                    session.Transaction.Rollback();
                }
                else
                {
                    session.Flush();
                }
                session.Close();
            }
        }

        private static void BuildSchema(Configuration config)
        {
            config.SetProperty("current_session_context_class", "managed_web");
        }
    }

Before binding to HttpContext you need to create HttpModule described in post about Binding Fluent NHibernate session to HttpContext or you can remove parts related to HttpContext and bind always to WCF call.

Binding Fluent NHibernate session to HttpContext

It is very useful and common practice to bind Fluent NHibernate session to HttpContext. Easiest way to do it is to create HttpModule.

public class ExampleSessionModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += OpenSession;
            context.EndRequest += CloseSession; 
        }

        private void OpenSession(object sender, EventArgs e)
        {
            ExampleSessionProvider.Instance.OpenSession();            
        }
        
        private void CloseSession(object sender, EventArgs e)
        {
            ExampleSessionProvider.Instance.CloseSession();
        } 

        public void Dispose()
        {
            
        }
    }

The you just need a session provider.

public class ExampleSessionProvider
    {
        private const string SESION_KEY = "SESSION_KEY";

        private ExampleSessionProvider()
        {

        }

        private static ExampleSessionProvider instance;

        public static ExampleSessionProvider Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new ExampleSessionProvider();
                }
                return instance;
            }
        }

        private ISessionFactory sessionFactory;

        public void CreateSessionFactory()
        {
            sessionFactory = Fluently.Configure();                
                .ExposeConfiguration(BuildSchema)
                .BuildSessionFactory();
            // add more configuration options above !!!
        }

        public ISession GetSession()
        {
            if (HttpContext.Current != null)
            {
                return sessionFactory.GetCurrentSession();
            }           
            return null;
        }

        public ISession OpenSession()
        {
            ISession session = sessionFactory.OpenSession();
            ManagedWebSessionContext.Bind(HttpContext.Current, session);            
            return session;
        }

        public void CloseSession()
        {
            ISession session = ManagedWebSessionContext.Unbind(HttpContext.Current, sessionFactory);            
            if (session != null)
            {
                if (session.Transaction != null &&
                    session.Transaction.IsActive)
                {
                    session.Transaction.Rollback();
                }
                else
                {
                    session.Flush();
                }
                session.Close();
            }
        }

        private static void BuildSchema(Configuration config)
        {
            config.SetProperty("current_session_context_class", "managed_web");
        }
    }

And a bit of web.config configuration:
<system.web>
<httpModules>
<add name="ExampleSessionModule" type="Example.Session.ExampleSessionModule, Example" />
</httpModules>
</system.web>

OR (depending on IIS version)

<system.webServer>
<modules>
<add name="ExampleSessionModule" type="Example.Session.ExampleSessionModule, Example" />
</modules>
</system.webServer>

Last thing to do is to create session factory in Application Start event.

protected void Application_Start(Object sender, EventArgs e)
{
    ExampleSessionProvider.Instance.CreateSessionFactory();
}

20100315

WCF Session

You may need to define object that behaves like HttpSession and bind it to the WCF request. It's pretty useful when you want to keep Fluent NHibernate session opened during WCF call.

First define the Endpoint Extension that will hold the session state.

public class ExampleEndpointExtension : IExtension
    {
        public ExampleEndpointExtension()
        {
            State = new Dictionary();
        }

        public IDictionary State { get; private set; }

        public void Attach(OperationContext owner) { }
        public void Detach(OperationContext owner) { }
    }

Then you need to bind it to the Call Context.

public class ExampleEndpointContextInitializer : ICallContextInitializer
    {
        public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
        {
            bool found = false;
            foreach (IExtension extension in OperationContext.Current.Extensions)
            {
                if (extension is ExampleEndpointExtension)
                {
                    found = true;
                    break;
                }
            }
            if (!found)
            {
                OperationContext.Current.Extensions.Add(new ExampleEndpointExtension());
            }
            return new object();
        }

        public void AfterInvoke(object correlationState)
        {            
        }
    }

Last class to implement is Endpoint Behaviour Extension.

public class ExampleEndpointBehavior : BehaviorExtensionElement,IEndpointBehavior
    {

        public override Type BehaviorType
        {
            get { return typeof(ExampleEndpointBehavior); }
        }

        protected override object CreateBehavior()
        {
            return new ExampleEndpointBehavior();
        }

        public void Validate(ServiceEndpoint endpoint)
        {            
        }

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {            
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
            EndpointDispatcher endpointDispatcher)
        {
            foreach (DispatchOperation operation in endpointDispatcher.DispatchRuntime.Operations)
            {
                operation.CallContextInitializers.Add(new ExampleEndpointContextInitializer());
            }
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {            
        }
    }

You should add your extension in web.config (or app.config).
Remember to define assembly together with version and culture. There's a bug in framework that will cause load fail if you omit it.
<behaviorextensions>
    <add name="ExampleBehaviorExtension" type="Example.Session.ExampleEndpointBehavior, Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>

Now you can use it:

foreach (IExtension extension in OperationContext.Current.Extensions)
{
    if (extension is ExampleEndpointExtension)
    {
        ((ExampleEndpointExtension)extension).State["SESSION_ITEM"] = "test";
    }
}

Example of usage in next post Binding Fluent NHibernate session to WCF call.

Fluent NHibernate - List of Int as String

Having field of type List it is sometimes worthy to save it in database as string rather than create separate table just to keep few values per record.
It seems to be completely wrong from design point of view but can be much cleaner solution when you have just few values per record.

To map this easily in Fluent create just two classes.
Then just define your field as IList.

User type convention:
public class IntListConvention : IUserTypeConvention
    {
        public bool Accept(IProperty target)
        {
            return target.PropertyType == typeof(IList);
        }

        public void Apply(IProperty target)
        {
            target.CustomTypeIs(typeof(IntListUserType));
        }

        public bool Accept(Type type)
        {
            return type == typeof(IList);
        }
    }

And new user type:
class IntListUserType : IUserType
    {
        public new bool Equals(object x, object y)
        {
            return x != null && x.Equals(y);
        }

        public int GetHashCode(object x)
        {
            return x.GetHashCode();
        }

        object IUserType.NullSafeGet(IDataReader rs, string[] names, object owner)
        {
            string stringValue = (string) NHibernateUtil.String.NullSafeGet(rs, names[0]) ?? String.Empty;
            List result = new List();
            foreach (string stringItem in stringValue.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
            {
                int item;
                if (Int32.TryParse(stringItem, out item))
                {
                    result.Add(item);
                }
            }
            return result;
        }

        public void NullSafeSet(IDbCommand cmd, object value, int index)
        {
            StringBuilder stringValue = new StringBuilder();
            List result = value as List;
            if (value != null)
            {
                foreach (int item in result)
                {
                    if (stringValue.Length > 0)
                    {
                        stringValue.Append(",");
                    }
                    stringValue.Append(item);
                }
            }
            ((IDataParameter)cmd.Parameters[index]).Value = stringValue.ToString();
        }

        public object DeepCopy(object value)
        {
            return value;
        }

        public object Replace(object original, object target, object owner)
        {
            return original;
        }

        public object Assemble(object cached, object owner)
        {
            return cached;
        }

        public object Disassemble(object value)
        {
            return value;
        }

        public SqlType[] SqlTypes
        {
            get
            {
                return new[] { new SqlType(DbType.String, 1000) };
            }
        }

        public Type ReturnedType
        {
            get
            {
                return typeof(List);
            }
        }

        public bool IsMutable
        {
            get
            {
                return false;
            }
        }
    }

Shrinking MSSQL log files

Best solution I've found below.
You just have to replace XYZ with database name in few places.
You can also uncomment print to get filename.
Yes, I know it would be useful to have version that iterates through all the databases - I'm just too lazy.

alter database XYZ set recovery simple
GO
alter database XYZ set recovery full
GO
use XYZ
GO
declare @filename sysname
select @filename=Name from sys.database_files where Type=1
--print @filename
DBCC Shrinkfile(@filename,100) 
GO
alter database XYZ set recovery bulk_logged
GO