新人SEくんの日常

新人エンジニアが大好きなesports、音楽、プログラミングなどなど、いろんなこと書いてきます

【C#】入力チェックを実装する

前提

  • Vsual Studio 2017がインストールされていること

本記事でやること

  1. ModelState.IsValidでModelを検証する
  2. エラーメッセージを作成する

ModelState.IsValidでModelを検証する

Modelを作成する

まず下記のようなModel[UserInfo]を作成します。
C#

public class UserInfo
{
    public string id { get; set; }

    public string password { get; set; }

    public string name { get; set; }

    public string mailAddress { get; set; }

    public IList<Skill> skillList { get; set; }

}
public class Skill
{

    public string skillName { get; set; }

    public string experience { get; set; }

}

属性を付ける

次に各項目に属性をつけます。
この項目は「半角英数字のみ許可する」とか「必須項目とする」とか。
下記を参考に属性を付けてみました。
qiita.com

C#

public class UserInfo
{

    [DisplayName("ID")]
    [Required(ErrorMessage = "IDは必須です")]
    public string Id { get; set; }

    [DisplayName("パスワード")]
    [Required(ErrorMessage = "パスワードは必須です")]
    public string Password { get; set; }

    [DisplayName("名前")]
    [Required(ErrorMessage = "名前は必須です")]
    public string Name { get; set; }

    [DisplayName("メールアドレス")]
    [EmailAddress(ErrorMessage = "メールアドレスの形式で入力してください")]
    [Required(ErrorMessage = "メールアドレスは必須です")]
    public string MailAddress { get; set; }

    [DisplayName("スキルリスト")]
    public IList<Skill> SkillList { get; set; }

}

public class Skill
{

    [DisplayName("スキル名")]
    [Required(ErrorMessage = "スキル名は必須です")]
    public string SkillName { get; set; }

    [DisplayName("経験年数")]
    [Required(ErrorMessage = "経験年数は必須です")]
    [MaxLength(3)]
    [MinLength(1)]
    [RegularExpression(@"[0-9]+", ErrorMessage = "半角数字のみ入力できます")]
    public string Experience { get; set; }

}

Modelを検証する

Modelの検証には、ModelState.IsValidメソッドを使用します。
こんな感じに。

C#

public IHttpActionResult Post([FromBody]UserInfo reqParam)
{

    string RESULT_OK = "0";
    string RESULT_NG = "1";

    ResultInfo result = new ResultInfo();
    result.result = RESULT_OK;

    // リクエストパラメータを検証
    if (!ModelState.IsValid)
    {
        result.result = RESULT_NG;
        return Json(result);
    }

    return Json(result);
}


リクエストパラメータの「Id」を空にしてリクエストを送ってみます↓

動作確認
IDは必須なので、RESULT_NG("result" : "1")で返却されました。

このままでもエラーなのは分かりますが、
どんなエラー内容なのかがクライアントに伝わりません。
クライアントがどんなエラーなのか分かりやすくするために、
適当なエラーメッセージを返してあげます。

エラーメッセージを作成する

エラー情報用Modelを作成する

以下のようにエラー情報用のModelと処理結果用のModelを作成しました。

C#

public class ResultInfo
{
    public string result { get; set; }
    public IList<ErrorInfo> errorInfoList { get; set; } = new List<ErrorInfo>();
}
public class ErrorInfo
{
    public string errorId { get; set; }
    public string errorMessage { get; set; }
}

エラーメッセージを作成する

リクエストパラメータ内のエラー項目の値を取得し、
クライアントへ返却するエラーメッセージを作成します。

※Controllerにこういった処理を書くのは適切ではないと思いますが、
検証のため一旦ここに書いてあります。
「入力値チェックってここに書くといいと思うよ!」っていうのがあれば、
コメントいただけると嬉しいです!

C#

public IHttpActionResult Post([FromBody]UserInfo reqParam)
{
    // 処理結果(初期値としてOKを設定)
    ResultInfo result = new ResultInfo();
    result.result = RESULT_OK;

    // 入力値エラーがあった場合
    if (!ModelState.IsValid)
    {
        foreach (string key in ModelState.Keys)
        {
            if (ModelState[key].Errors.Count > 0)
            {
                string[] keys = key.Split('.');
                object value = reqParam;
                string inputKey = "";
                string inputValue = "";

                for (int i = 1; i < keys.Length; ++i)
                {
                    // エラーがあった項目の値を取得する
                    value = getValue(value, keys[i]);
                    inputValue = (value == null ? "" : value.ToString());
                    inputKey = keys[i];
                }

                foreach (ModelError modelErr in ModelState[key].Errors)
                {
                    // エラーメッセージを作成
                    string message = modelErr.ErrorMessage;
                    ErrorInfo errorInfo = new ErrorInfo();
                    errorInfo.errorId = "E001";
                    errorInfo.errorMessage = modelErr.ErrorMessage + " 入力値:「" + inputValue + "」";
                    result.errorInfoList.Add(errorInfo);
                }
            }
        }
        return Json(result);
    }

    return Json(result);
}

↑のControllerの中で使うメソッド「getValue()」
入力値取得用のメソッドを作成しました。
正規表現でList型か判定し、キー項目に対応する値を取得します。
C#

/// <summary>
/// オブジェクト内から指定されたKEYに対応したVALUEを取得する。
/// </summary>
/// <param name="obj">オブジェクト</param>
/// <param name="key">キー</param>
static public object getValue(object obj, string key)
{
    // オブジェクトの型を取得
    Type type = obj.GetType();

    // key項目がListか判定
    Match matche = Regex.Match(key, "^(.*?)\\[(\\d)\\]");
    if (matche.Success)
    {
        // Listの場合
        PropertyInfo property = type.GetProperty(matche.Groups[1].Value);
        IList list = property.GetValue(obj, null) as IList;
        return list[int.Parse(matche.Groups[2].Value)];
    }
    else
    {
        // Listでない場合
        PropertyInfo property = type.GetProperty(key);
        return property.GetValue(obj, null);
    }
}

動作確認

以下の画像の通りリクエストパラメータを設定し、
リクエストを投げます。
動作確認_エラーメッセージ出力

想定したエラーメッセージが出力されました。