Transactional attribute kills controller

0 views
Skip to first unread message

Symon Rottem

unread,
Nov 18, 2008, 8:55:01 AM11/18/08
to castle-pro...@googlegroups.com
Hi Guys,

I don't know if anyone else has seen this, but I'm getting a weird exception as soon as I apply a [Transactional] attribute to a controller class.  We're using the NHibernateFacility and WindsorIntegrationFacility and want to get that transaction management goodness happening too.

I'm using a base class which has other attributes applied to it (filters, resources, etc) and everything works fine but as soon as I apply the [Transactional] attribute to the actual controller class things blow up. 

It looks like it's happening when the view attempts to render and I'm wondering if this is being caused because DynamicProxy is creating a proxy of the controller and that something that was available to the view on the real controller isn't visible on the proxy.  Note, this is happening on actions that are non transactional as well as transactional ones and regardless of whether or not they are virtual.

Has anyone seen this and is there a suggested workaround?

The exception stacktrace is below:

[NullReferenceException: Object reference not set to an instance of an object.]
NVelocity.Util.Introspection.VelGetterImpl.get_MethodName() +9
NVelocity.Runtime.Parser.Node.ASTIdentifier.Execute(Object o, IInternalContextAdapter context) +1017
NVelocity.Runtime.Parser.Node.ASTReference.Execute(Object o, IInternalContextAdapter context) +178
NVelocity.Runtime.Parser.Node.ASTReference.Render(IInternalContextAdapter context, TextWriter writer) +55
NVelocity.Runtime.Parser.Node.SimpleNode.Render(IInternalContextAdapter context, TextWriter writer) +55
NVelocity.Template.Merge(IContext context, TextWriter writer) +135
Castle.MonoRail.Framework.Views.NVelocity.NVelocityViewEngine.Process(String viewName, TextWriter output, IEngineContext context, IController controller, IControllerContext controllerContext) +309
Castle.MonoRail.Framework.Services.DefaultViewEngineManager.Process(String templateName, TextWriter output, IEngineContext context, IController controller, IControllerContext controllerContext) +132
Castle.MonoRail.Framework.Controller.ProcessView() +66
InvocationProcessView_44.InvokeMethodOnTarget() +14
Castle.DynamicProxy.AbstractInvocation.Proceed() +40
Castle.Facilities.AutomaticTransactionManagement.TransactionInterceptor.Intercept(IInvocation invocation) +80
Castle.DynamicProxy.AbstractInvocation.Proceed() +70
OperationControllerProxyfd136e2982754fb5b5a417b6556fcf94.ProcessView() +88
Castle.MonoRail.Framework.Controller.RunActionAndRenderView() +1379
Castle.MonoRail.Framework.Controller.Process(IEngineContext engineContext, IControllerContext context) +32
InvocationProcess_13.InvokeMethodOnTarget() +63
Castle.DynamicProxy.AbstractInvocation.Proceed() +40
Castle.Facilities.AutomaticTransactionManagement.TransactionInterceptor.Intercept(IInvocation invocation) +80
Castle.DynamicProxy.AbstractInvocation.Proceed() +70
OperationControllerProxyfd136e2982754fb5b5a417b6556fcf94.Process(IEngineContext engineContext, IControllerContext context) +120
Castle.MonoRail.Framework.BaseHttpHandler.Process(HttpContext context) +77

[MonoRailException: Error processing MonoRail request. Action ShowOperationSelection on controller Operation]
Castle.MonoRail.Framework.BaseHttpHandler.Process(HttpContext context) +300
Castle.MonoRail.Framework.BaseHttpHandler.ProcessRequest(HttpContext context) +4
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +358
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +64

--
Symon Rottem
http://blog.symbiotic-development.com

Ayende Rahien

unread,
Nov 18, 2008, 8:58:06 AM11/18/08
to castle-pro...@googlegroups.com
Can you create an isolated test case?

Symon Rottem

unread,
Nov 18, 2008, 10:00:15 AM11/18/08
to castle-pro...@googlegroups.com
Hm, OK.

I've managed to tighen things down a little.  It appears to be a problem that occurs when the [Transactional] attibute is being used with  the [Resource] attrubte.

The controller TestConntroller.cs:

    [Transactional]
    [Resource("CommonResources", "Extranet.Resources.Resources")]
    public class TestController : SmartDispatcherController
    {
        public void Test()
        {
        }
    }

The view Test.vm:

I am $CommonResources.Name

If the [Transactional] attribute is not present but the [Resource] attribute is then the view returns:

I am Symon.

If the Resource attribute is not present but the [Transactional] attribute is then the view returns:

I am $CommonResources.Name

If both are present the request throws an exception:
[NullReferenceException: Object reference not set to an instance of an object.]
NVelocity.Util.Introspection.VelGetterImpl.get_MethodName() +9
NVelocity.Runtime.Parser.Node.ASTIdentifier.Execute(Object o, IInternalContextAdapter context) +1017
NVelocity.Runtime.Parser.Node.ASTReference.Execute(Object o, IInternalContextAdapter context) +178
NVelocity.Runtime.Parser.Node.ASTReference.Render(IInternalContextAdapter context, TextWriter writer) +55
NVelocity.Runtime.Parser.Node.SimpleNode.Render(IInternalContextAdapter context, TextWriter writer) +55
NVelocity.Template.Merge(IContext context, TextWriter writer) +135
Castle.MonoRail.Framework.Views.NVelocity.NVelocityViewEngine.Process(String viewName, TextWriter output, IEngineContext context, IController controller, IControllerContext controllerContext) +309
Castle.MonoRail.Framework.Services.DefaultViewEngineManager.Process(String templateName, TextWriter output, IEngineContext context, IController controller, IControllerContext controllerContext) +132
Castle.MonoRail.Framework.Controller.ProcessView() +66
   InvocationProcessView_38.InvokeMethodOnTarget() +14

Castle.DynamicProxy.AbstractInvocation.Proceed() +40
Castle.Facilities.AutomaticTransactionManagement.TransactionInterceptor.Intercept(IInvocation invocation) +80
Castle.DynamicProxy.AbstractInvocation.Proceed() +70
   TestControllerProxya1055b51128c41bfbba0561426905786.ProcessView() +88

Castle.MonoRail.Framework.Controller.RunActionAndRenderView() +1379
Castle.MonoRail.Framework.Controller.Process(IEngineContext engineContext, IControllerContext context) +32
   InvocationProcess_7.InvokeMethodOnTarget() +63

Castle.DynamicProxy.AbstractInvocation.Proceed() +40
Castle.Facilities.AutomaticTransactionManagement.TransactionInterceptor.Intercept(IInvocation invocation) +80
Castle.DynamicProxy.AbstractInvocation.Proceed() +70
   TestControllerProxya1055b51128c41bfbba0561426905786.Process(IEngineContext engineContext, IControllerContext context) +120
Castle.MonoRail.Framework.BaseHttpHandler.Process(HttpContext context) +77

[MonoRailException: Error processing MonoRail request. Action Test on controller Test]

Castle.MonoRail.Framework.BaseHttpHandler.Process(HttpContext context) +300
Castle.MonoRail.Framework.BaseHttpHandler.ProcessRequest(HttpContext context) +4
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +358
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +64

Still using WindsorIntegration. Does that help?

Cheers,

Symon.

hammett

unread,
Nov 18, 2008, 4:01:12 PM11/18/08
to castle-pro...@googlegroups.com
Somewhere in the code we're using GetType and expecting to be
controller (or comparing to controller) when in fact it will be the
dyn proxy type.
I dont have time to investigate this now, but if you look at some of
the code, there are special treatments for proxy types on MR code (and
Windsor too IIRC)
--
Cheers,
hammett
http://hammett.castleproject.org/

Symon Rottem

unread,
Nov 18, 2008, 5:56:47 PM11/18/08
to castle-pro...@googlegroups.com
Thanks Hammett.

I've kept digging and (although I'm really not sure what I'm doing here) I think the original stack track was a simple bug that covered another, possibly more difficult one.  Seems to be my day for this...*sigh* :)

The code for the NVelocity assembly has the following property getter in the NVelocity.Util.Introspection.UberspectImpl.VelGetterImpl class:

            public String MethodName
            {
                get
                {
                    if (abstractExecutor.Property.Name != null)
                    {
                        return abstractExecutor.Property.Name;
                    }

                    if (abstractExecutor.Method != null)
                    {
                        return abstractExecutor.Method.Name;
                    }

                    return "undefined";
                }
            }

The null reference exception was being thrown because the Property property of the abstractExecutor was null.  Changing this line to...


if (abstractExecutor.Property != null && abstractExecutor.Property.Name != null)

...fixed the null reference exception...however I'm not sure whether or not this getter is supposed to throw if Property == null.  My guess is not and that this is an unusual circumstance.

To add additional information, the point where it's failing is when attempting to execute the get_Item method when attempting to get the value that corresponds to the key "Name" from the Resource file.  The single line in the view is correctly parsed, the "Name" token of "$CommonResources.Name" is located and the failure occurs when attempting to get the value that corresponds to this token.  The new exception is as follows:
[NotSupportedException: The invoked member is not supported in a dynamic assembly.]
System.Reflection.Emit.AssemblyBuilder.GetManifestResourceNames() +54
System.Resources.ResourceManager.CaseInsensitiveManifestResourceStreamLookup(Assembly satellite, String name) +134
System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents) +391
System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents) +509
System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents) +509
System.Resources.ResourceManager.GetObject(String name, CultureInfo culture, Boolean wrapUnmanagedMemStream) +79
System.Resources.ResourceManager.GetObject(String name, CultureInfo culture) +11
Castle.MonoRail.Framework.Resources.ResourceFacade.get_Item(String key) +35

[MethodInvocationException: Invocation of method 'get_Item' in Castle.MonoRail.Framework.Resources.ResourceFacade, template Test\Test.vm Line 1 Column 23 threw an exception]
NVelocity.Runtime.Parser.Node.ASTIdentifier.Execute(Object o, IInternalContextAdapter context) in D:\My Documents\Visual Studio Projects\Xpedite\Papa Extranet\Castle\Tools\NVelocity\src\NVelocity\Runtime\Parser\Node\ASTIdentifier.cs:159
NVelocity.Runtime.Parser.Node.ASTReference.Execute(Object o, IInternalContextAdapter context) in D:\My Documents\Visual Studio Projects\Xpedite\Papa Extranet\Castle\Tools\NVelocity\src\NVelocity\Runtime\Parser\Node\ASTReference.cs:177
NVelocity.Runtime.Parser.Node.ASTReference.Render(IInternalContextAdapter context, TextWriter writer) in D:\My Documents\Visual Studio Projects\Xpedite\Papa Extranet\Castle\Tools\NVelocity\src\NVelocity\Runtime\Parser\Node\ASTReference.cs:195
NVelocity.Runtime.Parser.Node.SimpleNode.Render(IInternalContextAdapter context, TextWriter writer) in D:\My Documents\Visual Studio Projects\Xpedite\Papa Extranet\Castle\Tools\NVelocity\src\NVelocity\Runtime\Parser\Node\SimpleNode.cs:234
NVelocity.Template.Merge(IContext context, TextWriter writer) in D:\My Documents\Visual Studio Projects\Xpedite\Papa Extranet\Castle\Tools\NVelocity\src\NVelocity\Template.cs:177
Castle.MonoRail.Framework.Views.NVelocity.NVelocityViewEngine.Process(String viewName, TextWriter output, IEngineContext context, IController controller, IControllerContext controllerContext) in D:\My Documents\Visual Studio Projects\Xpedite\Papa Extranet\Castle\MonoRail\Castle.MonoRail.Framework.Views.NVelocity\NVelocityViewEngine.cs:172
Castle.MonoRail.Framework.Services.DefaultViewEngineManager.Process(String templateName, TextWriter output, IEngineContext context, IController controller, IControllerContext controllerContext) +187
Castle.MonoRail.Framework.Controller.ProcessView() +87
TestControllerProxyc500c0323ac241498ce3bc57735c1445.ProcessView_callback_38() +23
InvocationProcessView_38.InvokeMethodOnTarget() +27
Castle.DynamicProxy.AbstractInvocation.Proceed() +55
Castle.Facilities.AutomaticTransactionManagement.TransactionInterceptor.Intercept(IInvocation invocation) +150
Castle.DynamicProxy.AbstractInvocation.Proceed() +144
TestControllerProxyc500c0323ac241498ce3bc57735c1445.ProcessView() +109
Castle.MonoRail.Framework.Controller.RunActionAndRenderView() +1824
Castle.MonoRail.Framework.Controller.Process(IEngineContext engineContext, IControllerContext context) +52
TestControllerProxyc500c0323ac241498ce3bc57735c1445.Process_callback_7(IEngineContext engineContext, IControllerContext context) +32
InvocationProcess_7.InvokeMethodOnTarget() +88
Castle.DynamicProxy.AbstractInvocation.Proceed() +55
Castle.Facilities.AutomaticTransactionManagement.TransactionInterceptor.Intercept(IInvocation invocation) +150
Castle.DynamicProxy.AbstractInvocation.Proceed() +144
TestControllerProxyc500c0323ac241498ce3bc57735c1445.Process(IEngineContext engineContext, IControllerContext context) +148
Castle.MonoRail.Framework.BaseHttpHandler.Process(HttpContext context) +130


[MonoRailException: Error processing MonoRail request. Action Test on controller Test]
   Castle.MonoRail.Framework.BaseHttpHandler.Process(HttpContext context) +396
Castle.MonoRail.Framework.BaseHttpHandler.ProcessRequest(HttpContext context) +28

System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +358
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +64

What's got me stumped here is that the method invoke get_Item(System.String) with the parameter "Name"  appears to be on an instance of the ResourceFacade class so I wouldn't have thought it was a dynamic assembly.  Anyway, to make a long story short, I'm dazed and confused and quite possibly going down the wrong path.  I understand that this might well be related to the generated controller proxy but i can't see how...anyone got any further suggestions for me? :)

Cheers,

Symon.

hammett

unread,
Nov 18, 2008, 7:03:00 PM11/18/08
to castle-pro...@googlegroups.com
I guess this goes back to what Fabian keeps saying. Our generated
proxy class shouldnt re-add the properties, it causes problems.


> To add additional information, the point where it's failing is when
> attempting to execute the get_Item method when attempting to get the value
> that corresponds to the key "Name" from the Resource file. The single line
> in the view is correctly parsed, the "Name" token of "$CommonResources.Name"
> is located and the failure occurs when attempting to get the value that
> corresponds to this token. The new exception is as follows:
>
> [NotSupportedException: The invoked member is not supported in a dynamic
> assembly.]
> System.Reflection.Emit.AssemblyBuilder.GetManifestResourceNames() +54
>
>
> System.Resources.ResourceManager.CaseInsensitiveManifestResourceStreamLookup(Assembly
> satellite, String name) +134
> System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo
> culture, Boolean createIfNotExists, Boolean tryParents) +391

Obviously there's an implementation error somewhere that is trying to
pull the resources from the dynamic generated assembly, instead of
your app's assembly...
Again, this is possibly a code that looks like

this.GetType()

where in 99% of cases will point to your controller class, but for
dynproxies, will be the dynamic generated one, and hence the problem.

hammett

unread,
Nov 19, 2008, 2:43:46 AM11/19/08
to castle-pro...@googlegroups.com
Problem was on Controller.cs line 1526. Fixed on my branch. Please
copy the fix and see how it goes...

Symon Rottem

unread,
Nov 19, 2008, 6:10:27 PM11/19/08
to castle-pro...@googlegroups.com
Thanks Hammett.

Perfect!

Cheers,

Symon.

Eric Hauser

unread,
Dec 9, 2008, 9:53:03 AM12/9/08
to Castle Project Development List
Which branch is this fix in? I am looking to apply the same fix.


On Nov 19, 6:10 pm, "Symon Rottem" <s.rot...@gmail.com> wrote:
> Thanks Hammett.
>
> Perfect!
>
> Cheers,
>
> Symon.
>
>
>
> On Wed, Nov 19, 2008 at 8:43 AM, hammett <hamm...@gmail.com> wrote:
>
> > Problem was on Controller.cs line 1526. Fixed on my branch. Please
> > copy the fix and see how it goes...
>

hammett

unread,
Dec 9, 2008, 11:48:35 AM12/9/08
to castle-pro...@googlegroups.com

Eric Hauser

unread,
Dec 9, 2008, 12:17:48 PM12/9/08
to Castle Project Development List
Thanks. I was also getting the same error proxying my controllers w/
resources (not using ATM), and I can verify that this fixes the
problem.
Reply all
Reply to author
Forward
0 new messages