Javid Ahmad
Javid Ahmad

Reputation: 38

Check if the string can be casted to a given type

I have to create an API where I need to provide a proper message to the user if he is not supplying the mandatory parameters in the GET request, I also need to make sure that the user has supplied the proper values in the parameters, the values can be integers, strings, dates OR the enums.

So I created a class SearchParameters which lists the information on the parameters for the request.

private static class SearchParameters
{
    public static List<ParamInfo> ParamList = new List<ParamInfo>
    {
        new ParamInfo {Name ="location", IsMandatory = true , ExpecteDataType = typeof(ulong) } ,
        new ParamInfo {Name ="service", IsMandatory = true  , ExpecteDataType = typeof(ServiceType)} ,
        new ParamInfo {Name ="start", IsMandatory = true  , ExpecteDataType = typeof(DateTimeOffset)} ,
        new ParamInfo {Name ="appointmentType", IsMandatory = true  , ExpecteDataType = typeof(AppointmentType)} ,
        new ParamInfo {Name ="status", IsOptional = true  , ExpecteDataType = typeof(string)} ,
        new ParamInfo {Name ="end", IsOptional = true  , ExpecteDataType = typeof(DateTimeOffset)} ,
        new ParamInfo {Name ="clinicianGender", IsOptional = true , ExpecteDataType = typeof(AdministrativeGender)}   ,
        new ParamInfo {Name ="_sort", IsForSorting = true , ExpecteDataType = typeof(string)},
        new ParamInfo {Name ="_count", IsForPaging = true , ExpecteDataType = typeof(uint)}
    };
}

where ParamInfo are the instances of class

public class ParamInfo
{
    public string Name { get; set; }
    public bool IsMandatory { get; set; }
    public bool IsRequired { get; set; }
    public bool IsOptional { get; set; }
    public bool IsForSorting { get; set; }
    public bool IsForPaging { get; set; }
    public Type ExpecteDataType { get; set; }
}

When user requests I have the parameters available in the list of Tuple where both Item1 & Item2 are strings, Item1 is the name of query parameter & Item2 is the value supplied by the user.

How can I make sure that the value of parameter(i.e Item2) is of a proper datatype?

I tried something like this:

// Data tye verification
foreach (ParamInfo info in SlotSearchParameters.ParamList)
{
    Tuple<string, string> param = searchparams.Parameters.Where(x => x.Item1.ToLower() == info.Name).FirstOrDefault();
    if (param != null)
    {
        Type expectedType = info.ExpecteDataType;
        // how can we check if the value of type of x.Item1 is as expected 
        // Can't procede
    }
}

But since x.Item1 is always a string representation of the value supplied which can be Date, Int or string etc, I don't know what to do?

Upvotes: 1

Views: 95

Answers (3)

BenKoshy
BenKoshy

Reputation: 35595

How can I make sure that the value of parameter(i.e Item2) is of a proper datatype?

  1. You can make it very difficult for the user to actually input an incorrect data type. For example, if they are typing things in a form and you are asking for a date – if they type in something non-sensical in that field, make it so that they cannot submit the form.
  2. You can throw an exception if they type in something non-sensical or
  3. You can prevent the creation of the ParamInfo object if the input value is not genuine. See below for some examples.
  4. A side note: where are you actually storing the data in the ParamInfo class? If you are in fact storing the variable as an int, date, or enum etc then having this variable there would obviate the need for an ExpectedDataType variable. I hope this is making sense. In other words, do you want to store item1.value as a string inside the ParamInfo class or not? Or do you want to store is as an actual number, date or enum?
  5. Is it possible for the users to accidentally type in the wrong ParamInfo.Name value?

Anyways, here are some ideas that will hopefully help you:

internal class Program
{
    private static void Main(string[] args)
    {
        List<Tuple<string, string>> userInputValues = new List<Tuple<string, string>>(); // obviously implement the correct user values here

        // This is the money below.
        // you'll have only valid ParamInfo objects here:

        List<ParamInfo> paramFactory = new ParamInfoFactory(userInputValues).ValidParameters;         
    }

    public class ParamInfo
    {
        public string Name { get; set; }
        public bool IsMandatory { get; set; }
        public bool IsRequired { get; set; }
        public bool IsOptional { get; set; }
        public bool IsForSorting { get; set; }
        public bool IsForPaging { get; set; }

        public Type ExpecteDataType { get; set; } // <--- you really don't need this.

        // where are you storing the item1.value?
        // are you storing it as a string, or as the proper type that it represents?
    }
    public class ParamInfoFactory
    {
        public List<ParamInfo> ValidParameters { get; set; }

        public ParamInfoFactory(List<Tuple<string, string>> userSuppliedValues)
        {
            ValidParameters = new List<ParamInfo>();
            foreach (Tuple<string, string> userValue in userSuppliedValues)
            {
                if (UserInputValuesAreValid(userValue))
                {
                    // all the values are valid. you can now create and add the parameters to your list.
                    // remember to instantiate it as you wish with the right values etc in there.
                    ValidParameters.Add(new ParamInfo());
                }
            }
        }
        private bool UserInputValuesAreValid(Tuple<string, string> userValue)
        {
            return IsNameValid(userValue.Item1) && IsDataValid(userValue.Item2);
        }

        private bool IsDataValid(string data)
        {
            return IsValidDate(data) || IsValidNumber(data); // you can also implement the IsValidEnum or any other method you want
        }

        private static bool IsValidDate(string data)
        {
            DateTime dateValue;
            bool isDate = DateTime.TryParse(data, out dateValue);
            return isDate;
        }

        //private static bool IsEnum(string data)
        //{
        //    Colors colorValue;
        //    bool isEnum = Enum.TryParse(data, out colorValue);
        //    return isEnum;
        //}

        private static bool IsValidNumber(string data)
        {
            int number;

            bool isNumber = Int32.TryParse(data, out number);
            return isNumber;
        }

        private bool IsNameValid(string userInputName)
        {
            return SearchParameters.ParamList.Any(paramInfo => paramInfo.Name == userInputName.ToLower());
        }

        private static class SearchParameters
        {
            public static List<ParamInfo> ParamList = new List<ParamInfo>
            {
                new ParamInfo {Name ="location", IsMandatory = true , ExpecteDataType = typeof(ulong) } ,
                new ParamInfo {Name ="service", IsMandatory = true  , ExpecteDataType = typeof(ServiceType)} ,
                new ParamInfo {Name ="start", IsMandatory = true  , ExpecteDataType = typeof(DateTimeOffset)} ,
                new ParamInfo {Name ="appointmentType", IsMandatory = true  , ExpecteDataType = typeof(AppointmentType)} ,
                new ParamInfo {Name ="status", IsOptional = true  , ExpecteDataType = typeof(string)} ,
                new ParamInfo {Name ="end", IsOptional = true  , ExpecteDataType = typeof(DateTimeOffset)} ,
                new ParamInfo {Name ="clinicianGender", IsOptional = true , ExpecteDataType = typeof(AdministrativeGender)}   ,
                new ParamInfo {Name ="_sort", IsForSorting = true , ExpecteDataType = typeof(string)},
                new ParamInfo {Name ="_count", IsForPaging = true , ExpecteDataType = typeof(uint)}
            };
        }
    }
}

Upvotes: 0

InBetween
InBetween

Reputation: 32750

You can add a validator to your ParamInfo class:

public class ParamInfo
{
    public string Name { get; set; }
    public bool IsMandatory { get; set; }
    public bool IsRequired { get; set; }
    public bool IsOptional { get; set; }
    public bool IsForSorting { get; set; }
    public bool IsForPaging { get; set; }
    public Type ExpecteDataType { get; set; }
    public Predicate<string> Validator { get; set; }
}

And now:

public static List<ParamInfo> ParamList = new List<ParamInfo>
{
    new ParamInfo { Name ="location",
                   IsMandatory = true, 
                   ExpecteDataType = typeof(ulong),
                   Validator = s => s != null && ulong.TryParse(s, out var _); }

And you can use it like this:

foreach (ParamInfo info in SlotSearchParameters.ParamList)
{
    Tuple<string, string> param = searchparams.Parameters.Where(x => x.Item1.ToLower() == info.Name).FirstOrDefault();

    if (param != null &&
        Validator(x.Item1) //
    {
        //whatever
    }
}

}

Upvotes: 2

Alexander Bell
Alexander Bell

Reputation: 7918

For the purpose stated in your question, you should use either Parse() (re: https://msdn.microsoft.com/en-us/library/system.int32.parse(v=vs.110).aspx) or TryParse() (re: https://msdn.microsoft.com/en-us/library/zf50za27(v=vs.110).aspx) methods, e.g. int32.Parse ([your_string]);

Hope this will help.

Upvotes: 1

Related Questions