3

I would like to know if there's a way to force the value of some properties to always be lowercase or uppercase when I receive the model at my controller. Preferably in a clean way, like using attributes.

Example:

Controller:

[HttpPost]
public async Task<Model> Post(Model model)
{
    //Here properties with the attribute [LowerCase] (Prop2 in this case) should be lowercase.
}

Model:

public class Model
{
    public string Prop1 { get; set; }

    [LowerCase]
    public string Prop2 { get; set; }
}

I've heard that changing values with a custom ValidationAttribute is not a good thing. Also decided to create a custom DataBinder, but didn't find exactly how I should implement it, when tried to, just received null in my controller.

jpcrrs
  • 63
  • 1
  • 6
  • `when tried to, just received null in my controller` - please [edit] the question and show what you tried for that, so we can help you fix the issue. – Peter B Dec 17 '18 at 14:14
  • so, do you want `Prop2` to be unaffected in other places (i.e. the database) but in the instance of your controller you'd like the conversion to take place? If so, could you create a new `ModelVM` that accepts `Model` in a constructor and does the conversion at that point? Then, in your controller you can take `ModelVM` and do what you need to with it. – scgough Dec 17 '18 at 14:16
  • Actually it can be persisted in the database as lowercase, so there's no need for a VM. I don't transform it in the Getter/Setter because there will be more transformations (not just uppercase/lowercase), so having an *Attribute* would be better for maintenance and searchability (there's a lot of models, would be nice to find which one are being transformed). Didn't put the DataBinder example here because wasn't dealing with transformation there, just trying to figure how it works. – jpcrrs Dec 17 '18 at 14:24

4 Answers4

3

Alternative solutions: Fluent API:

modelBuilder.Entity<Model>()
    .Property(x => x.Prop2)
    .HasConversion(
        p => p == null ? null : p.ToLower(),
        dbValue => dbValue);

Or, encapsulate within the class itself, using property with backing field:

private string _prop2;
public string Prop2
{ 
    get => _prop2;
    set => value?.ToLower();
}
dbardakov
  • 651
  • 1
  • 8
  • 22
1

Decided to use a custom JsonConverter.

public class LowerCase : JsonConverter
{
    public override bool CanRead => true;
    public override bool CanWrite => false;
    public override bool CanConvert(Type objectType) => objectType == typeof(string);

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return reader.Value.ToString().ToLower();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

public class Model
{
    public string Prop1 { get; set; }

    [JsonConverter(typeof(LowerCase))]
    public string Prop2 { get; set; }
}

Still think there's a better way tho, will keep looking for something.

jpcrrs
  • 63
  • 1
  • 6
0

You can make readonly property

 public string Prop2 { get{return Prop1.ToLower()}}

or like that

 public string Prop2 => Prop1.ToLower();
Ahmed Ghoniem
  • 661
  • 1
  • 8
  • 15
  • To me it doesn't look like OP wants `Prop1` and `Prop2` to be connected. – Peter B Dec 17 '18 at 14:13
  • Exactly, there's no relation between the two props. And as stated, I don't transform it in the Getter/Setter because there will be more transformations (not just uppercase/lowercase), so having an Attribute would be better for maintenance and searchability (there's a lot of models, would be nice to find which one are being transformed) – jpcrrs Dec 17 '18 at 14:28
  • oh okay you want to use `ValidationAttribute`. i think this would help you https://stackoverflow.com/a/6216679/6522459 – Ahmed Ghoniem Dec 17 '18 at 14:34
  • Actually I said that I don't want to use ValidationAttribute, it just doesn't seems right. IsValid doesn't seems to be a method to cause mutations, but just to validate if the input is right, I guess there's a better way of doing this. – jpcrrs Dec 17 '18 at 14:40
  • what about using DTO , or ViewModel and then map domain models with automapper – Ahmed Ghoniem Dec 17 '18 at 14:43
-1

You can build a class constructor like this:

public class Model
{
        public Model()
        {
            this.Prop2 = this.Prop2.ToLower();
        }
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
}
TempoClick
  • 169
  • 12