6

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
  • 26,817
  • 58
  • 206
  • 383
  • 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

1 Answers1

8

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
  • 26,817
  • 58
  • 206
  • 383
  • 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