3

I have a lot of Guid properties in my classes and I want to make sure that a Guid.Empty will make ModelState invalid. What's the best way of handling this?

Say, I have the following class that a user submits to my API action method:

{
   public Guid Id { get; set: }

   [Required]
   public string name { get; set: }
}

By using [Required], I make sure that the user must always give me something in the name field but if the user doesn't provide an Id, it becomes Guid.Empty and ModelState is still valid.

I want to make sure that I will always get a Guid value in the Id property and NOT a Guid.Empty.

Sam
  • 22,737
  • 46
  • 168
  • 303
  • Put `[Required]` on `Id` as well. – Igor Jan 23 '17 at 19:30
  • That doesn't work. Even if the user doesn't provide a value, it becomes Guid.Empty and ModelState accepts it as valid. – Sam Jan 23 '17 at 19:31
  • 1
    @Igor - It would have to be `Guid?` for that to work wouldn't it? – hatchet - done with SOverflow Jan 23 '17 at 19:32
  • Or create a custom Validator and apply that. The framework is open, you can create any type of validator that you wish. – Igor Jan 23 '17 at 19:32
  • @hatchet - good point. So code becomes `[Required] public Guid? Id {get;set;}` – Igor Jan 23 '17 at 19:32
  • Maybe I wasn't clear in my original post. I require a Guid value. So no value or Guid.Empty should NOT be acceptable. Guid? doesn't accomplish any of these requriements. I think the only solution here is to implement a custom validation attribute. – Sam Jan 23 '17 at 19:34
  • @Igor: That just ensure it's not null at that point. Technically, it could still be set to `Guid.Empty` successfully, though at least that would no longer happen by default. – Chris Pratt Jan 23 '17 at 19:34
  • `[Required] public Guid? Id {get;set;}` <= if the client does not supply a value this becomes `null` and the ModelState is then invalid. – Igor Jan 23 '17 at 19:34
  • @ChrisPratt - true but the client would have to explicitly create an empty guid and pass it along. I guess the question then becomes who has source control over the client. – Igor Jan 23 '17 at 19:35
  • But if the user "intentionally" sends a Guid.Empty, it is valid so it's not a robust solution. – Sam Jan 23 '17 at 19:36
  • @Sam - I lean with Igor's solution above. But you could also do a custom attribute like this, but make it be InvalidValuesAttribute http://stackoverflow.com/questions/17243665/web-api-custom-validation-to-check-string-against-list-of-approved-values – hatchet - done with SOverflow Jan 23 '17 at 19:36
  • If you own the client (ie. you are writing code for both) its a non issue. If the client is outside of your source control (3rd party, a customer you are working for, etc) then you need something more robust. In that case a custom attribute would do the trick. – Igor Jan 23 '17 at 19:36
  • This is an API call so an intruder who wants to exploit the system can send a Guid.Empty value to see what happens. – Sam Jan 23 '17 at 19:38
  • I do think the solution is to build custom validation here: https://msdn.microsoft.com/en-us/library/cc668224.aspx – Sam Jan 23 '17 at 19:38
  • 2
    Agreed. It's basically just `RequiredAttribute` with an additional condition. You can simply create something like `RequiredGuidAttribute`, inherit from `Required` and override `IsValid`. – Chris Pratt Jan 23 '17 at 19:41

2 Answers2

5

So, here are the super easy steps:

First, I created a new class named CustomAttributeNoGuidEmpty.cs and placed it under my "Utils/Validation" folder. I see that some people place it under App_Code, etc. which is fine also.

The class looks like this:

using System;
using System.ComponentModel.DataAnnotations;

namespace MyApp.Utils.Validation
{
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    sealed public class CustomAttributeNoGuidEmpty : ValidationAttribute
    {
        public override bool IsValid(Object value)
        {
            bool result = true;

            if ((Guid)value == Guid.Empty)
                result = false;

            return result;
        }
    }
}

I then simply apply it to properties in my classes. Obviously, I need the using to reference it:

using MyApp.Utils.Validation;

{
   [CustomAttributeNoGuidEmpty]
   public Guid Id { get; set; }

   [Required]
   public string Name { get; set; }
}

Now, unless the value of Id is a valid Guid ModelState becomes invalid. This includes scenarios where Id field's value is Guid.Empty.

Sam
  • 22,737
  • 46
  • 168
  • 303
  • Do you mean instead of using INT or something? – Sam Jan 23 '17 at 20:07
  • 1
    Well it seems you rely on a user to provide a valid guid. Tha can't be good. Using id is a possibility and not using any keys in the views (but saving them and getting them from session) is also woth considering. – Ivaylo Stoev Jan 23 '17 at 20:10
  • It's not the user that I'm actually relying on. I have a React frontend app that communicates with my API. Additionally, I'm working on mobile apps. So I cannot rely on storing stuff in session. The reason why I'm going the extra mile to make sure I get "valid" Guid values is to make sure that in case potential intruders tamper with "requests", I still have robust validation in place. – Sam Jan 23 '17 at 20:13
0

As a possible solution you can use nullable Guid, so the default value will be null and you will be able to check it with Required.

The solution will be something like this:

{
  [Required]
  public Guid? Id { get; set: }

  [Required]
  public string name { get; set: }
}
flerka
  • 345
  • 2
  • 4
  • 2
    How does this help preventing Guid.Empty? The key requirement here is to make sure we do NOT allow Guid.Empty. – Sam Jan 23 '17 at 22:27