Archive

Archive for the ‘Castle’ Category

Castle ActiveRecord – Exception : The ProxyFactoryFactory was not configured

23 January, 2009 18 comments

I’ve just updated to the latest version of the Castle stack and got hit with this exception:

The ProxyFactoryFactory was not configured.
Initialize 'proxyfactory.factory_class' property of the session-factory configuration section with one of the available NHibernate.ByteCode providers.
Example:
NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu
Example:
NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle

Turns out the NHibernate config has changed and as the exception says you must now specify a factory class.

To fix the exception add a new line to your active record facility config:

<facility id="activerecord.facility" isweb="true" type="Castle.Facilities.ActiveRecordIntegration.ActiveRecordFacility, Castle.Facilities.ActiveRecordIntegration">

    <assemblies>

        <item>Nu.Core</item>

    </assemblies>

    <config>

        <add value="false" key="cache.use_query_cache" />

        <add value="ReadCommitted" key="connection.isolation" />

        <add value="false" key="show_sql" />

        <add value="NHibernate.Dialect.SQLiteDialect" key="dialect" />

        <add value="NHibernate.Driver.SQLite20Driver" key="connection.driver_class" />

        <add value="true=1;false=0" key="query.substitutions" />

        <add value="#{ConnectionString}" key="connection.connection_string" />

        <add value="NHibernate.Connection.DriverConnectionProvider" key="connection.provider" />

        <add value="NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle" key="proxyfactory.factory_class" />

    </config>

</facility>

Then add a reference in your project to NHibernate.ByteCode.Castle.dll.

Categories: ActiveRecord, Castle Tags: ,

MonoRail custom rescue controller (IRescueController)

9 January, 2009 1 comment
The problem

I am calling a web service from a controller and the web service throws a WebException with different exception messages, one when the remote server is unavailable and another when the remote server times out. I’d like to show a rescue view based on the exception type and message not just it’s type. 

The standard Monorail Rescue attribute only takes an exception type so there didn’t seem to be an easy way to solve my problem. I could have a generic rescue view which shows an error for all WebExceptions but I’d like to be a bit more specific. I could send all WebExceptions to the same rescue view and then handle the different messages in the view but I didn’t want the logic in my rescue view.

I noticed in the trunk (revision 5407) the Rescue attribute takes a rescue controller which I’d never seen before. I started digging around the web and source and came up with the following solution which works although I not sure its the best solution!

My solution

I changed my base controller to use a rescue controller instead of rescue views:

[Rescue(typeof(RescueController))]
public class ApplicationController : SmartDispatcherController

I then created a RescueController:

[Layout("default")]
public class RescueController : SmartDispatcherController, IRescueController
{
	public void Rescue(Exception exception, IController controller, IControllerContext controllerContext)
	{
		SetRescueView("generalerror");
		if (exception.GetType() == typeof(WebException) && exception.Message == "Unable to connect to the remote server") SetRescueView("webexception_cannot_connect");
		if (exception.GetType() == typeof(WebException) && exception.Message == "The operation has timed out") SetRescueView("webexception_portal_timeout");

	}

	private void SetRescueView(string viewname)
	{
		RenderSharedView(Path.Combine("rescues", viewname));
	}
}

The Rescue method simply checks the exception type and message and if it gets a match it sets the relevant rescue view. Notice I’m using a little helper method to set the rescue view this tells Monorail look in the standard folder Views\rescues for the view otherwise it would be looking for these views in Views\Rescue which could get confusing.

Gotchas!
  • Make sure your custom rescue controller inherits from SmartDispatcherController otherwise your custom controller will not get called. See Castle Project Users list for more detail
  • Add the Layout attribute to the Rescue controller if you want  to use your standard layout on the rescue pages.
  • If your using the Windsor container remember to add the Rescue controller to your container otherwise your custom rescue controller will not be found and called. This one had me scratching my head for a while!
  • Make sure your rescue views exist in the Views\rescues folder otherwise you will get the standard ASP.NET error page and it will look like none of this has worked.
  • This works with the trunk (revision 5407) not sure when the IRescueController functionality was added so it may not work with earlier revisions.
A better solution?

I thought a better solution would be to add a sub string message to the Rescue attribute which could be used to match the exception type and message. E.g:

Rescue("web_exception_unable_to_connect", typeof(WebException), "Unable to connect to remote server")
Rescue("web_exception_timeout", typeof(WebException), "The operation has timed out")

I couldn’t see an easy way to extend the standard Monorail rescue functionality so I ended up creating a builder which allowed me to define a map of exceptions to rescue views.

builder.Map<WebException>()
	.WithMessageContaining("Unable to connect to the remote server")
	.OrMessageContaining("The remote server returned an error: (403) Forbidden.")
	.ToRescue("webexception_cannot_connect");

builder.Map<WebException>()
	.WithMessageContaining("The operation has timed out")
	.ToRescue("webexception_portal_timeout");

My final rescue controller simply uses the map to select the correct rescue view, no more if statements needed.

[Layout("default")]
public class RescueController : SmartDispatcherController, IRescueController
{
	private readonly IExceptionToRescueMapper _mapper;

	public RescueController(IExceptionToRescueMapper mapper)
	{
		_mapper = mapper;
	}

	public void Rescue(Exception exception, IController controller, IControllerContext controllerContext)
	{
		SetRescueView(_mapper.GetRescueFor(exception));
	}

	private void SetRescueView(string viewname)
	{
		RenderSharedView(Path.Combine("rescues", viewname));
	}
}

If you know of a better way I’d love to hear it…

Categories: MonoRail Tags:

Castle + Using the Trunk + My registry entries

18 June, 2007 Comments off

When I build from the trunk I usually follow the instructions found here:

http://using.castleproject.org/display/CASTLE/Using+the+Trunk

My source location is slightly different from the instructions so I have to hand edit the registry entries listed at the end of the page. So to save me doing that again here they are:

Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Castle] "vs8templatelocation"="C:\\source\\Castle\\Tools\\VSNetWizards\\CastleTemplates\\VS8" [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v2.0.50727\AssemblyFoldersEx\castle] @="C:\\source\\Castle\\build\\net-2.0\\debug"

Categories: Castle Tags:

Monorail + NVelocity + How to find out if your in the first item of a foreach loop?

17 May, 2007 Comments off

A colleague needed to add a button to the first row of a table but how do you do this in a foreach loop?

NVelocity has a property called $velocityCount which you can check within the foreach loop:

<table>
#foreach($detail in $details)
  <tr>
    <td>
      $detail.ShortText)
      #if($velocityCount == 1) First Row! #end
    </td>
  </tr>
#end
</table>
Categories: MonoRail

Castle Monorail + Active Record + Testing + CreateSchemaFromFile

5 December, 2006 2 comments

It’s always a good idea to have your test database match your production database exactly to do that use:

ActiveRecordStarter.CreateSchemaFromFile()

Unlike CreateSchema which takes a best guess at how your schema should be CreateSchemaFromFile uses an SQL script which allows you to control exactly what the schema should be.

Call CreateSchemaFromFile as part of your PrepareSchema method in your AbstractTestCase class.

protected virtual void PrepareSchema()
{
// If you want to delete everything from the model.
// Remember to do it in a descendent dependency order
// Office.DeleteAll();
// User.DeleteAll();
// Another approach is to always recreate the schema
// (please use a separate test database if you want to do that)
ActiveRecordStarter.DropSchema();
ActiveRecordStarter.CreateSchemaFromFile("schema.sql");
}

Your schema.sql file should contain scripts in the standard MS SQL format:

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Application_Status]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[Application_Status]
GO

CREATE TABLE [dbo].[Application_Status] (
[ID] [int] NOT NULL ,
[Title] [varchar] (50) NOT NULL ,
[Description] [text] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

Categories: MonoRail

FW: Castle Projects + Monorail + 1.0 Release Candidate 2

10 November, 2006 Comments off

I’m a little late with this one (I’ve been busy honest!) the Castle project have a new release:

1.0 Release Candidate 2 – November 1st 2006

They have also have a jazzy new site and updated documentation too. Top work!

Categories: MonoRail

Castle Monorail + Active Record + Testing + CreateSchemaFromFile

27 July, 2006 Comments off

It’s always a good idea to have your test database match your production database exactly, we can do that easily using:

ActiveRecordStarter.CreateSchemaFromFile()

Unlike CreateSchema which makes a best guess at how your schema should be CreateSchemaFromFile takes an SQL script which allows you to fully control the database schema.

Call CreateSchemaFromFile as part of your PrepareSchema method in your AbstractTestCase class.

protected virtual void PrepareSchema()
{
ActiveRecordStarter.DropSchema();
ActiveRecordStarter.CreateSchemaFromFile("schema.sql");
}

Your schema.sql file should contain scripts in the standard MS SQL format:

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Application_Status]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[Application_Status]
GO

CREATE TABLE [dbo].[Application_Status] (
[ID] [int] NOT NULL ,
[Title] [varchar] (50) NOT NULL ,
[Description] [text] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

Categories: MonoRail