কোনও এএসপি.নেট এমভিসি ক্রিয়াকলাপ থেকে এইচটিটিপি 404 প্রতিক্রিয়া প্রেরণের উপযুক্ত উপায় কী?


92

যদি রুটটি দেওয়া হয়:

{ফিডনাম} / tem আইটেমপার্মালিংক}

প্রাক্তন: / ব্লগ / হ্যালো-ওয়ার্ল্ড

যদি আইটেমটি বিদ্যমান না থাকে তবে আমি একটি 404 ফিরিয়ে দিতে চাই A এএসপি.নেট এমভিসিতে এটি করার সঠিক উপায় কী?


বিটিডব্লিউ এই প্রশ্ন জিজ্ঞাসা করার জন্য ধন্যবাদ। এটি আমার স্ট্যান্ডার্ড প্রকল্প সংযোজনে যাচ্ছে: ডি
এরিক ভ্যান ব্র্যাকেল

উত্তর:


69

হিপ থেকে শুটিং (কাউবয় কোডিং ;-)), আমি এই জাতীয় কিছু প্রস্তাব করব:

নিয়ামক:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return new HttpNotFoundResult("This doesn't exist");
    }
}

এইচটিপিএনটফাউন্ডআরসাল্ট:

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 :)

এই পদ্ধতির ব্যবহার করে আপনি কাঠামোর মান মেনে চলেন। সেখানে ইতিমধ্যে একটি এইচটিটিপিউনাওরাইজড রিসাল্ট রয়েছে, সুতরাং এটি পরে আপনার কোড বজায় রেখে অন্য বিকাশকারীর চোখে কাঠামোটি প্রসারিত করবে (আপনি জানেন, আপনি কোথায় থাকেন সাইকো জানেন)।

আপনি কীভাবে এইচটিটিপিউনাথরাইজড রিসাল্ট অর্জন করা হয় তা দেখতে সমাবেশের দিকে নজর দেওয়ার জন্য আপনি প্রতিবিম্বকে ব্যবহার করতে পারেন, কারণ আমি জানি না যে এই পদ্ধতির কোনও কিছুই মিস হয় না (এটি প্রায় খুব সহজ বলে মনে হয়)।


আমি এই মুহুর্তে এইচটিটিপিউনাথরাইজড রেজাল্টটি একবার দেখার জন্য রিফ্লেক্টর ব্যবহার করেছি। তারা 0x191 (401) এর প্রতিক্রিয়ায় স্থিতি কোডটি সেট করছে বলে মনে হচ্ছে। যদিও এটি 401 এর জন্য কাজ করে, 404 কে নতুন মান হিসাবে ব্যবহার করে আমি মনে করি ফায়ারফক্সে কেবল একটি ফাঁকা পৃষ্ঠা পাচ্ছি। ইন্টারনেট এক্সপ্লোরার একটি ডিফল্ট 404 দেখায় যদিও (ASP.NET সংস্করণ নয়)। ওয়েব-ডেভেলপার সরঞ্জামদণ্ডটি ব্যবহার করে আমি এফএফ-এ শিরোনামগুলি পরিদর্শন করেছি, যা একটি 404 পাওয়া যায়নি প্রতিক্রিয়া দেখায়। কেবল এফএফ-তে আমি ভুল কনফিগার করা এমন কিছু হতে পারে।


এটি বলা হচ্ছে, আমি মনে করি জেফের দৃষ্টিভঙ্গি KISS এর একটি সূক্ষ্ম উদাহরণ। আপনার যদি এই নমুনায় সত্যই ভারবোসিটির প্রয়োজন না হয় তবে তার পদ্ধতিটিও ঠিকঠাকভাবে কাজ করে।


হ্যাঁ, আমি এনামও লক্ষ্য করেছি। যেমনটি আমি বলেছি, এটি কেবল একটি অদ্ভুত উদাহরণ, এটির উন্নতি করতে নির্দ্বিধায়। এটি সর্বোপরি একটি জ্ঞানবাস হিসাবে বিবেচিত হবে ;-)
এরিক ভ্যান ব্রাকেল

আমি মনে করি আমি কিছুটা ওভারবোর্ডে গিয়েছি ... উপভোগ করুন: ডি
ড্যানিয়েল শ্যাফার

FWIW, জেফের উদাহরণে আপনার কাস্টম 404 পৃষ্ঠা থাকাও দরকার।
ড্যানিয়েল শেফার

4
কেবলমাত্র HTTPContext.Response.StatusCode = 404 সেট করার পরিবর্তে এইচটিপিএক্সেপশন নিক্ষেপ করার একটি সমস্যা হ'ল আপনি যদি অন এক্সসেপশন কন্ট্রোলার হ্যান্ডলারটি ব্যবহার করেন (যেমন আমি করি) তবে এটিও এইচটিটিপিএক্সেজেশনকে ধরবে। সুতরাং আমি মনে করি যে কেবলমাত্র স্ট্যাটাসকোড সেট করা একটি ভাল পদ্ধতির।
ইগোর ব্রেকজ

4
এমভিসি 3 তে এইচটিপিএক্সেপশন বা এইচটিটিপিএনটফাউন্ডআরসাল্ট বিভিন্ন উপায়ে কার্যকর। @Igor Brejc ক্ষেত্রে, শুধু ব্যবহার যদি OnException মধ্যে বিবৃতি পাওয়া যায়নি ত্রুটি ফিল্টার করার জন্য।
কলমেলএএনএন

46

আমরা এটি যেমন করি; এই কোড পাওয়া যায়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();

এই ক্রিয়াটি কি তখন একটি ডিফল্ট রুট পর্যন্ত তারযুক্ত? কীভাবে এটি কার্যকর করা যায় তা দেখতে পাচ্ছি না।
খ্রিস্টান ডালাগার

4
এটি এর মতো চলতে পারে: সুরক্ষিত ওভাররাইড শূন্যতা হ্যান্ডলঅনজ্ঞানঅ্যাকশন (স্ট্রিং অ্যাকশননাম) {পেজনোটফাউন্ড () Exec }
ত্রিস্তান ওয়ার্নার-স্মিথ

আমি এটি সেভাবেই করতাম, তবে দেখতে পেলাম যে ফলাফলকে বিভক্ত করা এবং প্রদর্শিত দর্শন একটি ভাল পদ্ধতির ছিল। নীচে আমার উত্তর দেখুন।
ব্রায়ান ভাললেলুঙ্গা

19
throw new HttpException(404, "Are you sure you're in the right place?");

আমি এটি পছন্দ করি কারণ এটি সেট আপ করা কাস্টম ত্রুটি পৃষ্ঠাগুলি অনুসরণ করে web.config
মাইক কোল

7

এইচটিটিপিএনটফাউন্ডআরেসাল্ট আমি যা ব্যবহার করছি তার একটি দুর্দান্ত প্রথম পদক্ষেপ। এইচটিপিএনটফাউন্ডআরসাল্ট ফিরিয়ে দেওয়া ভাল। তাহলে প্রশ্ন হচ্ছে, এর পরে কী?

আমি হ্যান্ডলনটফাউন্ডএট্রিবিউট নামে একটি অ্যাকশন ফিল্টার তৈরি করেছি যা তারপরে একটি 404 ত্রুটি পৃষ্ঠা দেখায়। যেহেতু এটি একটি দর্শন ফেরায়, তাই আপনি নিয়ামক প্রতি একটি বিশেষ 404 ভিউ তৈরি করতে পারেন বা একটি ডিফল্ট ভাগ করা 404 ভিউ ব্যবহার করা যাক। এমনকি যখন কোনও কন্ট্রোলারের নির্দিষ্ট ক্রিয়া উপস্থিত না থাকে তখনও এটি ডাকা হবে, কারণ ফ্রেমওয়ার্কটি 404 এর স্থিতি কোড সহ একটি এইচটিপিএক্সসেপশন ছুড়ে দেয়।

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
                                        };
        }
    }
}

7

মনে রাখবেন যে এমভিসি 3 হিসাবে আপনি কেবল ব্যবহার করতে পারেন HttpStatusCodeResult


8
বা, আরও সহজ,HttpNotFoundResult
ম্যাট এনরাট

6

ব্যবহার ActionFilter হয় বজায় রাখা কঠিন কারণ যখনই আমরা একটি ত্রুটি ফিল্টার প্রয়োজন নিক্ষেপ অ্যাট্রিবিউট সেট করতে হবে। আমরা যদি সেট করতে ভুলে যাই? এক উপায় OnExceptionবেজ কন্ট্রোলারে ডাইরিভ করা হয়। আপনার BaseControllerকাছ থেকে প্রাপ্ত একটি সংজ্ঞা দেওয়া দরকার Controllerএবং আপনার সমস্ত কন্ট্রোলার অবশ্যই তা থেকে নেওয়া উচিত BaseController। বেস কন্ট্রোলার থাকা ভাল অভ্যাস।

Exceptionপ্রতিক্রিয়া স্থিতি কোডটি 500 ব্যবহার করা হয় তা নোট করুন , সুতরাং আমাদের এটি নট ফাইন্ডের জন্য 404 এবং অননুমোদিতের জন্য 401 এ পরিবর্তন করতে হবে। আমি উপরে যেমন উল্লেখ করেছি ঠিক OnExceptionতেমন BaseControllerফিল্টার বৈশিষ্ট্য ব্যবহার এড়াতে ওভাররাইড ব্যবহার করুন ।

নতুন এমভিসি 3 ব্রাউজারে একটি খালি ভিউ ফিরিয়ে আরও জটিল করে তোলে। কিছু গবেষণার পরে সর্বোত্তম সমাধানটি আমার উত্তরের উপর ভিত্তি করে তৈরি করা হয়েছে এখানে এএসপি.নেট এমভিসি 3 তে এইচটিপিএনটফাউন্ড () এর জন্য কীভাবে দেখা যায়?

আরও দৃ make় বিশ্বাসের জন্য আমি এটি এখানে আটকান:


কিছু অধ্যয়নের পরে। জন্য কার্যসংক্রান্ত MVC 3 এখানে সব আহরণ করা হয় HttpNotFoundResult, HttpUnauthorizedResult, HttpStatusCodeResultক্লাস এবং বাস্তবায়ন নতুন (এটা অগ্রাহ্য করা হবে) HttpNotFound() পদ্ধতি BaseController

বেস কন্ট্রোলারটি ব্যবহার করা ভাল অনুশীলন যাতে আপনার প্রাপ্ত সমস্ত কন্ট্রোলারের উপর আপনার 'নিয়ন্ত্রণ' থাকে।

আমি নতুন HttpStatusCodeResultশ্রেণি তৈরি করেছি , উত্সটি উল্লেখ করে নয়, তবে সম্পত্তি নির্দিষ্ট করে ভিউ বা আপনার পছন্দসই কোনও রেন্ডার করা ActionResultথেকে । আমি সেটটি সেট করতে আসলটি অনুসরণ করি এবং তারপরে উপযুক্ত ভিউ রেন্ডার করব কারণ আবার আমার থেকে প্রাপ্ত । যথেষ্ট সহজ? এমভিসি কোর এ বাস্তবায়িত হবে আশা করি।ViewResultViewViewNameHttpStatusCodeResultHttpContext.Response.StatusCodeHttpContext.Response.StatusDescriptionbase.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
}

এবং _ লেআউট.একএসটিএমএলে (মাস্টার পৃষ্ঠার মতো)

<div class="content">
    @if (ViewBag.Message != null)
    {
        <div class="inlineMsg"><p>@ViewBag.Message</p></div>
    }
    @RenderBody()
</div>

অতিরিক্ত হিসাবে আপনি কোডটিতে মন্তব্য করা মত Error.shtmlনতুন NotFound.cshtmlপছন্দ তৈরি করতে বা পছন্দ করতে পছন্দ করতে পারেন এবং স্থিতির বিবরণ এবং অন্যান্য ব্যাখ্যাগুলির জন্য আপনি একটি ভিউ মডেলটি সংজ্ঞায়িত করতে পারেন।


আপনি সর্বদা এমন একটি বিশ্বব্যাপী ফিল্টার নিবন্ধন করতে পারেন যা একটি বেস নিয়ামককে পরাজিত করে কারণ আপনার বেস নিয়ামকটি ব্যবহার করতে আপনাকে স্মরণ রাখতে হবে!
জন কালভিনার

:) নিশ্চিত না হয় এটি এমভিসি 4 তে এখনও একটি সমস্যা। আমি তখন যা বোঝাতে চাইছি তা হ্যান্ডলনটফাউন্ডএট্রিবিউট ফিল্টারটি অন্য কেউ উত্তর দিয়েছেন। প্রতিটি ক্রিয়াকলাপের জন্য এটি প্রয়োগ করা প্রয়োজন হয় না। উদাহরণস্বরূপ এটি কেবলমাত্র সেই ক্রিয়াকলাপের জন্য উপযুক্ত যেখানে আইডি প্যারাম রয়েছে তবে সূচীকরণ () ক্রিয়া নয়। আমি হ্যান্ডলনটফাউন্ডআট্রিবিউটের জন্য নয় বরং একটি কাস্টম হ্যান্ডলিরর অ্যাট্রিবিউটের জন্য বিশ্বব্যাপী ফিল্টারটিতে সম্মত হয়েছি।

আমি ভেবেছিলাম এমভিসি 3 এরও এটি ছিল, নিশ্চিত নয়। অন্যদের জন্য নির্বিশেষে ভাল আলোচনা যে উত্তরটি আসতে পারে
জন কালভিনার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.