ルートが与えられた場合:
{FeedName}/{ItemPermalink}
例: /Blog/Hello-World
アイテムが存在しない場合は、404 を返したいのですが、ASP.NET MVC でこれを行う正しい方法は何ですか?
ルートが与えられた場合:
{FeedName}/{ItemPermalink}
例: /Blog/Hello-World
アイテムが存在しない場合は、404 を返したいのですが、ASP.NET MVC でこれを行う正しい方法は何ですか?
ヒップからの撮影 (カウボーイ コーディング ;-))、次のようなものをお勧めします。
コントローラ:
public class HomeController : Controller
{
public ActionResult Index()
{
return new HttpNotFoundResult("This doesn't exist");
}
}
HttpNotFoundResult:
using System;
using System.Net;
using System.Web;
using System.Web.Mvc;
namespace YourNamespaceHere
{
/// <summary>An implementation of <see cref="ActionResult" /> that throws an <see cref="HttpException" />.</summary>
public class HttpNotFoundResult : ActionResult
{
/// <summary>Initializes a new instance of <see cref="HttpNotFoundResult" /> with the specified <paramref name="message"/>.</summary>
/// <param name="message"></param>
public HttpNotFoundResult(String message)
{
this.Message = message;
}
/// <summary>Initializes a new instance of <see cref="HttpNotFoundResult" /> with an empty message.</summary>
public HttpNotFoundResult()
: this(String.Empty) { }
/// <summary>Gets or sets the message that will be passed to the thrown <see cref="HttpException" />.</summary>
public String Message { get; set; }
/// <summary>Overrides the base <see cref="ActionResult.ExecuteResult" /> functionality to throw an <see cref="HttpException" />.</summary>
public override void ExecuteResult(ControllerContext context)
{
throw new HttpException((Int32)HttpStatusCode.NotFound, this.Message);
}
}
}
// By Erik van Brakel, with edits from Daniel Schaffer :)
このアプローチを使用すると、フレームワークの標準に準拠できます。そこにはすでに HttpUnauthorizedResult があるため、後でコードを保守する別の開発者 (あなたがどこに住んでいるかを知っているサイコ) の目にフレームワークを拡張するだけです。
リフレクターを使用してアセンブリを調べて、HttpUnauthorizedResult がどのように達成されるかを確認できます。
リフレクターを使用して、今 HttpUnauthorizedResult を確認しました。0x191 (401) への応答に StatusCode を設定しているようです。これは 401 では機能しますが、新しい値として 404 を使用すると、Firefox で空白のページが表示されるようです。ただし、Internet Explorer ではデフォルトの 404 が表示されます (ASP.NET バージョンではありません)。webdeveloper ツールバーを使用して、FF のヘッダーを調べたところ、404 Not Found 応答が表示されました。単純に FF で設定を誤った可能性があります。
そうは言っても、ジェフのアプローチはKISSの良い例だと思います。このサンプルの冗長性が本当に必要ない場合は、彼の方法も問題なく機能します。
私たちはそうします。このコードはBaseController
/// <summary>
/// returns our standard page not found view
/// </summary>
protected ViewResult PageNotFound()
{
Response.StatusCode = 404;
return View("PageNotFound");
}
そう呼ばれる
public ActionResult ShowUserDetails(int? id)
{
// make sure we have a valid ID
if (!id.HasValue) return PageNotFound();
throw new HttpException(404, "Are you sure you're in the right place?");
HttpNotFoundResult は、私が使用しているものへの優れた最初のステップです。HttpNotFoundResult を返すのは良いことです。次に問題は、次は何ですか?
404 エラー ページを表示する HandleNotFoundAttribute というアクション フィルターを作成しました。ビューを返すため、コントローラーごとに特別な 404 ビューを作成するか、デフォルトの共有 404 ビューを使用できます。これは、コントローラーに指定されたアクションが存在しない場合でも呼び出されます。これは、フレームワークがステータス コード 404 で HttpException をスローするためです。
public class HandleNotFoundAttribute : ActionFilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
var httpException = filterContext.Exception.GetBaseException() as HttpException;
if (httpException != null && httpException.GetHttpCode() == (int)HttpStatusCode.NotFound)
{
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; // Prevents IIS from intercepting the error and displaying its own content.
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.StatusCode = (int) HttpStatusCode.NotFound;
filterContext.Result = new ViewResult
{
ViewName = "404",
ViewData = filterContext.Controller.ViewData,
TempData = filterContext.Controller.TempData
};
}
}
}
MVC3 の時点では、単に使用できることに注意してくださいHttpStatusCodeResult
。
ActionFilterの使用は、エラーをスローするたびに属性にフィルターを設定する必要があるため、保守が困難です。設定し忘れたら?OnException
1 つの方法は、ベース コントローラーから派生させることです。BaseController
派生元を定義する必要がありController
、すべてのコントローラーは から派生する必要がありますBaseController
。ベース コントローラを使用することをお勧めします。
Exception
応答ステータス コードが 500 の場合は、Not Found の場合は 404、Unauthorized の場合は 401 に変更する必要があることに注意してください。上で述べたように、OnException
オーバーライドをBaseController
使用してフィルター属性を使用しないようにします。
また、新しい MVC 3 では、空のビューがブラウザーに返されるため、面倒です。ASP.Net MVC 3 でHttpNotFound () のビューを返す方法は?
より便利にするために、ここに貼り付けます。
少し勉強した後。ここでのMVC 3の回避策は、すべてHttpNotFoundResult
の , HttpUnauthorizedResult
,HttpStatusCodeResult
クラスを派生させ、新しい(オーバーライドする) HttpNotFound
() メソッドを に実装することBaseController
です。
すべての派生コントローラーを「制御」できるように、基本コントローラーを使用することをお勧めします。
HttpStatusCodeResult
派生するのではなく、ビューまたはプロパティを指定して必要なものをレンダリングするための新しいクラスActionResult
をViewResult
作成View
しますViewName
。オリジナルに従ってandHttpStatusCodeResult
を設定しますが、再び から派生するため、適切なビューをレンダリングします。簡単ですよね?これが MVC コアに実装されることを願っています。HttpContext.Response.StatusCode
HttpContext.Response.StatusDescription
base.ExecuteResult(context)
ViewResult
私のBaseController
怒鳴るを参照してください:
using System.Web;
using System.Web.Mvc;
namespace YourNamespace.Controllers
{
public class BaseController : Controller
{
public BaseController()
{
ViewBag.MetaDescription = Settings.metaDescription;
ViewBag.MetaKeywords = Settings.metaKeywords;
}
protected new HttpNotFoundResult HttpNotFound(string statusDescription = null)
{
return new HttpNotFoundResult(statusDescription);
}
protected HttpUnauthorizedResult HttpUnauthorized(string statusDescription = null)
{
return new HttpUnauthorizedResult(statusDescription);
}
protected class HttpNotFoundResult : HttpStatusCodeResult
{
public HttpNotFoundResult() : this(null) { }
public HttpNotFoundResult(string statusDescription) : base(404, statusDescription) { }
}
protected class HttpUnauthorizedResult : HttpStatusCodeResult
{
public HttpUnauthorizedResult(string statusDescription) : base(401, statusDescription) { }
}
protected class HttpStatusCodeResult : ViewResult
{
public int StatusCode { get; private set; }
public string StatusDescription { get; private set; }
public HttpStatusCodeResult(int statusCode) : this(statusCode, null) { }
public HttpStatusCodeResult(int statusCode, string statusDescription)
{
this.StatusCode = statusCode;
this.StatusDescription = statusDescription;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
context.HttpContext.Response.StatusCode = this.StatusCode;
if (this.StatusDescription != null)
{
context.HttpContext.Response.StatusDescription = this.StatusDescription;
}
// 1. Uncomment this to use the existing Error.ascx / Error.cshtml to view as an error or
// 2. Uncomment this and change to any custom view and set the name here or simply
// 3. (Recommended) Let it commented and the ViewName will be the current controller view action and on your view (or layout view even better) show the @ViewBag.Message to produce an inline message that tell the Not Found or Unauthorized
//this.ViewName = "Error";
this.ViewBag.Message = context.HttpContext.Response.StatusDescription;
base.ExecuteResult(context);
}
}
}
}
次のようにアクションで使用するには:
public ActionResult Index()
{
// Some processing
if (...)
return HttpNotFound();
// Other processing
}
そして _Layout.cshtml (マスターページと同様)
<div class="content">
@if (ViewBag.Message != null)
{
<div class="inlineMsg"><p>@ViewBag.Message</p></div>
}
@RenderBody()
</div>
さらに、コードでコメントしたように、カスタム ビューを使用しError.shtml
たり、新しく作成したりできますNotFound.cshtml
。また、ステータスの説明やその他の説明用にビュー モデルを定義することもできます。