Null reference exception when using custom validation

Null reference exception when using custom validation

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


halcwb posted on Sunday, March 14, 2010

Following the instructions of the C# 2008 Business Objects book I have created the following root object:

using System;
using System.Linq;
using Csla;
using Csla.Data;
using Csla.Security;

namespace SimpleFormularium.Library
{
    [Serializable]
    public class Apotheek : BusinessBase<Apotheek>
    {
        #region Business Methods

        private static PropertyInfo<int> IdProperty =
            RegisterProperty(new PropertyInfo<int>("ApotheekId"));
        [System.ComponentModel.DataObjectField(true, true)]
        public int Id
        {
            get { return GetProperty(IdProperty); }
        }

        private static PropertyInfo<string> NameProperty =
            RegisterProperty(new PropertyInfo<string>("ApotheekNaam"));
        public string Naam
        {
            get { return GetProperty(NameProperty); }
            set { SetProperty(NameProperty, value); }
        }
       
        #endregion

        #region Business and Validation Rules

        protected override void AddBusinessRules()
        {
            //ValidationRules.AddRule(Csla.Validation.CommonRules.StringRequired,
            //    new Csla.Validation.RuleArgs(NameProperty));
            ValidationRules.AddRule(
                Csla.Validation.CommonRules.StringMaxLength,
                new Csla.Validation.CommonRules.MaxLengthRuleArgs(
                    NameProperty, 50));
        }

        #endregion

        #region Authorization Rules

        #endregion

        #region Factory Methods

        private Apotheek() { }

        public static Apotheek NewApotheek()
        {
            return DataPortal.Create<Apotheek>();
        }

        #endregion

        #region Data Access


        #endregion

        #region Exists

        #endregion

    }
}

When I test the methods of this object I get the following null reference exception:

Csla.DataPortalException was unhandled
  Message="DataPortal.Create failed (Csla.Validation.ValidationException: Validation rule rule://Csla.Validation.CommonRules/StringMaxLength/ApotheekNaam?MaxLength=50&Format= failed in property ApotheekNaam ---> System.NullReferenceException: Object reference not set to an instance of an object.\r\n   at Csla.Utilities.CallByName(Object target, String methodName, CallType callType, Object[] args) in D:\\Data\\VisualStudio\\csla3.8.2\\cslacs\\Csla\\Utilities.cs:line 48\r\n   at Csla.Validation.CommonRules.StringMaxLength(Object target, RuleArgs e) in D:\\Data\\VisualStudio\\csla3.8.2\\cslacs\\Csla\\Validation\\CommonRules.cs

I may have missed something obvious, but cannot see it.

Any suggestions?

P.s. Implementing a custom rule that does the same as the common rule is no problem.

halcwb replied on Sunday, March 14, 2010

Ok, the solution seems to be that the declaration of the property info should be as follows:

        private static PropertyInfo<string> NameProperty =
            RegisterProperty<string>(p => p.Naam, "ApotheekNaam");

Is this a breaking change from CSLA 3.6x to CSLA 3.8.2 I am currently using?

JonnyBee replied on Sunday, March 14, 2010

Hi,

No, this is caused by wrong parameters to PropertyInfo.The first parameter to the PropertyInfo constuctor must be the exact correctly spelled  PropertyName or a lambda expression. So in you code it should look like this:

        private static PropertyInfo<string> NameProperty =
            RegisterProperty(new PropertyInfo<string>("Naam", "ApotheekNaam"));

or

        private static PropertyInfo<string> NameProperty =
            RegisterProperty<string>(p => p.Naam, "ApotheekNaam");

When you attach a validation rule to your original property declaration the validation rule will try to read the value of a property named "ApoteekNaam" on your BO and this property does not exist => throws exception.

RockfordLhotka replied on Sunday, March 14, 2010

If the change is "breaking" it is only in so far as that CSLA was enhanced to catch and prevent what was rapidly becoming a common coding error. Jonny is right about the syntax options, but a lot of people (often through copy-paste mistakes) got the wrong type name in RegisterProperty().

This happens to me all the time with dependency properties too - similar syntax, same error.

It is better to use the lambda expression overload, as that avoids the issue and makes the code simpler and more maintainable. In 3.x you can't use the lambda syntax in a few places (command, criteria and identity objects), but that's being addressed (through a breaking change) in CSLA 4.

Copyright (c) Marimer LLC