Alex
Alex

Reputation: 47

C# / MVC / Entity Access property from a refrenced model class when validating using IValidatableObject

I have created an WebAPI web app and I am validating the data by implementing the IValidatableObject. Based on the validation results an external API is being called and the data is being saved either if the model is valid or not. I've already created the logic for calling the external API.

My model has the below structure :

public class Class1
{
   public string Class1Prop { get; set; }
   public ICollection<Class1Data> Data { get; set; }
}

public class Class1Data : IValidatableObject
{
   public int Id { get; set; }
   public string Prop1{ get; set; }
   public string Prop2 { get; set; }
   ..
   public string Prop10 { get; set; }

   // Validate Model
   private bool validated = false;
   public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
   {
          if (!validated)
          {
                 if ((Prop1 != value1) || (Prop2 != value2) || .. )
                 {
                       // CALL EXTERNAL API
                 }
                 validated = true;
          }     
          yield return ValidationResult.Success;
   }
}       

WebAPI contoller for POST:

[ResponseType(typeof(Class1))]
public async Task<IHttpActionResult> PostClass1(Class1 class1)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    db.Class1.Add(class1);
    await db.SaveChangesAsync();

    return CreatedAtRoute("DefaultApi", new { id = Class1.Id }, class1);
}

I would like to include the value of Class1Prop when calling the external API from the Validate method within the Class2. I've tried to find out a way to do that and also searched for a method but could find one. As much as it's possible I would like to keep the structure of the model. I hope that my question makes any sense and sorry if it's not that documented.

Upvotes: 1

Views: 158

Answers (1)

Bob Dust
Bob Dust

Reputation: 2460

You probably need some kinds of delegation for referencing Class1.Class1Prop from within Class1Data:

public class Class1Data : IValidatableObject
{
    public int Id { get; set; }
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public string Prop10 { get; set; }

    public Func<string> AcquiresParentProp { get; set; }

    // Validate Model
    private bool validated = false;
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
          if (!validated)
          {
                 if ((Prop1 != value1) || (Prop2 != value2))
                 {
                       // CALL EXTERNAL API
                     if(AcquiresParentProp != null)
                     {
                         var parentProp = AcquiresParentProp();
                         // use parentProp
                     }
                 }
                 validated = true;
          }     
        yield return ValidationResult.Success;
    }
}

The method to set delegation can be placed in Class1:

public class Class1
{
    public string Class1Prop { get; set; }
    public ICollection<Class1Data> Data { get; set; }

    private string GetProp()
    {
        return Class1Prop;
    }

    public void ParentLookup()
    {
        foreach(var data in Data)
        {
            data.AcquiresParentProp = GetProp;
        }
    }
}

and that method can be called before validating:

    [ResponseType(typeof(Class1))]
    public async Task<IHttpActionResult> PostClass1(Class1 class1)
    {
        class1.ParentLookup();
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        db.Class1.Add(class1);
        await db.SaveChangesAsync();

        return CreatedAtRoute("DefaultApi", new { id = Class1.Id }, class1);
    }

Upvotes: 1

Related Questions