3

I've the following ZapScan class with a TargetUrl property whose purpose is to return the concatenation of the Url and Path properties.

The ZapScan class is also used as a parameter in a controller action, and thus is subject to model binding:

[HttpPost, FormatFilter]
    [Consumes("application/json", new string[]{"application/xml"})]
    public ActionResult<ZapScan> OnPost([FromBody] ZapScan scan)
    {
        return HandleRequest(scan);
    }

How can I prevent the TargetUrl property from being subject to model binding? Is it sufficient that it's a read-only property? What about the general case, where the property is also set-able?

public class ZapScan
{
   private string _url;
   private string _path;


   [XmlElement(IsNullable = true)]
   public string Url
   {
       get
       {
           return _url;
       }
       set
       {
           if (value is null)
           {
               throw new ArgumentNullException();
           }

           _url = value.EndsWith("/", StringComparison.Ordinal) ? value.Remove(value.Length - 1) : value;
       }
   }
   [XmlElement(IsNullable = true)]
   public string Path
   {
       get
       {
           return _path;
       }
       set
       {
           if (value is null)
           {
               _path = "";
           }
           else
           {
               _path = value.StartsWith("/", StringComparison.Ordinal) ? value : value.Remove(value.Length - 1);
           }
       }
   }
   public ScanType Type { get; set; } = ScanType.Active;

   public string TargetUrl
   {
       get
       {
           return Url + Path;
       }
   }

   public override string ToString() {
       return JsonSerializer.Serialize(this).ToLower();
   }
}

[Bind] attribute: I've been looking at the Bind attribute, but it doesn't appear to have a an Exclude property in ASP.NET Core Web API?

[Bind(Exclude = "Height, Width")]
Shuzheng
  • 11,288
  • 20
  • 88
  • 186
  • 1
    [`XmlIgnore`](https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlignoreattribute?view=netframework-4.8) – Heretic Monkey Dec 20 '19 at 14:17
  • Does this answer your question? [Prevent Property from being serialized](https://stackoverflow.com/questions/8397524/prevent-property-from-being-serialized) – Heretic Monkey Dec 20 '19 at 14:20
  • I believe there's a [BindNever] attribute you can use on the property. – HaukurHaf Dec 20 '19 at 14:20
  • If you are using entity-framework you can use [NotMapped] attribute – David Edel Dec 20 '19 at 16:58
  • @HereticMonkey - doesn’t `XmlIgnore` only apply to serialization and not to data binding? – Shuzheng Dec 20 '19 at 18:14
  • @HereticMonkey - isn’t data binding and serialization two different things? – Shuzheng Dec 20 '19 at 18:15
  • Why can not have different view model (like ZapScanForPost) without TargetUrl for POST? – sam Dec 20 '19 at 18:34
  • Because it would be redundant to have a second class thats just a copy of the first with one property unbound. There are attributes for this for a reason –  Dec 20 '19 at 19:14
  • Why did you want to prevent a property from being set through model binding?What the result you wanted?I test your code and could get the value like:`url:"aa",path:"bb",targetUrl:"aabb"`. – Rena Dec 25 '19 at 07:37
  • @Rena - because `TargetUrl` is only a convenience property that returns the concatenation of two other properties - it don’t need its own backing field. – Shuzheng Dec 25 '19 at 07:45

2 Answers2

1

Maybe a private setter on TargetUrl can help :

public string TargetUrl
{
    get
    {
        return Url + Path;
    }

    private set;
}

On the other hand, given that you are saying the framework to consume json, maybe just a JsonIgnore will do the trick

[JsonIgnore]
public string TargetUrl
{
    get
    {
        return Url + Path;
    }
}
Mauricio Atanache
  • 2,424
  • 1
  • 13
  • 18
  • 1
    I believe no set is similar to readonly not to private. I know readonly is more restrictive than private, but I think this worked for me in the past. – Mauricio Atanache Dec 20 '19 at 18:52
0

If the property is settable you can use [BindNever] on it. Like so:

using Microsoft.AspNetCore.Mvc.ModelBinding;

public class ZapScan
{
    // ...

    [BindNever]
    public string TargetUrl { get; set; }

    // ...
}

Here are the Microsoft docs explaining it.

Alternatex
  • 1,505
  • 4
  • 24
  • 47