1

I have data class using DataContract and implementing field validation using System.ComponentModel.DataAnnotations.

In my class, the type attribute renders some fields relevant while others are not applicable. That is, some fields, depending on the type attribute, will become invalid while others are valid.

I am trying to find a good pattern to validate such conditions in an elegant fashion. I am open to accepting that running into this situation might mean I need to break my class in a few chunks to accommodate such polymorphism. Although not sure how.

Just in case it is relevant, those data classes will be serialized and stored on ServiceFabric reliable collections. This validation if more from an API perspective.

As of today, I am performing the validation in this way (which I do not find satisfactory) in the endpoint controller.

if (voucher.ServiceType == ServiceType.VaccineCompany)
            {
                if (voucher.Asignee == null)
                {
                    throw new ArgumentNullException("Asignee is required for company vaccine voucher");
                }
                if (!voucher.BookingTime.HasValue)
                {
                    throw new ArgumentNullException("Booking time is required for company vaccine voucher");
                }
                if (!voucher.FixedPrice.HasValue)
                {
                    throw new ArgumentNullException("Fixed price is required for company vaccine voucher");
                }
                if (voucher.Discount.HasValue)
                {
                    throw new ArgumentNullException("Discount is not a valid argument for company vaccine type voucher");
                }
            }

            if (voucher.ServiceType == ServiceType.Vaccine)
            {
                if (voucher.Asignee != null)
                {
                    throw new ArgumentException("Invalid argument asignee");
                }
                if (voucher.BookingTime.HasValue)
                {
                    throw new ArgumentNullException("Invalid argument booking time");
                }
                if (voucher.FixedPrice.HasValue && voucher.Discount.HasValue)
                {
                    throw new ArgumentException("Fixed price and discount cannot be set simultaneously");
                }
            }

This is how the model looks like:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;

namespace Remoting.VoucherService
{
    [DataContract]

    public sealed class Voucher
    {
        [Required(ErrorMessage = "Code is required")]
        [DataMember(Name = "code")]
        public string Code { get; set; }

        [Required(ErrorMessage = "Description is required")]
        [DataMember(Name = "description")]
        public string Description { get; set; }

        [Required(ErrorMessage = "ServiceType is required")]
        [DataMember(Name = "serviceType")]
        public ServiceType ServiceType { get; set; }

        [DataMember(Name = "discount")]
        public double? Discount { get; set; }

        [DataMember(Name = "fixedPrice")]
        public double? FixedPrice { get; set; }

        [DataMember(Name = "isValid")]
        public bool Valid {
            get { return TimesUsed < MaxUsage; }
            set { }
        }

        [DataMember(Name = "maxUsage")]
        public uint MaxUsage { get; set; } = 1;

        [DataMember(Name = "asignee")]
        public string Asignee;

        [DataMember(Name = "bookingTime")]
        public DateTime? BookingTime;

        [DataMember(Name = "timesUsed")]
        public uint TimesUsed { get; set; } = 0;

        public void IncreaseUsage()
        {
            TimesUsed += 1;
        }

        private ExtensionDataObject data;

        public ExtensionDataObject ExtensionData
        {
            get => data;
            set => data = value;
        }
    }
}

I hope somebody can provide me with some insights!

0 Answers0