HttpResponseException নিক্ষেপ করুন বা অনুরোধটি ফেরত দিন re


172

এএসপি.নেট ওয়েব এপিআই-তে এক্সেসপশন হ্যান্ডলিংয়ের একটি নিবন্ধ পর্যালোচনা করার পরে আমি কখন একটি ব্যতিক্রম ত্রুটি প্রতিক্রিয়া ফিরিয়ে আনব তা নিয়ে কিছুটা বিভ্রান্ত হয়ে পড়েছি। আমি যখন আপনার পদ্ধতিটি পরিবর্তে কোনও ডোমেন নির্দিষ্ট মডেলটি ফেরত দেয় তখন প্রতিক্রিয়াটি সংশোধন করা সম্ভব কিনা তা নিয়েও আমি ভাবছি HttpResponseMessage...

সুতরাং, এখানে পুনরুদ্ধার করার জন্য আমার প্রশ্নগুলি # কেস # সহ কিছু কোড অনুসরণ করে:

প্রশ্নাবলি

মামলা # 1 সম্পর্কিত প্রশ্নসমূহ

  1. আমার কী সর্বদা HttpResponseMessageকংক্রিট ডোমেন মডেলের পরিবর্তে ব্যবহার করা উচিত, যাতে বার্তাটি কাস্টমাইজ করা যায়?
  2. আপনি যদি কংক্রিটের ডোমেন মডেলটি ফিরিয়ে দিচ্ছেন তবে বার্তাটি কাস্টমাইজ করা যায়?

কেস # 2,3,4 সম্পর্কিত প্রশ্নাবলী

  1. আমি কি একটি ব্যতিক্রম ছোঁড়া বা ত্রুটি প্রতিক্রিয়া ফেরত করা উচিত? যদি উত্তরটি "এটি নির্ভর করে" হয় তবে আপনি কখন একটির তুলনায় অন্যটিকে ব্যবহার করতে পারেন সে সম্পর্কে পরিস্থিতি / উদাহরণ দিতে পারেন।
  2. HttpResponseExceptionবনাম ছুড়ে দেওয়ার মধ্যে পার্থক্য কী Request.CreateErrorResponse? ক্লায়েন্টের কাছে আউটপুট অভিন্ন বলে মনে হচ্ছে ...
  3. আমি কি সবসময় HttpErrorত্রুটিগুলিতে প্রতিক্রিয়া বার্তাগুলি "মোড়ানো" ব্যবহার করি (ব্যতিক্রম নিক্ষিপ্ত হয় বা ত্রুটির প্রতিক্রিয়া ফিরে আসে কিনা)?

কেস নমুনা

// CASE #1
public Customer Get(string id)
{
    var customer = _customerService.GetById(id);
    if (customer == null)
    {
        var notFoundResponse = new HttpResponseMessage(HttpStatusCode.NotFound);
        throw new HttpResponseException(notFoundResponse);
    }
    //var response = Request.CreateResponse(HttpStatusCode.OK, customer);
    //response.Content.Headers.Expires = new DateTimeOffset(DateTime.Now.AddSeconds(300));
    return customer;
}        

// CASE #2
public HttpResponseMessage Get(string id)
{
    var customer = _customerService.GetById(id);
    if (customer == null)
    {
        var notFoundResponse = new HttpResponseMessage(HttpStatusCode.NotFound);
        throw new HttpResponseException(notFoundResponse);
    }
    var response = Request.CreateResponse(HttpStatusCode.OK, customer);
    response.Content.Headers.Expires = new DateTimeOffset(DateTime.Now.AddSeconds(300));
    return response;
}

// CASE #3
public HttpResponseMessage Get(string id)
{
    var customer = _customerService.GetById(id);
    if (customer == null)
    {
        var message = String.Format("customer with id: {0} was not found", id);
        var errorResponse = Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
        throw new HttpResponseException(errorResponse);
    }
    var response = Request.CreateResponse(HttpStatusCode.OK, customer);
    response.Content.Headers.Expires = new DateTimeOffset(DateTime.Now.AddSeconds(300));
    return response;
}

// CASE #4
public HttpResponseMessage Get(string id)
{
    var customer = _customerService.GetById(id);
    if (customer == null)
    {
        var message = String.Format("customer with id: {0} was not found", id);
        var httpError = new HttpError(message);
        return Request.CreateErrorResponse(HttpStatusCode.NotFound, httpError);
    }
    var response = Request.CreateResponse(HttpStatusCode.OK, customer);
    response.Content.Headers.Expires = new DateTimeOffset(DateTime.Now.AddSeconds(300));
    return response;
}

হালনাগাদ

কেসগুলি আরও প্রদর্শন করতে সহায়তার জন্য # 2,3,4 নিম্নলিখিত কোড স্নিপেট গ্রাহককে পাওয়া না গেলে "ঘটতে পারে" এমন কয়েকটি বিকল্প হাইলাইট করে ...

if (customer == null)
{
    // which of these 4 options is the best strategy for Web API?

    // option 1 (throw)
    var notFoundMessage = new HttpResponseMessage(HttpStatusCode.NotFound);
    throw new HttpResponseException(notFoundMessage);

    // option 2 (throw w/ HttpError)
    var message = String.Format("Customer with id: {0} was not found", id);
    var httpError = new HttpError(message);
    var errorResponse = Request.CreateErrorResponse(HttpStatusCode.NotFound, httpError);
    throw new HttpResponseException(errorResponse);

    // option 3 (return)
    var message = String.Format("Customer with id: {0} was not found", id);
    return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
    // option 4 (return w/ HttpError)
    var message = String.Format("Customer with id: {0} was not found", id);
    var httpError = new HttpError(message);
    return Request.CreateErrorResponse(HttpStatusCode.NotFound, httpError);
}

6
@ মাইক ওয়াসন লিঙ্কযুক্ত নিবন্ধটির লেখক হিসাবে আপনি কোন পন্থা অবলম্বন করবেন?
zam6ak

উত্তর:


102

আমি যে পদ্ধতি নিয়েছি তা হ'ল এপিআই কন্ট্রোলার ক্রিয়াকলাপ থেকে কেবল ব্যতিক্রম ছুঁড়ে ফেলা এবং একটি ব্যতিক্রম ফিল্টার নিবন্ধিত হওয়া যা ব্যতিক্রম প্রক্রিয়া করে এবং কার্য সম্পাদন প্রসঙ্গে উপযুক্ত প্রতিক্রিয়া সেট করে।

ফিল্টারটি একটি সাশ্রয়ী ইন্টারফেস প্রকাশ করে যা বিশ্বব্যাপী কনফিগারেশনের মাধ্যমে ফিল্টারটি নিবন্ধ করার আগে নির্দিষ্ট ধরণের ব্যতিক্রমগুলির জন্য হ্যান্ডলারদের নিবন্ধকরণের একটি উপায় সরবরাহ করে।

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

ফিল্টার নিবন্ধকরণ উদাহরণ:

GlobalConfiguration.Configuration.Filters.Add(
    new UnhandledExceptionFilterAttribute()
    .Register<KeyNotFoundException>(HttpStatusCode.NotFound)

    .Register<SecurityException>(HttpStatusCode.Forbidden)

    .Register<SqlException>(
        (exception, request) =>
        {
            var sqlException = exception as SqlException;

            if (sqlException.Number > 50000)
            {
                var response            = request.CreateResponse(HttpStatusCode.BadRequest);
                response.ReasonPhrase   = sqlException.Message.Replace(Environment.NewLine, String.Empty);

                return response;
            }
            else
            {
                return request.CreateResponse(HttpStatusCode.InternalServerError);
            }
        }
    )
);

আনহানডেলড এক্সসেপশনফিল্টারঅ্যাট্রিবিউট ক্লাস:

using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http.Filters;

namespace Sample
{
    /// <summary>
    /// Represents the an attribute that provides a filter for unhandled exceptions.
    /// </summary>
    public class UnhandledExceptionFilterAttribute : ExceptionFilterAttribute
    {
        #region UnhandledExceptionFilterAttribute()
        /// <summary>
        /// Initializes a new instance of the <see cref="UnhandledExceptionFilterAttribute"/> class.
        /// </summary>
        public UnhandledExceptionFilterAttribute() : base()
        {

        }
        #endregion

        #region DefaultHandler
        /// <summary>
        /// Gets a delegate method that returns an <see cref="HttpResponseMessage"/> 
        /// that describes the supplied exception.
        /// </summary>
        /// <value>
        /// A <see cref="Func{Exception, HttpRequestMessage, HttpResponseMessage}"/> delegate method that returns 
        /// an <see cref="HttpResponseMessage"/> that describes the supplied exception.
        /// </value>
        private static Func<Exception, HttpRequestMessage, HttpResponseMessage> DefaultHandler = (exception, request) =>
        {
            if(exception == null)
            {
                return null;
            }

            var response            = request.CreateResponse<string>(
                HttpStatusCode.InternalServerError, GetContentOf(exception)
            );
            response.ReasonPhrase   = exception.Message.Replace(Environment.NewLine, String.Empty);

            return response;
        };
        #endregion

        #region GetContentOf
        /// <summary>
        /// Gets a delegate method that extracts information from the specified exception.
        /// </summary>
        /// <value>
        /// A <see cref="Func{Exception, String}"/> delegate method that extracts information 
        /// from the specified exception.
        /// </value>
        private static Func<Exception, string> GetContentOf = (exception) =>
        {
            if (exception == null)
            {
                return String.Empty;
            }

            var result  = new StringBuilder();

            result.AppendLine(exception.Message);
            result.AppendLine();

            Exception innerException = exception.InnerException;
            while (innerException != null)
            {
                result.AppendLine(innerException.Message);
                result.AppendLine();
                innerException = innerException.InnerException;
            }

            #if DEBUG
            result.AppendLine(exception.StackTrace);
            #endif

            return result.ToString();
        };
        #endregion

        #region Handlers
        /// <summary>
        /// Gets the exception handlers registered with this filter.
        /// </summary>
        /// <value>
        /// A <see cref="ConcurrentDictionary{Type, Tuple}"/> collection that contains 
        /// the exception handlers registered with this filter.
        /// </value>
        protected ConcurrentDictionary<Type, Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>>> Handlers
        {
            get
            {
                return _filterHandlers;
            }
        }
        private readonly ConcurrentDictionary<Type, Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>>> _filterHandlers = new ConcurrentDictionary<Type, Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>>>();
        #endregion

        #region OnException(HttpActionExecutedContext actionExecutedContext)
        /// <summary>
        /// Raises the exception event.
        /// </summary>
        /// <param name="actionExecutedContext">The context for the action.</param>
        public override void OnException(HttpActionExecutedContext actionExecutedContext)
        {
            if(actionExecutedContext == null || actionExecutedContext.Exception == null)
            {
                return;
            }

            var type    = actionExecutedContext.Exception.GetType();

            Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>> registration = null;

            if (this.Handlers.TryGetValue(type, out registration))
            {
                var statusCode  = registration.Item1;
                var handler     = registration.Item2;

                var response    = handler(
                    actionExecutedContext.Exception.GetBaseException(), 
                    actionExecutedContext.Request
                );

                // Use registered status code if available
                if (statusCode.HasValue)
                {
                    response.StatusCode = statusCode.Value;
                }

                actionExecutedContext.Response  = response;
            }
            else
            {
                // If no exception handler registered for the exception type, fallback to default handler
                actionExecutedContext.Response  = DefaultHandler(
                    actionExecutedContext.Exception.GetBaseException(), actionExecutedContext.Request
                );
            }
        }
        #endregion

        #region Register<TException>(HttpStatusCode statusCode)
        /// <summary>
        /// Registers an exception handler that returns the specified status code for exceptions of type <typeparamref name="TException"/>.
        /// </summary>
        /// <typeparam name="TException">The type of exception to register a handler for.</typeparam>
        /// <param name="statusCode">The HTTP status code to return for exceptions of type <typeparamref name="TException"/>.</param>
        /// <returns>
        /// This <see cref="UnhandledExceptionFilterAttribute"/> after the exception handler has been added.
        /// </returns>
        public UnhandledExceptionFilterAttribute Register<TException>(HttpStatusCode statusCode) 
            where TException : Exception
        {

            var type    = typeof(TException);
            var item    = new Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>>(
                statusCode, DefaultHandler
            );

            if (!this.Handlers.TryAdd(type, item))
            {
                Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>> oldItem = null;

                if (this.Handlers.TryRemove(type, out oldItem))
                {
                    this.Handlers.TryAdd(type, item);
                }
            }

            return this;
        }
        #endregion

        #region Register<TException>(Func<Exception, HttpRequestMessage, HttpResponseMessage> handler)
        /// <summary>
        /// Registers the specified exception <paramref name="handler"/> for exceptions of type <typeparamref name="TException"/>.
        /// </summary>
        /// <typeparam name="TException">The type of exception to register the <paramref name="handler"/> for.</typeparam>
        /// <param name="handler">The exception handler responsible for exceptions of type <typeparamref name="TException"/>.</param>
        /// <returns>
        /// This <see cref="UnhandledExceptionFilterAttribute"/> after the exception <paramref name="handler"/> 
        /// has been added.
        /// </returns>
        /// <exception cref="ArgumentNullException">The <paramref name="handler"/> is <see langword="null"/>.</exception>
        public UnhandledExceptionFilterAttribute Register<TException>(Func<Exception, HttpRequestMessage, HttpResponseMessage> handler) 
            where TException : Exception
        {
            if(handler == null)
            {
              throw new ArgumentNullException("handler");
            }

            var type    = typeof(TException);
            var item    = new Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>>(
                null, handler
            );

            if (!this.Handlers.TryAdd(type, item))
            {
                Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>> oldItem = null;

                if (this.Handlers.TryRemove(type, out oldItem))
                {
                    this.Handlers.TryAdd(type, item);
                }
            }

            return this;
        }
        #endregion

        #region Unregister<TException>()
        /// <summary>
        /// Unregisters the exception handler for exceptions of type <typeparamref name="TException"/>.
        /// </summary>
        /// <typeparam name="TException">The type of exception to unregister handlers for.</typeparam>
        /// <returns>
        /// This <see cref="UnhandledExceptionFilterAttribute"/> after the exception handler 
        /// for exceptions of type <typeparamref name="TException"/> has been removed.
        /// </returns>
        public UnhandledExceptionFilterAttribute Unregister<TException>()
            where TException : Exception
        {
            Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>> item = null;

            this.Handlers.TryRemove(typeof(TException), out item);

            return this;
        }
        #endregion
    }
}

উত্স কোডও এখানে পাওয়া যাবে


কি দারুন! :) এটি ছোট প্রকল্পগুলির জন্য কিছুটা হলেও হতে পারে তবে এখনও খুব সুন্দর ... বিটিডাব্লু, ডিফল্টহ্যান্ডলারের ক্রিয়েটআররআরস্পোনসের পরিবর্তে ক্রিয়েটরেসপোনস কেন?
zam6ak

আমি ত্রুটি বিশদটি (শরীরে সিরিয়ালযুক্ত) কারণ বাক্যাংশ থেকে আলাদা করার চেষ্টা করছিলাম; তবে যদি আপনি মডেল বাইন্ডিংয়ের ক্ষেত্রে এর চেয়ে বেশি জ্ঞান তৈরি করেন তবে আপনি অবশ্যই তৈরিরররআরস্পোন ব্যবহার করতে পারেন।
বিরোধী

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

আপনি রক্ষীদের জন্য (হোমগ্রাউন বা তৃতীয় পক্ষ) কী ব্যবহার করছেন?
zam6ak

হেমগ্রাউন, আমি উপরের উদাহরণে এর ব্যবহারটি সরিয়েছি। গার্ড ক্লাস স্থিতিশীল পদ্ধতির একটি সেট সরবরাহ করে যা একটি দাবি পূরণ হয়েছে কিনা তা থেকে রক্ষা করে বা যাচাই করে। আপনি যদি বাস্তবায়ন চান তবে কোডেপস্টে.নেট / 5 এস 1 আইফ (গার্ড) এবং কোডেপস্টে.net / সেন্সরই ( ডেলিগেটইনফো ) দেখুন ।
বিরোধী

23

আপনি যদি HTTPResponseMessage ফিরে না আসছেন এবং পরিবর্তে সত্তা / মডেল ক্লাসগুলি সরাসরি ফিরিয়ে দিচ্ছেন তবে আমি যে কৌশলটি কার্যকর মনে করেছি তা হল আমার নিয়ামকের সাথে নিম্নলিখিত ইউটিলিটি ফাংশনটি যুক্ত করা is

private void ThrowResponseException(HttpStatusCode statusCode, string message)
{
    var errorResponse = Request.CreateErrorResponse(statusCode, message);
    throw new HttpResponseException(errorResponse);
}

এবং কেবল এটিকে উপযুক্ত স্থিতি কোড এবং বার্তা সহ কল ​​করুন


4
এটি সঠিক উত্তর, এটি শরীরে একটি মূল মান জুটি হিসাবে "বার্তা" বিন্যাসের সাথে আসে। এটি সাধারণত আমি অন্যান্য ফ্রেমওয়ার্ক এবং ভাষাগুলি এটি দেখতে দেখি
মোবাইলমন

এই পদ্ধতির সম্পর্কে আমার একটি ছোটখাটো প্রশ্ন আছে। আমি কৌনিক জেএস পৃষ্ঠায় {{}} সিনট্যাক্স ব্যবহার করে বার্তাটি গ্রাস করছি। আমি যদি গাড়ীর রিটার্ন ছেড়ে যাই তবে তারা বার্তায় n \ r as হিসাবে আসে। এগুলি সংরক্ষণের সঠিক উপায় কী?
নাওমি

আমি এই পদ্ধতির চেষ্টা করেছি। আমি করেছি throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid Request Format!")), তবে ফিডলারের মধ্যে এটি স্ট্যাটাস দেখায় 500 (400 নয়)। কোন ধারণা কেন?
স্যাম

পার্থক্যটি হ'ল ত্রুটির মূল কাজ function অ্যাপ্লিকেশনটিতে যে কোনও ব্যতিক্রমের জন্য এখানে থ্রো রিস্পোন এক্সেপশন। তবে ব্যতিক্রমটি ছুঁড়ে ফেলার আসল ফাংশনটি হওয়া উচিত ...
সার্জ

15

মামলা 1

  1. অগত্যা নয়, পাইপলাইনে অন্যান্য প্রতিক্রিয়া পরিবর্তন করার জন্য অন্যান্য জায়গা রয়েছে (অ্যাকশন ফিল্টার, বার্তা হ্যান্ডলার)।
  2. উপরে দেখুন - কিন্তু যদি কর্ম একটি ডোমেইন মডেল ফেরৎ, তাহলে আপনি প্রতিক্রিয়া সংশোধন করতে পারবেন না ভিতরে কর্ম।

কেস # 2-4

  1. HttpResponseException নিক্ষেপের প্রধান কারণগুলি হ'ল:
    • আপনি যদি কোনও ডোমেন মডেল ফিরিয়ে দিচ্ছেন তবে ত্রুটির কেসগুলি পরিচালনা করতে হবে,
    • ব্যতিক্রম হিসাবে ত্রুটিগুলি আচরণ করে আপনার নিয়ামক যুক্তিটিকে সহজ করতে
  2. এগুলি সমতুল্য হওয়া উচিত; এইচটিটিপি রেসপোনস এক্সসেপশন একটি এইচটিটিপি রেসপোনসমেসেজকে এনক্যাপুলেট করে, যা এইচটিটিপি প্রতিক্রিয়া হিসাবে ফিরে আসে।

    উদাহরণস্বরূপ, কেস # 2 হিসাবে আবারও লেখা যেতে পারে

    public HttpResponseMessage Get(string id)
    {
        HttpResponseMessage response;
        var customer = _customerService.GetById(id);
        if (customer == null)
        {
            response = new HttpResponseMessage(HttpStatusCode.NotFound);
        }
        else
        {
            response = Request.CreateResponse(HttpStatusCode.OK, customer);
            response.Content.Headers.Expires = new DateTimeOffset(DateTime.Now.AddSeconds(300));
        }
        return response;
    }

    ... তবে যদি আপনার নিয়ামক যুক্তি আরও জটিল হয় তবে একটি ব্যতিক্রম ছুঁড়ে দেওয়া কোড প্রবাহকে সহজতর করতে পারে।

  3. এইচটিপিআরআর আপনাকে প্রতিক্রিয়া বডির জন্য একটি সামঞ্জস্যপূর্ণ ফর্ম্যাট দেয় এবং জেএসএন / এক্সএমএল / ইত্যাদিতে সিরিয়ালায়িত করা যেতে পারে, তবে এটির প্রয়োজন নেই। উদাহরণস্বরূপ, আপনি প্রতিক্রিয়াতে কোনও সত্তা-দেহ অন্তর্ভুক্ত করতে না চাইতে পারেন, বা আপনি অন্য কোনও ফর্ম্যাটটি পেতে চাইতে পারেন।


আমি যে পদ্ধতি নিয়েছি তা হ'ল এপিআই কন্ট্রোলার ক্রিয়াকলাপ থেকে কেবল ব্যতিক্রম ছড়িয়ে দেওয়া এবং আমি একটি ব্যতিক্রম ফিল্টার নিবন্ধিত করেছি যা ব্যতিক্রমটি প্রসেস করে এবং ক্রিয়া সম্পাদন প্রসঙ্গে উপযুক্ত প্রতিক্রিয়া সেট করে। ফিল্টারটি 'প্লাগেবল' এমন যে আমি বিশ্বব্যাপী কনফিগারেশনের মাধ্যমে ফিল্টারটি নিবন্ধ করার আগে নির্দিষ্ট ধরণের ব্যতিক্রমগুলির জন্য হ্যান্ডলারের নিবন্ধন করতে পারি। এটি আমাকে কন্ট্রোলারগুলিতে ছড়িয়ে দেওয়ার পরিবর্তে কেন্দ্রীভূত ব্যতিক্রম হ্যান্ডলিংয়ের অনুমতি দেয়।
বিরোধী

@ আপত্তিগত কোনও সুযোগ আপনি কি আপনার ব্যতিক্রম ফিল্টার ভাগ করতে চান? সম্ভবত গিস্ট হিসাবে বা কোনও কোড শেয়ার সাইটে যেমন কোডপাস্ট?
পাইগ কুক

@ মাইক ওয়াসন আপনি কি বলবেন যে "রিটার্ন ত্রুটি প্রতিক্রিয়া" "ফলো ব্যতিক্রম" বনাম আরও সাধারণ পদ্ধতি? আমি বুঝতে পারছি কার্যক্রমে শেষ ফলাফলটি একই (তবে?) একই হতে পারে তবে আমি ভাবছি কেন কেবল চেষ্টা / ধরা এবং ত্রুটি প্রতিক্রিয়াটিকে যথাযথ হিসাবে প্রত্যাবর্তন করতে পুরো নিয়ামক যুক্তিকে অন্তর্ভুক্ত করবেন না?
zam6ak

15

একটি HttpResponseException নিক্ষেপ বা আসতে একটি HttpResponesMessage ত্রুটির জন্য না - ব্যতীত যদি অভিপ্রায় হয় অনুরোধ শেষ সঙ্গে যে সঠিক ফলাফলের

HttpResponseException এর অন্যান্য ব্যতিক্রমগুলির মতো পরিচালনা করা হয় না । তারা ব্যতিক্রম ফিল্টারগুলিতে ধরা পড়েনি । তারা ব্যতিক্রম হ্যান্ডলারের হাতে ধরা পড়ে না । বর্তমান কোডটির সম্পাদন প্রবাহ বন্ধ করার সময় এগুলি একটি এইচটিটিপিআরস্পোনমেসেজে পিছলে যাওয়ার এক ধূর্ত উপায়।

কোডটি যদি এই বিশেষ আন-হ্যান্ডলিংয়ের উপর নির্ভর করে অবকাঠামোগত কোড না হয় তবে এইচটিপিআরএসপোনস এক্সসেপশন প্রকারটি ব্যবহার এড়িয়ে চলুন!

HttpResponseMessage এর ব্যতিক্রম নয়। তারা বর্তমান কোডটির কার্যকরকরণ প্রবাহকে শেষ করে না। এগুলি ব্যতিক্রম হিসাবে ফিল্টার করা যায় না । তারা ব্যতিক্রম হিসাবে লগ করা যাবে না । তারা একটি বৈধ ফলাফল উপস্থাপন করে - এমনকি 500 টি প্রতিক্রিয়া হ'ল একটি বৈধ ব্যতিক্রমী প্রতিক্রিয়া "!


জীবনকে সহজ করুন:

যখন কোনও ব্যতিক্রমী / ত্রুটির ক্ষেত্রে থাকে, তখন এগিয়ে যান এবং একটি সাধারণ .NET ব্যতিক্রম - বা একটি অনুকূলিত অ্যাপ্লিকেশন ব্যতিক্রম প্রকার ( HttpResponseException থেকে প্রাপ্ত নয় ) যেমন স্থিতি কোডের মতো কাঙ্ক্ষিত 'http ত্রুটি / প্রতিক্রিয়া' বৈশিষ্ট্য সহ - সাধারণ ব্যতিক্রম অনুসারে হ্যান্ডলিং

এই ব্যতিক্রমী কেসগুলির সাথে উপযুক্ত কিছু করতে ব্যতিক্রম ফিল্টার / ব্যতিক্রম হ্যান্ডলার / ব্যতিক্রম লগার ব্যবহার করুন: স্থিতি কোডগুলি পরিবর্তন / যুক্ত করুন? ট্র্যাকিং শনাক্তকারীদের যুক্ত করবেন? স্ট্যাক ট্রেস অন্তর্ভুক্ত? লগ ইন করুন?

HttpResponseException এড়িয়ে 'ব্যতিক্রমী কেস' হ্যান্ডলিংটি ইউনিফর্ম তৈরি করে এবং এক্সপোজড পাইপলাইনের অংশ হিসাবে পরিচালনা করা যায়! উদাহরণস্বরূপ, কেউ 'নটফাউন্ড' কে একটি 404 এবং একটি 'আর্গুমেন্টএক্সেপশন' 400 এ রূপান্তর করতে পারে এবং অ্যাপ্লিকেশন-স্তরের ব্যতিক্রমগুলির সাথে একযোগে 500 টিতে 'নালরফারেন্স' - বর্ধনযোগ্যতা যেমন ত্রুটি লগিংয়ের জন্য "বেসিকগুলি" সরবরাহ করার অনুমতি দেয়।


2
আমি বুঝতে পারি কেন ArgumentExceptionএকটি নিয়ামক এর কেন যৌক্তিকভাবে 400 হবে, কিন্তু ArgumentExceptionস্ট্যাকের আরও গভীর কী ? এগুলি 400 এ রূপান্তরিত করা অগত্যা সঠিক হবে না, তবুও যদি আপনার কাছে এমন একটি ফিল্টার থাকে যা কম্বল সমস্ত এসকে ArgumentException400 এ রূপান্তর করে তবে এড়ানো থেকে বাঁচার একমাত্র উপায় নিয়ামকের মধ্যে ব্যতিক্রম ধরা এবং আবার কিছু ফেলে দেওয়া, যা মনে হয় ফিল্টার বা অনুরূপ ব্যতিক্রম হ্যান্ডলিংয়ের উদ্দেশ্যকে পরাস্ত করতে।
cmeeren

@cmeeren কোডটিতে আমি এটিই আচরণ করছিলাম, বেশিরভাগ ব্যতিক্রমটি ধরা পড়ে এবং প্রতিটি ওয়েব-পদ্ধতিতে এটি HTTPResponse [ব্যতিক্রম / বার্তা] রূপান্তরিত করে। উভয় ক্ষেত্রেই একইরকম , যদি উদ্বেগটি অভ্যন্তরীণ ব্যতিক্রমগুলির সাথে পৃথকভাবে কিছু করা হয় যা ধরা পড়ে অভ্যন্তরীণ ব্যতিক্রমের সাথে "কিছু" করা হয়: আমি প্রস্তাব দিই ফলস্বরূপ একটি উপযুক্ত মোড়কের ব্যতিক্রম ছুঁড়ে দেওয়া যা এখনও সামলে নেওয়া হয় স্ট্যাক।
ব্যবহারকারী 2864740

@cmeeren আপডেটের পরে, আমাদের বেশিরভাগ ওয়েব এন্ট্রি পয়েন্টগুলি ব্যবহারের ত্রুটিগুলিতে একটি বিশেষ উত্সযুক্ত (নন-এইচটিপিআরসিপোনসএক্সসেপশন, যা সঠিক প্রতিক্রিয়া কোডগুলিতে ম্যাপযুক্ত বা থাকে) ফেলে দেয়। ইউনিফর্ম হ্যান্ডলার কিছু স্ট্যাক পরিদর্শন করতে পারে (আইকি, তবে এটি কিছু যত্ন নিয়ে কাজ করে) ব্যতিক্রমটি কোন স্তর থেকে এসেছে তা নির্ধারণ করতে - অর্থাৎ। 99% কেসগুলিতে বেশি সংশোধিত হ্যান্ডলিং নেই - বা অভ্যন্তরীণ ত্রুটির জন্য কেবল 500 এর সাথে সাড়া দিন। HttpResponseException সহ কারুকস হ'ল এটি দরকারী পাইপলাইন প্রক্রিয়াকরণটিকে বাইপাস করে।
ব্যবহারকারী 2864740

9

HttpResponseExceptionপরিবর্তে Response.CreateResponse(HttpStatusCode.NotFound), বা অন্য ত্রুটি স্থিতির কোডের পরিবর্তে কখন ব্যবহার করতে হবে তার জন্য আরেকটি ক্ষেত্রে হ'ল যদি আপনার অ্যাকশন ফিল্টারগুলিতে লেনদেন হয় এবং আপনি ক্লায়েন্টকে ত্রুটির প্রতিক্রিয়া ফিরিয়ে দেওয়ার সময় লেনদেনগুলি ফিরিয়ে আনতে চান।

ব্যবহার Response.CreateResponseকরলে লেনদেনটি পিছনে ফিরে আসবে না, যেখানে ব্যতিক্রম ছুঁড়ে ফেলা হবে।


3

আমি এটি উল্লেখ করতে চাই যে এটি আমার অভিজ্ঞতা হয়েছে যে কোনও ওয়েবপি 2 পদ্ধতিতে এইচটিপিআরএসপোনসম্যাসেজটি ফেরার পরিবর্তে এইচটিটিপিআরস্পোনসেক্সপশনটি ছুঁড়ে ফেলা হলে, যদি আইআইএস এক্সপ্রেসে তাত্ক্ষণিকভাবে কোনও কল করা হয় তবে এটি শেষ হয়ে যাবে বা 200 ফিরিয়ে দেবে তবে এইচটিএমএল ত্রুটির সাথে প্রতিক্রিয়া. এটি পরীক্ষার সহজতম উপায় হ'ল একটি পদ্ধতিতে to .জ্যাক্স কল করা যা কোনও এইচটিপিআরস্পোন এক্সেপশনটি ছুড়ে ফেলে এবং অজ্যাক্স-এ ত্রুটি-কলব্যাকে অন্য কোনও পদ্ধতিতে বা এমনকি একটি সাধারণ পোস্ট পৃষ্ঠায় তাত্ক্ষণিক কল করতে পারে। আপনি লক্ষ্য করবেন অমিডিয়েট কল ব্যর্থ হবে। যদি আপনি ত্রুটি কলটিতে একটি ব্রেক পয়েন্ট বা একটি সেটটাইমআউট () যোগ করেন তবে দ্বিতীয় কলটি দ্বিতীয় বা দু'বার বিলম্বিত করতে সার্ভারকে পুনরুদ্ধার করতে সময় দেয় যাতে এটি সঠিকভাবে কাজ করে।

হালনাগাদ:ওয়্যার্ড এজাক্স সংযোগের সময়সীমাটির মূল কারণটি যদি একটি এজাক্স কলটি দ্রুত করা হয় তবে একই টিসিপি সংযোগটি ব্যবহৃত হয়। আমি এইচটিটিপিআরসনেসমেজ ফিরে বা একটি HTTPResponseException নিক্ষেপ করে একটি 401 ত্রুটি ইথার উত্থাপন করছি যা ব্রাউজারের এজাক্স কলটিতে ফিরে এসেছিল। তবে সেই কলটির সাথে সাথে এমএস একটি অবজেক্ট নট সন্ধানের ত্রুটি ফিরিয়েছিল কারণ স্টার্টআপে uthউথ.ভিবি অ্যাপ্লিকেশন U ইউজারকুকি প্রমাণীকরণ সক্ষম করা হয়েছিল তাই এটি প্রতিক্রিয়াটি ফিরে আসার চেষ্টা করে এবং একটি পুনর্নির্দেশ যুক্ত করার চেষ্টা করছিল তবে এটি অবজেক্ট নট অব ইনজেক্টের সাথে ভুল করে। এই ত্রুটিটি এইচটিএমএল ছিল তবে সত্যতার পরে প্রতিক্রিয়াতে যুক্ত হয়েছিল তাই কেবলমাত্র যদি এজাক্স কলটি দ্রুত করা হয় এবং একই টিসিপি সংযোগটি ব্রাউজারে ফিরে আসে এবং তারপরে এটি পরবর্তী কলের সামনের দিকে যুক্ত হয়ে যায়। কিছু কারণে ক্রমের সময়সীমা শেষ হয়েছে, ফিডলার জসন এবং এইচটিএম এর মিশ্রণটি ছুঁড়েছিলেন তবে ফায়ারফক্সটি আসল ত্রুটিটিকে শক্ত করে দিয়েছে। তাই এটিকে নিচে নেওয়ার একমাত্র উপায় ছিল উইন্ডার্ড তবে প্যাকেট স্নিফার বা ফায়ারফক্স।

এছাড়াও এটি লক্ষ করা উচিত যে আপনি যদি স্বয়ংক্রিয় সহায়তা জেনার জন্য ওয়েব API সহায়তা ব্যবহার করে থাকেন এবং আপনি এইচটিটিপিআরএসপোনসম্যাসেজ ফেরত দেন তবে আপনার একটি যুক্ত করা উচিত

[System.Web.Http.Description.ResponseType(typeof(CustomReturnedType))] 

পদ্ধতির বৈশিষ্ট্য যাতে সহায়তা সঠিকভাবে উত্পন্ন হয়। তারপর

return Request.CreateResponse<CustomReturnedType>(objCustomeReturnedType) 

বা ত্রুটি

return Request.CreateErrorResponse( System.Net.HttpStatusCode.InternalServerError, new Exception("An Error Ocurred"));

আশা করি এটি এইচটিটিপিআরস্পোন এক্সেপশন ছুঁড়ে দেওয়ার পরে অবিলম্বে র্যান্ডম টাইমআউট বা সার্ভার উপলব্ধ না হয়ে অন্য কাউকে সহায়তা করে।

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

আপডেট: আমি আইআইএস এক্সপ্রেসের সময় নির্ধারণের বিষয়ে আমার বক্তব্য প্রত্যাহার করছি, এটি আমার ক্লায়েন্টের পক্ষের এজাক্স কলটিতে ভুল হয়েছে যা আজাক্স ১.৮ থেকে $ .জ্যাক্স () এবং ফেরত $ .জ্যাক্স () এর পরে দেখা যাচ্ছে then () তখন () উভয়ই প্রত্যাবর্তন প্রতিশ্রুতি দেয় তবে একই শৃঙ্খলযুক্ত প্রতিশ্রুতি নয় () তখন একটি নতুন প্রতিশ্রুতি দেয় যা মৃত্যুদন্ড কার্যকর করার আদেশকে ভুল বলে দেয়। সুতরাং যখন তত্ক্ষণিক () প্রতিশ্রুতি পূর্ণ হয়েছিল তখন এটি ছিল একটি স্ক্রিপ্ট সময়সীমা। অদ্ভুত গোটচা তবে আইআইএস এক্সপ্রেস নয় কী-বোর্ড এবং চেয়ারের মধ্যে সমস্যা issue


0

আমি যতদূর বলতে পারি, আপনি কোনও ব্যতিক্রম ছুঁড়ে ফেলুন বা আপনি অনুরোধটি ফেরত দিন কিনা। ক্রিয়েট এরিরআরস্পোনস, ফলাফলটি একই। আপনি যদি System.Web.Http.dll এর উত্স কোডটি দেখেন তবে আপনি দেখতে পাবেন। এই সাধারণ সংক্ষিপ্তসার এবং আমি তৈরি করেছি এমন একটি খুব একই সমাধান দেখুন: ওয়েব এপি, এইচটিপিআরর, এবং ব্যতিক্রমগুলির আচরণ


0

ত্রুটি পরিস্থিতিতে, আমি ক্লায়েন্টকে খুশি পথ অবজেক্টের পরিবর্তে অনুরোধ করা যাই হোক না কেন বিন্যাসে একটি নির্দিষ্ট ত্রুটির বিশদ বিবরণ শ্রেণিতে ফিরে আসতে চেয়েছিলাম।

আমি চাই আমার কন্ট্রোলার পদ্ধতিগুলি ডোমেনের নির্দিষ্ট সুখী পথ অবজেক্টটি ফিরিয়ে আনতে এবং অন্যথায় ব্যতিক্রম ছুঁড়ে ফেলাতে চায়।

আমার যে সমস্যাটি ছিল তা হচ্ছিল যে এইচটিটিপিআরস্পোন এক্সেপশন কনস্ট্রাক্টররা ডোমেন অবজেক্টগুলিকে অনুমতি দেয় না।

এই আমি অবশেষে সামনে এসেছি

public ProviderCollection GetProviders(string providerName)
{
   try
   {
      return _providerPresenter.GetProviders(providerName);
   }
   catch (BadInputValidationException badInputValidationException)
   {
     throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest,
                                          badInputValidationException.Result));
   }
}

Resultএমন একটি শ্রেণি যা ত্রুটির বিশদ যুক্ত করে, যদিও ProviderCollectionআমার খুশির পথ ফলাফল।


0

আমি বিরোধী উত্তর পছন্দ করি

যাইহোক, উত্তরাধিকারসূত্রে প্রাপ্ত ব্যতিক্রমটি ধরার জন্য আমার একটি উপায়ের প্রয়োজন ছিল এবং এই সমাধানটি আমার সমস্ত চাহিদা পূরণ করে না।

সুতরাং আমি কীভাবে তিনি অনেক্সপশন পরিচালনা করি তা পরিবর্তন করে শেষ করেছি এবং এটি আমার সংস্করণ

public override void OnException(HttpActionExecutedContext actionExecutedContext) {
   if (actionExecutedContext == null || actionExecutedContext.Exception == null) {
      return;
   }

   var type = actionExecutedContext.Exception.GetType();

   Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>> registration = null;

   if (!this.Handlers.TryGetValue(type, out registration)) {
      //tento di vedere se ho registrato qualche eccezione che eredita dal tipo di eccezione sollevata (in ordine di registrazione)
      foreach (var item in this.Handlers.Keys) {
         if (type.IsSubclassOf(item)) {
            registration = this.Handlers[item];
            break;
         }
      }
   }

   //se ho trovato un tipo compatibile, uso la sua gestione
   if (registration != null) {
      var statusCode = registration.Item1;
      var handler = registration.Item2;

      var response = handler(
         actionExecutedContext.Exception.GetBaseException(),
         actionExecutedContext.Request
      );

      // Use registered status code if available
      if (statusCode.HasValue) {
         response.StatusCode = statusCode.Value;
      }

      actionExecutedContext.Response = response;
   }
   else {
      // If no exception handler registered for the exception type, fallback to default handler
      actionExecutedContext.Response = DefaultHandler(actionExecutedContext.Exception.GetBaseException(), actionExecutedContext.Request
      );
   }
}

মূলটি এই লুপটি যেখানে আমি পরীক্ষা করে দেখি ব্যতিক্রমটি কোনও নিবন্ধিত ধরণের একটি সাবক্লাস কিনা।

foreach (var item in this.Handlers.Keys) {
    if (type.IsSubclassOf(item)) {
        registration = this.Handlers[item];
        break;
    }
}

my2cents

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