Tuesday, August 31, 2010

Broken AspView Sending Emails

One more broken thing I've noticed and had to fix in the source - you cannot send emails when using a layout (non-deprecated methods) from monorail. In order to fix this, I had to change one line in the asp view source. In AspViewEngine.Process(string, string, TextWriter, IDictionary):

Process(templateName, output, null, null, controllerContext);
changes to
Process(templateName, output, EngineContextLocator.Instance.LocateCurrentContext(), null, controllerContext);

The problem was that the context being passed into the next process step was null, and I was getting a null object ref when trying to send an email. With this fix in place, everything works as expected. Not sure if this is an oversight on the AspView creator's part or just an odd chain of events.

Castle Monorail/Activerecord on Mono

I have had a heck of time trying to get Monorail working fully on Mono (2.4, 2.6, and even the latest tarballs). After weeks of sorting through code, I think I have finally figured out the solutions to the most common problems I've encountered:

1) Invalid casts in the form helper select generation. This has taken me quite awhile to track down, and the solution is simple enough that I thought I would blog about it to remember what I done in the future. The problem is with casting and the proxies for AR objects. The AR objects that are proxies, when used in a form helper select can sometimes generate an InvalidCastException if they have already been used. I ended up getting the source from GitHub and modifying the form helper itself in the ReflectionValueGetter. Here is the full GetValue method I used in the AbstractFormHelper.cs:

public override object GetValue(object instance)
   {
    try
    {
     try
     {
      return propInfo.GetValue(instance, null);
     } 
     catch (InvalidCastException)
     {
      propInfo = propInfo.ReflectedType.BaseType.GetProperty(Name);
      return propInfo.GetValue(instance, null);
     }
    }
    catch (TargetException)
    {
     var tempProp = instance.GetType().GetProperty(Name);

     if (tempProp == null)
     {
      throw;
     }

     return tempProp.GetValue(instance, null);
    }
   }

The new code is in the extra try/catch InvalidCastException block.  It merely gets the base type and tries to find the property there if it was an invalid cast (ie Instrument being cast as InstrumentProxy).  More can be found here.

2) Asynchronous actions do not work in mono (at least using the AspView engine and the ActiveRecord integration). I finally tracked this down due to the incorrect or null context being assigned on the End method. Luckily, the fix is VERY easy, especially considering how long it took me to track down. Merely do "HttpContext.Current = HttpContext" in the end method of the action, and it will correctly release the ActiveRecord session in the web module or in your custom methods to attach/release the session. More here.