0

Update

I have since realised the underlying cause of this problem, and have detailed it in another question, here: How Can I Use Custom Validation Attributes on Child Models of a DB Entity?


I have a WebsiteConfiguration model that consists of a number of sub models, broken down as such for convenience.

public class WebsiteConfiguration
{

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    public TitleAuthorAndPublishingConfiguration TitleAuthorAndPublishing { get; set; }

    public BookChaptersAndSectionsConfiguration BookChaptersAndSections { get; set; }

    public SocialMediaLoginsConfiguration SocialMediaLogins { get; set; }

    public TagGroupsConfiguration TagGroups { get; set; }
}

I am trying to add a DataAnnotation to one of the sub models, making certain properties required if another is marked as true. Like this:

public class SocialMediaLoginsConfiguration
{
    public bool Initialised { get; set; }

    public bool IsLoginWithFacebookEnabled { get; set; }

    [RequiredIfEnabled("IsLoginWithFacebookEnabled")]
    public string LoginWithFacebookAppID { get; set; }

    [RequiredIfEnabled("IsLoginWithFacebookEnabled")]
    public string LoginWithFacebookAppSecret { get; set; }
}

The DataAnnotation code is:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = false)]
public class RequiredIfEnabledAttribute : ValidationAttribute
{
    private string _ifWhatIsEnabled { get; set; }


    public RequiredIfEnabledAttribute(string IfWhatIsEnabled)
    {
        _ifWhatIsEnabled = IfWhatIsEnabled;
    }


    protected override ValidationResult IsValid(object currentPropertyValue, ValidationContext validationContext)
    {
        var isEnabledProperty = validationContext.ObjectType.GetProperty(_ifWhatIsEnabled);
        if (isEnabledProperty == null)
        {
            return new ValidationResult(
                string.Format("Unknown property: {0}", _ifWhatIsEnabled)
            );
        }
        var isEnabledPropertyValue = (bool)isEnabledProperty.GetValue(validationContext.ObjectInstance, null);

        if (isEnabledPropertyValue == true)
        {
            if (String.IsNullOrEmpty(currentPropertyValue.ToString()))
            {
                return new ValidationResult(String.Format("This field is required if {0} is enabled", isEnabledProperty));
            }
        }
        return ValidationResult.Success;
    }
}

When I attempt to get the value of IsLoginWithFacebookEnabled it looks for this property in the WebsiteConfiguration class, rather than the SocialMediaLoginsConfiguration. Even though the annoted property is in the latter.

How can I make it look for the property within the same class as the annotation?


Update

I think this is happening because I am calling DB.SaveChanges() on the WebsiteConfiguration, like this:

    public void SeedWebsiteConfiguration()
    {
        var titleAuthorAndPublishingConfiguration = new TitleAuthorAndPublishingConfiguration()
        {
            // seed values
        };
        var bookChaptersAndSectionsConfiguration = new BookChaptersAndSectionsConfiguration()
        {
            // seed values
        };
        var socialMediaLoginConfiguration = new SocialMediaLoginsConfiguration()
        {
            // seed values
        };
        var tagGroupsConfiguration = new TagGroupsConfiguration()
        {
            // seed values
        };
        var websiteConfiguration = new WebsiteConfiguration()
        {
            TitleAuthorAndPublishing = titleAuthorAndPublishingConfiguration,
            BookChaptersAndSections = bookChaptersAndSectionsConfiguration,
            SocialMediaLogins = socialMediaLoginConfiguration,
            TagGroups = tagGroupsConfiguration
        };
        DB.WebsiteConfiguration.Add(websiteConfiguration);
        DB.SaveChanges();
    }

But I don't want to create separate DB tables for each of the sub models. I'd like them stored together in one table, but in the code I'd like to manage them as sub models.

Community
  • 1
  • 1
Martin Hansen Lennox
  • 2,837
  • 2
  • 23
  • 64
  • Your attribute should inherit `ValidationAttribute`, not `RequiredAttribute`. The `validationContext` will be the class of the property you apply the attribute to - i.e. `SocialMediaLoginsConfiguration`, not `WebsiteConfiguration` –  Nov 02 '15 at 21:27
  • Thanks Stephen. I've tried doing that, and updated the question to reflect the change. But `validationContext.ObjectType` still comes up in the debugger as `WebsiteConfiguration` rather than `SocialMediaLoginsConfiguration`. I must have done something wrong somewhere. Does the above `RequiredIfEnabledAttribute` look correct to you? – Martin Hansen Lennox Nov 02 '15 at 23:35
  • Its a bit confusing and not sure what `IsEnabledOption.Enabled` is supposed to be. Typically the constructor would be something like `public RequiredIfAttribute(string propertyName, object value) {` where `value` in your case would be `true` or `false` and used as `[RequiredIf("IsLoginWithFacebookEnabled", true)]` since the condition is based on a `bool` property. I'll copy you code into my project and test it shortly –  Nov 02 '15 at 23:41
  • I was editing the comment but exceeded the time limit. I copied and pasted the wrong bit of code there. Gimmie 2 mins I am editing the question now to make things clearer. – Martin Hansen Lennox Nov 02 '15 at 23:44
  • Tested your validation attribute and it works fine. The value of `validationContext.ObjectContext` is `"SocialMediaLoginsConfiguration "` (not `"WebsiteConfiguration"`) –  Nov 02 '15 at 23:57
  • Thanks for taking the time to. I really appreciate that. Could the problem be that I am calling `SaveChanges()` on the WebsiteConfiguration model (as in the update above)? – Martin Hansen Lennox Nov 03 '15 at 00:01
  • Not sure, and can't test it obviously so I suspect that may be the source of your problem :) –  Nov 03 '15 at 00:03
  • Darn it. But thank you :) – Martin Hansen Lennox Nov 03 '15 at 00:12

0 Answers0