xin9le.net

Microsoft の製品/技術が大好きな Microsoft MVP な管理人の技術ブログです。

キャリッジリターン (CR) を無視する ModelBinder を適用する

タイトルの通りです、それ以上の情報がないのですが...!下記のドキュメントを参考に、そういうものを作りました。

動機

iOS の Safari から改行を含む <textarea> のデータを POST すると勝手に CR が付与されるという問題がありました。Form の Submit イベントを JavaScript でハンドリングして CR を除外してから送信しても勝手に付与される不思議!なんでだ!

もはやクライアント側では回避不能なのではないかということになり、サーバー側で CR を削除するしかないということで対応することにしました。

実装

ASP.NET Core MVC には (ASP.NET MVC にも) ModelBinder という POST されたデータをプロパティや変数に値を詰める処理をカスタマイズする拡張ポイントがあるので、それを使っています。案外簡単ですね!

public class IgnoreCarriageReturnStringBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
            throw new ArgumentNullException(nameof(bindingContext));

        //--- 値を取り出す
        var modelName = bindingContext.ModelName;
        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
        if (valueProviderResult == ValueProviderResult.None)
            return Task.CompletedTask;

        //--- ModelState を更新
        bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);

        //--- CR を削除
        var value = valueProviderResult.FirstValue;
        if (value != null)
            value = value.Replace("\r", string.Empty);

        //--- バインディング成功
        bindingContext.Result = ModelBindingResult.Success(value);
        return Task.CompletedTask;
    }
}

あとは適用したいプロパティにピンポイントで属性を貼れば OK です。サービス全体で適用する場合は Startup.cs で処理しても良いですが、良し悪しあるので適宜判断してください。

public class HogeModel
{
    //--- textarea とマップされるプロパティ
    [ModelBinder(typeof(IgnoreCarriageReturnStringBinder))]
    public string Text { get; set; }
}