Null Reference Exception in Utilities.CallByName CSLA 3.6.1 (Please Help)

Null Reference Exception in Utilities.CallByName CSLA 3.6.1 (Please Help)

Old forum URL: forums.lhotka.net/forums/t/6279.aspx


Jack posted on Wednesday, January 28, 2009

I'm completely stuck on an issue with updating managed properties that have a ValidationRule attached to them.  Basically it seems that the first time I call SetProperty and there is an attached business rule it is it crashing.  It has something to do with instantiating as if I trap the exception and make the same call again then I am fine.

I have loaded my data, done data binding, and then I am setting a property in code.  I traced it through to the CallByName method in Utilities.cs (see stack trace) and it is failing on the highlighted line [
return p.GetValue(target, args);] as p is null

public static object CallByName(
      object target, string methodName, CallType callType,
      params object[] args)
    {
      switch (callType)
      {
        case CallType.Get:
          {
            PropertyInfo p = target.GetType().GetProperty(methodName);
            return p.GetValue(target, args);
          }
        case CallType.Let:


>    Csla.dll!Csla.Utilities.CallByName(object target = {Epm.Library.DataEntry.DataCollection}, string methodName = "DataEntryId", Csla.CallType callType = Get, object[] args = {object[0]}) Line 43    C#
     Csla.dll!Csla.Validation.CommonRules.StringMaxLength(object target = {Epm.Library.DataEntry.DataCollection}, Csla.Validation.RuleArgs e = {DataEntryId?MaxLength=20&Format=}) Line 64 + 0x38 bytes    C#
     Csla.dll!Csla.Validation.RuleMethod.Invoke(object target = {Epm.Library.DataEntry.DataCollection}) Line 103 + 0x1d bytes    C#
     Csla.dll!Csla.Validation.ValidationRules.CheckRules(System.Collections.Generic.List<Csla.Validation.IRuleMethod> list = Count = 1) Line 1087 + 0xf bytes    C#
     Csla.dll!Csla.Validation.ValidationRules.CheckRules(string propertyName = "DataEntryId") Line 996 + 0xb bytes    C#
     Csla.dll!Csla.Core.BusinessBase.PropertyHasChanged(string propertyName = "DataEntryId") Line 300 + 0x18 bytes    C#
     Csla.dll!Csla.Core.BusinessBase.LoadPropertyValue<string>(Csla.PropertyInfo<string> propertyInfo = {Csla.PropertyInfo<string>}, string oldValue = "CATTERHA", string newValue = "Jack", bool markDirty = true) Line 2583 + 0x2d bytes    C#
     Csla.dll!Csla.Core.BusinessBase.SetProperty<string>(Csla.PropertyInfo<string> propertyInfo = {Csla.PropertyInfo<string>}, string newValue = "Jack", Csla.Security.NoAccessBehavior noAccess = ThrowException) Line 2352 + 0x65 bytes    C#
     Csla.dll!Csla.Core.BusinessBase.SetProperty<string>(Csla.PropertyInfo<string> propertyInfo = {Csla.PropertyInfo<string>}, string newValue = "Jack") Line 2244 + 0x44 bytes    C#
     EPM.Library.dll!Epm.Library.DataEntry.DataCollection.DataEntryId.set(string value = "Jack") Line 107 + 0x17 bytes    C#
     EPM.Library.dll!Epm.Library.DataEntry.DataEntrySession.Save() Line 446 + 0x2a bytes    C#
     EpmWin.exe!EpmWin.DataEntrySessionForm.bSave_Click(object sender = {Text = "SaveData"}, System.EventArgs e = {X = 25 Y = 12 Button = Left}) Line 183 + 0x3e bytes    C#
     [External Code]   
     EpmWin.exe!EpmWin.Program.Main() Line 18 + 0x1d bytes    C#
     [External Code]   
I thought maybe it had to do with the _forceInit business but I'm fairly certain that everything is okay.  I've also upgraded to 3.6.1 which is suppose to remove that issue and I still have the problem.

I'm assuming its something I am doing but I'm baffled. I'm using an ObjectFactory to load all my objects.  I'm making the call from the parentRoot to update the property on the first element of a ChildList.

In case it helps this is my code to add the business rule:
            //DataEntryId
            ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs(DataEntryIdProperty, 20));

I'm even getting the same error when I try to update a property on my root class:

Csla.PropertyLoadException: Property load or set failed for property UpdatorId (Validation rule rule://Csla.Validation.CommonRules/StringMaxLength/UpdatorId?MaxLength=20&Format= failed in property UpdatorId) ---> Csla.Validation.ValidationException: Validation rule rule://Csla.Validation.CommonRules/StringMaxLength/UpdatorId?MaxLength=20&Format= failed in property UpdatorId ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at Csla.Utilities.CallByName(Object target, String methodName, CallType callType, Object[] args) in C:\Csla\Framework\cslacs\Csla\Utilities.cs:line 48
   at Csla.Validation.CommonRules.StringMaxLength(Object target, RuleArgs e) in C:\Csla\Framework\cslacs\Csla\Validation\CommonRules.cs:line 64
   at Csla.Validation.RuleMethod.Invoke(Object target) in C:\Csla\Framework\cslacs\Csla\Validation\RuleMethod.cs:line 103
   at Csla.Validation.ValidationRules.CheckRules(List`1 list) in C:\Csla\Framework\cslacs\Csla\Validation\ValidationRules.cs:line 1087
   --- End of inner exception stack trace ---
   at Csla.Validation.ValidationRules.CheckRules(List`1 list) in C:\Csla\Framework\cslacs\Csla\Validation\ValidationRules.cs:line 1097
   at Csla.Validation.ValidationRules.CheckRules(String propertyName) in C:\Csla\Framework\cslacs\Csla\Validation\ValidationRules.cs:line 996
   at Csla.Core.BusinessBase.PropertyHasChanged(String propertyName) in C:\Csla\Framework\cslacs\Csla\Core\BusinessBase.cs:line 300
   at Epm.Library.DataEntry.DataEntrySession.PropertyHasChanged(String propertyName) in C:\epm\SourceCode\EPM.Libary\DataEntry\DataEntrySession.cs:line 235
   at Csla.Core.BusinessBase.LoadPropertyValue[P](PropertyInfo`1 propertyInfo, P oldValue, P newValue, Boolean markDirty) in C:\Csla\Framework\cslacs\Csla\Core\BusinessBase.cs:line 2583
   at Csla.Core.BusinessBase.SetProperty[P](PropertyInfo`1 propertyInfo, P newValue, NoAccessBehavior noAccess) in C:\Csla\Framework\cslacs\Csla\Core\BusinessBase.cs:line 2352
   --- End of inner exception stack trace ---
   at Csla.Core.BusinessBase.SetProperty[P](PropertyInfo`1 propertyInfo, P newValue, NoAccessBehavior noAccess) in C:\Csla\Framework\cslacs\Csla\Core\BusinessBase.cs:line 2356
   at Csla.Core.BusinessBase.SetProperty[P](PropertyInfo`1 propertyInfo, P newValue) in C:\Csla\Framework\cslacs\Csla\Core\BusinessBase.cs:line 2244
   at Epm.Library.DataEntry.DataEntrySession.set_UpdatorId(String value) in C:\epm\SourceCode\EPM.Libary\DataEntry\Generated\DataEntrySession.Generated.cs:line 228
   at Epm.Library.DataEntry.DataEntrySession.Save() in C:\epm\SourceCode\EPM.Libary\DataEntry\DataEntrySession.cs:line 446
   at EpmWin.DataEntrySessionForm.bSave_Click(Object sender, EventArgs e) in C:\epm\SourceCode\EpmWin\EpmWin\DataEntrySessionForm.cs:line 183

I'm getting quite frustrated so any push in the right direction would be appreciated although I would like to understand what it is I am doing wrong.

Thanks

jack

RockfordLhotka replied on Thursday, January 29, 2009

Have you looked in the debugger to see the value of methodName at the point of failure? If so, what is that value?

Jack replied on Thursday, January 29, 2009

It is the name of the Property I am trying to update. In the simple case at
the bottom of my post - 'UpdatorId', in the big long stacktrace (same id)
'DataEntryId'.

Thanks

-----Original Message-----
From: RockfordLhotka [mailto:cslanet@lhotka.net]
Sent: Thursday, January 29, 2009 8:53 AM
To: jaddington@alexandergracie.com
Subject: Re: [CSLA .NET] Null Reference Exception in Utilities.CallByName
CSLA 3.6.1 (Please Help)

Have you looked in the debugger to see the value of methodName at the point
of failure? If so, what is that value?

Jack replied on Tuesday, February 03, 2009

Rocky, I have updated to 3.6.1 RC1 and I am still having this issue. Any thoughts? Anywhere else I can look or try or give you more information to help?

This is my call to add the business rule:

//UpdatorId
            ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs(UpdatorIdProperty, 20));

Thanks jack

 -----Original Message----- From: Jack Addington [mailto:cslanet@lhotka.net] Sent: Thursday, January 29, 2009 9:23 AM To: jaddington@alexandergracie.com Subject: RE: [CSLA .NET] Null Reference Exception in Utilities.CallByName CSLA 3.6.1 (Please Help) It is the name of the Property I am trying to update. In the simple case at the bottom of my post - 'UpdatorId', in the big long stacktrace (same id) 'DataEntryId'. Thanks -----Original Message----- From: RockfordLhotka [mailto:cslanet@lhotka.net] Sent: Thursday, January 29, 2009 8:53 AM To: jaddington@alexandergracie.com Subject: Re: [CSLA .NET] Null Reference Exception in Utilities.CallByName CSLA 3.6.1 (Please Help) Have you looked in the debugger to see the value of methodName at the point of failure? If so, what is that value?

RockfordLhotka replied on Tuesday, February 03, 2009

Can you create a small project - perhaps a console app - that has just a
class, your property and your AddRule() call? If it occurs in that scenario,
you can share the project with me and I'll see what I can do to track down
the issue.

The problem is that I have code using StringMaxLength and it works fine. As
you can imagine, I'm trying to help you troubleshoot through pure
speculation at this point, with no direct example of failure to work
against.

Rocky

bt1 replied on Tuesday, February 03, 2009

Could this be the force static initilization thing when there is a base classe between BusinessBase and the final class?

Add the following to EVERY class (change ClassName to the name of your class ie constructor)

#pragma warning disable 0414

private static int _forceInit;

#pragma warning restore 0414

private ClassName()

{ /* require use of factory methods */

_forceInit = 1;

}

 

protected override void OnDeserialized(StreamingContext context)

{

base.OnDeserialized(context);

_forceInit = 1;

}

Jack replied on Tuesday, February 03, 2009

Rocky,

The problem is that I defined the underlying property as internal (non-public).

I'm using a codeGen template so it just creates common rules for any basic database schema information it can find.

        internal string UpdatorId
        {
            get { return ReadProperty<string>(UpdatorIdProperty); }
            set { SetProperty<string>(UpdatorIdProperty, value); }
        }

I never want these variables visable or set via the UI so that made sense.  I scoured the 2008 book and didn't see any reference to not using the validation functions on non-public properties.  Also after the exception happens, I can actually try again and it works so something is slightly off??

I'm just putting together a console app to show it working/crashing.

Thanks

jack

RockfordLhotka replied on Tuesday, February 03, 2009

Oh.

 

In that case this behavior is by design. The CallByName() method is designed to replicate in C# a VB runtime feature that lets you call a method or property by name. Neither the VB nor C#-replica allow you to invoke non-public members of an object.

 

If you want to invoke a non-public member by name, you’ll need to create your own CallByName() equivalent.

 

Rocky

Jack replied on Tuesday, February 03, 2009

Rocky,

 

I don’t want to do anything extra – this is all invoked from the rules validation logic of the framework when making a call to SetProperty for a non-public property.

 

Are you saying that one cannot, by design, use the CommonRules validation logic with non-public managed properties?

 

Thanks

jack

 

 

From: Rockford Lhotka [mailto:cslanet@lhotka.net]
Sent: Tuesday, February 03, 2009 1:05 PM
To: jaddington@alexandergracie.com
Subject: RE: [CSLA .NET] RE: Null Reference Exception in Utilities.CallByName CSLA 3.6.1 (Please Help)

 

Oh.

 

In that case this behavior is by design. The CallByName() method is designed to replicate in C# a VB runtime feature that lets you call a method or property by name. Neither the VB nor C#-replica allow you to invoke non-public members of an object.

 

If you want to invoke a non-public member by name, you’ll need to create your own CallByName() equivalent.

 

Rocky



RockfordLhotka replied on Tuesday, February 03, 2009

I’m saying that you can’t use the CommonRules rule methods against non-public properties.

It doesn’t matter if the property is managed or not – the property must be public in scope:

public string MyProperty
{
}

You said your property is internal:

internal string MyProperty
{
}

That is not public, and so it won’t work.

RockfordLhotka replied on Tuesday, February 03, 2009

I’m saying that you can’t use the CommonRules rule methods against non-public properties.

 

It doesn’t matter if the property is managed or not – the property must be public in scope:

 

public string MyProperty

{

}

 

You said your property is internal:

 

internal string MyProperty

{

}

 

That is not public, and so it won’t work.

 

Rocky

 

Jack replied on Tuesday, February 03, 2009

Thank you for the clarification – is that something that could be added to the wishlist for managed properties? 

 

Can you not go through the FieldManager to get the property value instead  or maybe have some logic that if the call to CallByName returns null then try to check if the field is a managed property and then find the field? 

 

Thanks

jack

 

 

From: Rockford Lhotka [mailto:cslanet@lhotka.net]
Sent: Tuesday, February 03, 2009 3:30 PM
To: jaddington@alexandergracie.com
Subject: RE: [CSLA .NET] RE: Null Reference Exception in Utilities.CallByName CSLA 3.6.1 (Please Help)

 

I’m saying that you can’t use the CommonRules rule methods against non-public properties.

 

It doesn’t matter if the property is managed or not – the property must be public in scope:

 

public string MyProperty

{

}

 

You said your property is internal:

 

internal string MyProperty

{

}

 

That is not public, and so it won’t work.

 

Rocky

 



RockfordLhotka replied on Tuesday, February 03, 2009

I may consider tapping into the managed field mechanism to avoid reflection in CommonRules, yes. More likely, I’ll create a set of ManagedRules that mirror the current ones, but require the target object to use the field manager.

 

I think, looking into the future (of Silverlight and Windows Azure) that the idea of using private fields may become quaint :)

 

Rocky

 

Jack replied on Tuesday, February 03, 2009

RockfordLhotka:

I may consider tapping into the managed field mechanism to avoid reflection in CommonRules, yes. More likely, I’ll create a set of ManagedRules that mirror the current ones, but require the target object to use the field manager.

 

Ok Thanks

RockfordLhotka:

I think, looking into the future (of Silverlight and Windows Azure) that the idea of using private fields may become quaint :)

 

Care to expand?  I thought I was being smart having a whole slew of internal managed properties that I used to do everything  I needed within my assembly and then I was just exposing filtered (LINQ) or public properties for the UI and external processes.  Given I'm trying to do a Silverlight plugin I would like to avoid more issues in the future.

thanks

jack

 

RockfordLhotka replied on Tuesday, February 03, 2009

The primary reason the field manager exists is that I needed a way to serialize an object graph without using reflection. This is because Silverlight (and I suspect Azure) doesn’t allow private reflection.

 

Managed backing fields allow CSLA (the MobileFormatter) to serialize an object graph with full fidelity, and without reflection. Which is why mobile objects now extend into the Silverlight environment just as well as a Windows client.

 

Looking forward to Azure (if my assumption is correct), the same will apply. And if there ends up being a CSLA .NET 3.6 for CF the same restriction will apply.

 

Now you CAN use private backing fields with the MobileFormatter – you just have to write OnGetState() and OnSetState() methods in every one of your classes so you can get/set all your fields. If you worked in VB5 or 6 you probably did some of this, either with CSLA for COM or using the PropertyBag concept of the time. It is boring code, easy to get wrong and hard to debug.

 

So there’s a pretty strong incentive to use managed backing fields in the future, to support these three platforms without creating maintenance issues.

 

 

In terms of using internal properties – that’s entirely up to you. If your objects work well with WPF data binding, they’ll probably work pretty well with Silverlight as well. Obviously internal properties are not available to the UI or data binding of any sort.

 

I would be a bit suspicious about internal properties, only in as much as you might be using your objects for more than one purpose. And that would be bad OO design. An object should have exactly one responsibility – one job in life. And that responsibility should fit in the context of a single user task/use case/story.

 

So having a public interface for the UI, and a non-public interface for “other code” could imply that your objects are doing double-duty – which would probably violate the single responsibility principle.

 

Rocky

 

Jack replied on Tuesday, February 03, 2009

Here is a sample.

Toggling the internal/public causes the exceptions to be thrown or work fine.

Thanks

jack

Copyright (c) Marimer LLC