Data Annotations Issue - Metadata type or class annotations, not both

Data Annotations Issue - Metadata type or class annotations, not both

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


PaternostroTwo posted on Thursday, September 29, 2011

We are using partial classes for our generated CSLA code.  We are also using data annotations.  Our generated code contains data annotations based upon the database (e.g. InvoiceAmount which gets a generated data annotation of Required since the column is not nullable).  We do not modify our generated code, so we create a Metadata Type class which is where we add additional data annotations like amount needs to be between 0 and 100. 


When CSLA adds the business rules it is only adding the data annotations from the Metadata type class and not adding the ones from our class.  When there is no Metadata type CSLA takes the data annotations of the class.  So it seems CSLA takes either or, but not both.  I have modified the CSLA code, which we never do for upgrade purposes, and have included the code below.  Is this a feature of CSLA to only add the data annotations of the class or the metadata class or an issue?  When the enterprise validators validate objects, the validators take the data annotation of both the class and metadata type.  We want this same behavior for CSLA.

 Generated Class:

    [Serializable()]
    public partial class SampleInvoiceLineItem : Csla.BusinessBase<SampleInvoiceLineItem>
    {
        private static PropertyInfo<System.Decimal> AmountProperty = RegisterProperty<System.Decimal>(p => p.Amount, "Amount", 0.0M);
        [Required(ErrorMessage="Please enter an amount")]
        public System.Decimal Amount
        {
            get { return GetProperty(AmountProperty); }
            set { SetProperty(AmountProperty, value); }
        }
   }

Non-Generated Class:

    public class SampleInvoiceLineItemMetaDataClass
    {
        [Required(ErrorMessage = "Amount is required")]
        [Range(typeof(decimal), "1", "100", ErrorMessage = "Please enter a value between 1 and 100")]
        public System.Decimal Amount { get; set; }

        [Required(ErrorMessage = "Quantity is required")]
        [Range(1, 100, ErrorMessage = "Please enter a value between 1 and 100")]
        public System.Int32 Quantity { get; set; }

    }

    /// <summary>
    /// Non-Generate code that can be modified
    /// </summary>
    [MetadataType(typeof(SampleInvoiceLineItemMetaDataClass))]
    public partial class SampleInvoiceLineItem : Csla.BusinessBase<SampleInvoiceLineItem>
    {
    }

Modified CSLA code (BusinessRules.cs)

    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
    public void AddDataAnnotations()
    {
      Type metadataType;
#if SILVERLIGHT
      metadataType = _target.GetType();
#else
      var classAttList = _target.GetType().GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.MetadataTypeAttribute), true);
      bool addDataAnnotationsForClass = false; // Added by Adam
      if (classAttList.Length > 0)
      { // Added by Adam
          metadataType = ((System.ComponentModel.DataAnnotations.MetadataTypeAttribute)classAttList[0]).MetadataClassType;
          addDataAnnotationsForClass = true; // Added by Adam
      } // Added by Adam
      else
      { // Added by Adam
          metadataType = _target.GetType();
      } // Added by Adam
#endif

      // attributes on class
      var attList = metadataType.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.ValidationAttribute), true);
      foreach (var att in attList)
        AddRule(new CommonRules.DataAnnotation(null, (System.ComponentModel.DataAnnotations.ValidationAttribute)att));

      // attributes on properties
      var propList = metadataType.GetProperties();
      foreach (var prop in propList)
      {
        attList = prop.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.ValidationAttribute), true);
        foreach (var att in attList)
        {
          var target = (IManageProperties)_target;
          var pi = target.GetManagedProperties().Where(c => c.Name == prop.Name).First();
          AddRule(new CommonRules.DataAnnotation(pi, (System.ComponentModel.DataAnnotations.ValidationAttribute)att));
        }
      }

      // BEGIN:::::: Added by Adam
      if (addDataAnnotationsForClass)
      {
          metadataType = _target.GetType();

          // attributes on class
          attList = metadataType.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.ValidationAttribute), true);
          foreach (var att in attList)
              AddRule(new CommonRules.DataAnnotation(null, (System.ComponentModel.DataAnnotations.ValidationAttribute)att));

          // attributes on properties
          propList = metadataType.GetProperties();
          foreach (var prop in propList)
          {
              attList = prop.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.ValidationAttribute), true);
              foreach (var att in attList)
              {
                  var target = (IManageProperties)_target;
                  var pi = target.GetManagedProperties().Where(c => c.Name == prop.Name).First();
                  AddRule(new CommonRules.DataAnnotation(pi, (System.ComponentModel.DataAnnotations.ValidationAttribute)att));
              }
          }
      }
      // END:::::: Added by Adam
    }    

 

 

 

 

RockfordLhotka replied on Thursday, September 29, 2011

This sounds like a bug, and I have added it to the bug list.

Copyright (c) Marimer LLC