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