22

部分ビューを返す POST コントローラー アクションがあります。すべてが本当に簡単に思えます。しかし。を使用してロードし$.ajax()、タイプを として設定しhtmlます。しかし、モデルの検証が失敗した場合、モデル状態エラーでエラーをスローする必要があると思いました。しかし、私の返信は常に 500 Server error を返します。

結果が何であれ、Json を返さずにモデル状態エラーを報告するにはどうすればよいですか。HTML要素に直接追加できる部分ビューを返したいと思います。

編集

また、エラーの部分ビューを返さないようにしたいと思います。これは、クライアントにとって成功のように見えます。クライアントに結果を解析させて、それが実際に成功したかどうかを確認すると、エラーが発生しやすくなります。設計者は部分的なビューの出力を変更する可能性があり、これだけでも機能が損なわれます。したがって、例外をスローしたいのですが、正しいエラーメッセージが ajax クライアントに返されます。

4

2 に答える 2

17

解決

意図したとおりに自動的に機能する 2 つの別個の部分を作成する必要がありました。

したがって、コントローラー アクション プロセスが成功した場合は部分的なビューを返す必要があり、問題が発生した場合は失敗の詳細を含むエラーをスローする必要があります。これにより、クライアント側で常に成功を処理するのではなく、成功と失敗を区別できるようになります。

これを実現するために使用される主要な部分が 2 つあります。

  • 何か問題が発生したときにスローされるカスタム例外クラス。これにより、何らかの理由でいつでも発生する可能性がある一般的な例外と、処理に関連するエラー (特に無効なモデル状態) を区別できます。
  • カスタム例外をキャッチし、その例外に基づいて結果を準備する例外アクション フィルター。コードからわかるように、カスタム例外はモデル状態エラーに関する情報を保持するため、このフィルターはカスタム HTTP ステータス コードといくつかのテキスト情報を返すことができます。

それでは詳細へ…

外部リンク: このすべての情報 (詳細な説明とすべてのコード) は、私のブログでも入手できます。最新のコード更新は常に公開されます

カスタム例外クラス

このクラスは2つのことを提供します

  1. モデル状態エラーと通常の例外を簡単に区別できるようにする
  2. 後で使用できるいくつかの基本的な機能を提供する

このクラスは、後でカスタム エラー フィルターで使用されます。

public class ModelStateException : Exception
{
    public Dictionary<string, string> Errors { get; private set; }

    public ModelStateDictionary ModelState { get; private set; }

    public override string Message
    {
        get
        {
            if (this.Errors.Count > 0)
            {
                return this.Errors.First().Value;
            }
            return null;
        }
    }

    private ModelStateException()
    {
        this.Errors = new Dictionary<string, string>();
    }

    public ModelStateException(ModelStateDictionary modelState) : this()
    {
        this.ModelState = modelState;
        if (!modelState.IsValid)
        {
            foreach (KeyValuePair<string, ModelState> state in modelState)
            {
                if (state.Value.Errors.Count > 0)
                {
                    this.Errors.Add(state.Key, state.Value.Errors[0].ErrorMessage);
                }
            }
        }
    }
}

エラーフィルター属性

この属性は、モデル状態エラーがある場合に、HTTP エラー コードに関してクライアントにエラーを返すのに役立ちます。

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class HandleModelStateExceptionAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        if (filterContext.Exception != null && typeof(ModelStateException).IsInstanceOfType(filterContext.Exception) && !filterContext.ExceptionHandled)
        {
            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.ContentEncoding = Encoding.UTF8;
            filterContext.HttpContext.Response.HeaderEncoding = Encoding.UTF8;
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
            filterContext.HttpContext.Response.StatusCode = 400;
            filterContext.HttpContext.Response.StatusDescription = (filterContext.Exception as ModelStateException).Message;
        }
    }
}

その後、コントローラー アクションを自分の属性と出来上がりで装飾するだけです。クライアントでコード 400 のエラーが発生し、フィルターに設定した正しい情報が表示されました。次に、この情報がユーザーに表示されます (モデル状態エラーに関連する場合、フォームを有効にするためにユーザーが修正する必要があるフォーム フィールドの情報が表示されます)。

[HandleModelStateException]
public ActionResult AddComment(MyModel data)
{
    // check if state is valid
    if (!this.ModelState.IsValid)
    {
        throw new ModelStateException(this.ModelState);
    }
    // get data from store
    return PartialView("Comment", /* store data */ );
}

これにより、コードはモデル状態エラーで再利用可能になり、それらは必要に応じてクライアントに送信されます。

1 つの問題 (現在は解決済み)

ただし、このコードに関連する問題が 1 つあります。エラー アクション フィルタが設定StatusDescriptionされ、その文字列に Č などの特殊文字が含まれていると、クライアントで問題が発生します。IE を使用しない限り (バージョン 8 を使用しています)。FFとCH表示ゴミ。そのため、エンコーディングを設定しましたが、機能しません。誰かがこの特殊性に対する回避策を持っている場合は、喜んで耳を傾けます。
コンテンツ自体にエラーメッセージが返された場合、すべて問題ありません。エンコーディングは正しく、必要なものは何でも表示できます。

于 2010-02-15T15:57:57.307 に答える
3

これを試して。

public ActionResult DoAjaxAction(Entity entity)
{
   if(ModelState.IsValid)
   {
     return PartialView("Valid_View", entity);
   }
   else
   {
     return PartialView("Invalid_View", entity);
   } 

}
于 2010-02-14T15:54:59.017 に答える