0

This post is related to Nested Try/Catch Blocks

Here's my model:

public class Benefits
{
    public int Id { get; set; }
    public Guid? ResponseId { get; set; }
    public decimal? MedicalTotal { get; set; }
    public decimal? StdSicknessAccident { get; set; }
    public decimal? LtdWage { get; set; }
    public decimal? MedicalPremiums { get; set; }
    public decimal? DentalPremiums { get; set; }
    public decimal? VisionCare { get; set; }
    public decimal? RetireePremiums { get; set; }
    public decimal? LifeInsurance { get; set; }
    public decimal? Prescription { get; set; }
    public decimal? MedAdmin { get; set; }
    public decimal? MedOther { get; set; }
    public decimal? HsaFsa { get; set; }
    public decimal? PtoTotal { get; set; }
    public decimal? Holidays { get; set; }
    public decimal? Pto { get; set; }
    public decimal? Vacations { get; set; }
    public decimal? SickLeave { get; set; }
    public decimal? PtoOther { get; set; }
    public decimal? RetirementTotal { get; set; }
    public decimal? X401k {get; set; }
    public decimal? DefinedBenefit { get; set; }
    public decimal? CashBalance { get; set; }
    public decimal? RetirementAdmin { get; set; }
    public decimal? RetirementOther { get; set; }
    public decimal? MiscTotal { get; set; }
    public decimal? Severance { get; set; }
    public decimal? Dependent { get; set; }
    public decimal? Tuition { get; set; }
    public decimal? Relocation { get; set; }
    public decimal? Total { get; set; }
}

Users are uploading an Excel file with rows in this identical order (they aren't uploading their own Id or ResponseId). I've started writing if statements to catch errors as such:

bool success = Decimal.TryParse(table[0], out decimal MedicalTotal);
if (success)
{
    b.MedicalTotal = MedicalTotal;
}
else
{
    model.ErrorList.Add("Medical total cell should be formatted as Currency, Accounting, or Number.");
}

bool success1 = Decimal.TryParse(table[1], out decimal StdSicknessAccident);
if (success1)
{
    b.StdSicknessAccident = StdSicknessAccident;
}
else
{
    model.ErrorList.Add("STD, Sickness, and Accident Insurance cell should be formatted as Currency, Accounting, or Number.");
}

bool success2 = Decimal.TryParse(table[2], out decimal LtdWage);
if (success2)
{
    b.LtdWage = LtdWage;
}
else
{
    model.ErrorList.Add("LTD & Wage Insurance cell should be formatted as Currency, Accounting, or Number.");
}

bool success3 = Decimal.TryParse(table[3], out decimal MedicalPremiums);
if (success3)
{
    b.MedicalPremiums = MedicalPremiums;
}
else
{
    model.ErrorList.Add("Medical Premiums cell should be formatted as Currency, Accounting, or Number.");
}

This is an easy enough process, but I feel that, given the repetitive nature of it, there might be some way to loop through my model fields and accomplish the same task. I'd be okay with adding a [Display(Name="Medical Total")] or some other metadata to each model field. I've also considered adding a new table to my context that houses all the error messages (Is this a best practice?).

So is there an alternative to my solution, which would be significantly shorter? Something like:

List<bool> success = new List<bool>();
for(var i = 1; i<Benefits.FieldCount; i++)
{
    success[i] = decimal.TryParse(Table[i], out decimal Benefits.Field[i]
};

if(success[i])
{
    b.Field[i] = Benefits.Field[i];
}
else
{
    model.ErrorList.Add(Benefits.Field[i].Name "must be formatted as Accounting, Currency, or Number.");
}
CarenRose
  • 1,266
  • 1
  • 12
  • 24
extensionhelp
  • 564
  • 1
  • 4
  • 18
  • You're looking for Reflection. – SLaks Jan 16 '19 at 00:06
  • You should look into model validation in asp.net. You can apply validation attributes at the property level for simple validation, and then you can do more complex validation for the whole model in the `Validate()` method of an `IValidatableObject`. See: https://stackoverflow.com/questions/3400542/how-do-i-use-ivalidatableobject – Jonathan Jan 16 '19 at 00:16

2 Answers2

0

you can use reflection for this, here is an example :

    Type type = typeof(Benefits);
    PropertyInfo[] properties = type.GetProperties();
    foreach (PropertyInfo property in properties)
    {
         // your logic here
        Console.WriteLine("{0} = {1}", property.Name, property.GetValue(benefitsInstance, null));
    }

    Console.Read();
Aldo
  • 204
  • 1
  • 7
0

I would forgo all the complexity and just use Custom Validation Attributes.

public class Foo : ValidationAttribute
{
    private readonly string _name;

    public Foo(string name)
    {
        _name = name;
    }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        // if the value is null, don't go further
        if (value == null) return ValidationResult.Success;

        // if the value cannot be parsed as a decimal (not valid)
        if (!Decimal.TryParse(value, out decimal d))
        {
            // return an error message
            return new ValidationResult($"{_name} cell should be formatted as...");
        }

        // if the parsed decimal is negative
        if (d < 0)
        {
            // return an error message
            return new ValidationResult($"{_name} cell cannot be negative.");
        }

        // if we got this far it was a success
        return ValidationResult.Success;
    }        
}

then simply decorate your properties with the validation attribute

[Foo("STD, Sickness, and Accident Insurance")]
decimal? StdSicknessAccident { get; set; }

[Foo("LTD & Wage Insurance")]
decimal? LtdWage { get; set; }
Svek
  • 12,350
  • 6
  • 38
  • 69