HttpResponseException'ı döndürün veya Request.CreateErrorResponse?


172

ASP.NET Web API'de bir özel durum işleme inceledikten sonra Bir hata ne zaman vs bir istisna atmak ne zaman biraz karışık. Ayrıca yöntem yerine bir etki alanına özgü modeli döndürdüğünde yanıtı değiştirmek mümkün olup olmadığını merak bıraktı HttpResponseMessage...

Burada özetlemek gerekirse, sorularımın ardından #s ile bazı kodlar geliyor:

Sorular

Dava # 1 ile ilgili sorular

  1. HttpResponseMessageMesajın özelleştirilebilmesi için her zaman somut bir alan modeli yerine kullanmalı mıyım ?
  2. Somut alan adı modelini iade ediyorsanız mesaj özelleştirilebilir mi?

Dava # 2,3,4 ile ilgili sorular

  1. Bir istisna atmalı mıyım veya hata yanıtı döndürmeli miyim? Cevap "duruma göre değişir" ise, birinden diğerine ne zaman kullanılacağına ilişkin durumlar / örnekler verebilir misiniz?
  2. Throwing HttpResponseExceptionvs arasındaki fark nedir Request.CreateErrorResponse? İstemciye çıktı aynı görünüyor ...
  3. HttpErrorYanıt mesajlarını her zaman hatalarda "istisna" olarak mı kullanmalıyım (istisna atılıyor veya hata yanıtı döndürülsün)?

Vaka Örnekleri

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

Güncelleme

2,3,4 numaralı vakaları daha fazla göstermeye yardımcı olmak için aşağıdaki kod snippet'i, bir müşteri bulunamadığında "gerçekleşebilecek" çeşitli seçenekleri vurgular ...

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
@Mike Wasson Bağlantılı makalenin yazarı olarak hangi yaklaşımı benimseyeceksiniz?
zam6ak

Yanıtlar:


102

Aldığım yaklaşım, api denetleyici eylemlerinden istisnalar atmak ve istisnayı işleyen ve eylem yürütme bağlamında uygun bir yanıt ayarlayan bir istisna filtresine sahip olmaktır.

Filtre, filtreyi genel yapılandırmaya kaydetmeden önce belirli istisna türleri için işleyicileri kaydetmenin bir yolunu sağlayan akıcı bir arayüz sunar.

Bu filtrenin kullanımı, denetleyici eylemlerine yayılmak yerine merkezi istisna işlemeye olanak tanır. Bununla birlikte, denetleyici eylemi içinde istisnaları yakalayacağım ve söz konusu istisnanın işlenmesini merkezileştirmenin bir anlamı yoksa belirli bir yanıt döndüreceğim durumlar vardır.

Filtrenin örnek kaydı:

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

UnhandledExceptionFilterAttribute sınıfı:

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

Kaynak kodu da burada bulunabilir .


Vaov! :) Bu küçük projeler için biraz fazla olabilir, ama yine de çok güzel ... BTW, neden DefaultHandler'da CreateErrorResponse yerine CreateResponse?
zam6ak

(Vücutta serileştirilmiş) hata ayrıntılarını neden deyiminden ayırmaya çalışıyordum; ancak model bağlama durumunda olduğu gibi daha mantıklıysa kesinlikle CreateErrorResponse'yi kullanabilirsiniz.
Muhalif

1
Filtreyi yalnızca bir kod satırı ile kaydedebileceğiniz için, hemen hemen her proje türü için uygun olduğunu düşünüyorum. Filtreyi dahili NuGet feed'imizde yayınlanan bir sınıf kütüphanesinde sahibiz, bu nedenle geliştiricilerin kullanımı kolaydır.
Muhalif

Muhafızlar için ne kullanıyorsunuz (evde yetişmiş veya 3. taraf)?
zam6ak

Hoemgrown, yukarıdaki örnekte kullanımını kaldırdım. Guard sınıfı, bir iddianın karşılandığını doğrulayan veya doğrulayan bir dizi statik yöntem sağlar. Uygulamayı isterseniz, bkz. Codepaste.net/5oc1if (Guard) ve codepaste.net/nsrsei (DelegateInfo).
Muhalif

23

Eğer dönen değilseniz HttpResponseMessage yerine ve benim kontrolöre sonrasında kamu işlev eklemek için, doğrudan faydalı bulduğum bir yaklaşım varlık / model sınıfları edilir dönüyor

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

ve sadece uygun durum kodu ve mesajla arayın


4
Bu doğru cevap, vücutta bir anahtar değer çifti olarak "Mesaj" biçimiyle geliyor. Bu genellikle diğer çerçeveleri ve dilleri nasıl görüyorum
MobileMon

Bu yaklaşım hakkında küçük bir sorum var. İletiyi angularJS sayfasındaki {{}} sözdizimini kullanarak tüketiyorum. Taşıyıcı iadelerini bırakırsam mesajda n \ r \ olarak gelirler. Onları korumanın doğru yolu nedir?
Naomi

Bu yaklaşımı denedim. Ben yaptım throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid Request Format!"))ama Fiddler'da, bu durumu 500 (değil 400) gösterir. Neden olduğu hakkında bir fikrin var mı?
Sam

fark hatanın üst işlevidir. İşte uygulamadaki herhangi bir istisna için ThrowResponseException. Ama istisna atan gerçek fonksiyon olmalı ...
Serge

15

Dava 1

  1. Her zaman değil, boru hattında yanıtı değiştirmek için başka yerler de vardır (eylem filtreleri, mesaj işleyicileri).
  2. Yukarıya bakın - ancak eylem bir etki alanı modeli döndürürse , eylemin içindeki yanıtı değiştiremezsiniz .

Vakalar # 2-4

  1. HttpResponseException özel nedenlerini atamak için:
    • bir etki alanı modeli döndürüyorsanız ancak hata durumlarını ele almanız gerekiyorsa,
    • hataları istisna olarak ele alarak denetleyici mantığınızı basitleştirmek için
  2. Bunlar eşdeğer olmalıdır; HttpResponseException, HTTP yanıtı olarak geri döndürülen bir HttpResponseMessage içerir.

    örneğin, durum # 2 şöyle yazılabilir

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

    ... ancak denetleyici mantığınız daha karmaşıksa, bir istisna atmak kod akışını basitleştirebilir.

  3. HttpError size yanıt gövdesi için tutarlı bir biçim verir ve JSON / XML / etc'ye serileştirilebilir, ancak zorunlu değildir. örneğin, yanıta bir varlık gövdesi eklemek istemeyebilirsiniz veya başka bir biçim isteyebilirsiniz.


Aldığım yaklaşım sadece api denetleyici eylemlerinden istisnalar atmak ve istisnayı işleyen ve eylem yürütme bağlamında uygun bir yanıt ayarlayan bir istisna filtresi kaydettirdim. Filtre 'takılabilir', böylece filtreyi genel yapılandırmaya kaydetmeden önce belirli özel durumlar için işleyicileri kaydedebilirim. Bu, denetleyicilere yaymak yerine merkezi özel durum işleme yapmamı sağlıyor.
Muhalif

@Opositional İstisna filtrenizi paylaşmak isteyebilir misiniz? Belki bir Gist olarak veya CodePaste gibi bir kod paylaşım sitesinde?
Paige Cook

@Mike Wasson, "dönüş hatası yanıtı" nın "istisna atma" ya karşı daha yaygın bir yaklaşım olduğunu söyleyebilir misiniz? İşlevsel olarak nihai sonucun aynı olabileceğini anlıyorum, ama neden sadece denemek / yakalamak ve uygun şekilde hata yanıtı döndürmek tüm denetleyici mantığını kapsamıyor merak ediyorum?
zam6ak

15

Bir HttpResponseException atmak veya hatalar için bir HttpResponesMessage iade etmeyin - haricinde niyet etmek ise isteği sona ile bu kesin sonuç .

HttpResponseException özel durumları ile aynı değildir . Onlar edilir İstisna Filtreler yakalanmış değil . Onlar edilir İstisna Handler yakalanmış değil . Geçerli kodun yürütme akışını sonlandırırken bir HttpResponseMessage içinde kaymanın sinsi bir yoludur.

Kod, bu özel işlemden geçirmeye dayanan altyapı kodu değilse , HttpResponseException türünü kullanmaktan kaçının !

HttpResponseMessage istisnaları değildir. Geçerli kodun yürütme akışını sonlandırmazlar. Onlar olabilir değil istisnalar olarak filtrelenmesi. Onlar olabilir değil istisnalar olarak kaydedilebilir. Geçerli bir sonucu temsil ederler - 500 yanıt bile "geçerli bir istisna dışı yanıttır"!


Hayatı basitleştirin:

Ya da (özelleştirilmiş uygulama istisna tipini - istisnai / hata durum olduğunda, devam edin ve normal .NET istisna değil , böyle bir durum kodu olarak 'http hatası / tepki' özelliklerine arzu ile HttpResponseException kaynaklanan) - gereğince , normal istisna elleçleme .

Şu istisnai durumlarda uygun bir şey yapmak için Kural Dışı Durum Filtreleri / Kural Dışı Durum İşleyicileri / Kural Dışı Durum Kaydedicileri'ni kullanın: durum kodlarını değiştirme / ekleme? izleme tanımlayıcıları eklensin mi? yığın izleri içerir mi? log?

HttpResponseException özelliğinden kaçınarak 'istisnai durum' işlemesi tek tip hale getirilir ve açıkta kalan boru hattının bir parçası olarak ele alınabilir! Örneğin, bir 'NotFound' değeri 404'e ve 'ArgumentException' değeri 400'e ve 'NullReference' değerine, uygulama düzeyi istisnaları ile kolay ve tekdüze bir şekilde 500'e dönüştürülebilir; bu da genişletilebilirliğin hata günlüğü gibi "temel bilgiler" sağlamasına olanak tanır.


2
ArgumentExceptionBir denetleyicideki neden mantıksal olarak 400 olacağını anlıyorum , ama ArgumentExceptionyığının derinliklerine ne dersiniz ? Bunları 400'e çevirmek doğru olmayacaktır, ancak battaniyenin tüm ArgumentExceptions'yi 400'e dönüştüren bir filtreniz varsa , bundan kaçınmanın tek yolu, kontrolördeki istisnayı yakalamak ve başka bir şeyi yeniden atmaktır. bir filtre veya benzerinde tekdüze istisna işleme amacını ortadan kaldırmak.
cmeeren

@cmeeren Ben ilgileniyordu kodunda, çoğu istisna yakaladı ve her web yönteminde HttpResponse [İstisna / Mesaj] dönüştü. Her iki durum da aynıdır , çünkü eğer endişe, yakalanan dahili istisna ile "bir şey" yaparak yapılan dahili istisnalar ile farklı bir şey yapmaksa: Sonuçta, hala daha fazla ele alınan uygun bir sarma istisnası atmaktır. yığını.
user2864740

@cmeeren Güncellemelerden sonra, web giriş noktalarımızın çoğu kullanım hatalarına özel bir türetilmiş (HttpResponseException olmayan, uygun yanıt kodlarına sahip olan veya bunlarla eşleştirilen) atar. Tek tip işleyici, istisnanın hangi seviyeden geldiğini belirlemek için biraz yığın denetimi yapabilir (icky, ancak biraz dikkatli çalışır) - yani. daha rafine bir işleme sahip olmayan vakaların% 99'unu kapsar - veya yalnızca dahili hatalar için 500 ile yanıt verir. HttpResponseException özelliği, yararlı boru hattı işlemeyi atlamasıdır.
user2864740

9

Ne zaman kullanılacağına ilişkin bir diğer vaka HttpResponseExceptionyerine Response.CreateResponse(HttpStatusCode.NotFound)sen eylem filtrelerde işlemleri varsa ve müşteriye bir hata yanıtı iade ederken işlemler geri alınmasını istiyorsanız veya başka bir hata durum kodu vardır.

Kullanmak Response.CreateResponseişlemi geri almaz, oysa bir istisna atmak.


3

Ben bir webapi 2 yönteminde bir HttpResponseMessage döndürmek yerine bir HttpResponseException atarsanız, bir çağrı hemen IIS Express için yapılırsa zaman aşımı veya bir html hatası ile dönecek ki benim deneyim olduğunu belirtmek istiyorum yanıt. Bunu test etmenin en kolay yolu, bir HttpResponseException özel durumu oluşturan bir yönteme $ .ajax çağrısı yapmaktır ve ajax'taki errorCallBack'te başka bir yönteme veya hatta basit bir http sayfasına hemen çağrı yapabilirsiniz. Acil aramanın başarısız olacağını fark edeceksiniz. İkinci çağrıyı bir veya iki saniye geciktirmek için hata çağrısına bir kesme noktası veya bir settimeout () eklerseniz, sunucuya kurtarması için zaman verilir.

Güncelleme:Garip Ajax bağlantısının temel nedeni Zaman Aşımı, bir ajax çağrısı yeterince hızlı yapılırsa aynı tcp bağlantısı kullanılır. Bir HttpResonseMessage döndürerek veya tarayıcı ajax çağrısına döndürülen bir HTTPResponseException özel durumu oluşturarak bir 401 hata eter yetiştiriyordum. Ancak bu çağrı ile MS, Startup.Auth.vb app.UserCookieAuthentication etkinleştirildiği için bir Nesne Bulunamadı Hatası döndürüyordu, bu nedenle yanıtı döndürmeye ve bir yönlendirme eklemeye çalışıyordu, ancak bir Nesne Örneği Değilken hatalı. Bu Hata html idi, ancak sadece ajax çağrısı yeterince hızlı yapılmışsa ve kullanılan aynı tcp bağlantısı tarayıcıya geri döndüğünde ve bir sonraki çağrının önüne eklendikten sonra yanıta eklenmiştir. Nedense Chrome zaman aşımına uğradı, Fiddler, json ve htm'nin karışımından dolayı sıkıştı, ancak firefox gerçek hatayı bozdu. Bu yüzden bunu takip etmenin tek yolu garip ama paket dinleyicisi veya firefox oldu.

Ayrıca, otomatik yardım oluşturmak için Web API yardımı kullanıyorsanız ve HttpResponseMessage'ı döndürdüğünüzde,

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

yönteme atfedilir böylece yardım doğru şekilde oluşturulur. Sonra

return Request.CreateResponse<CustomReturnedType>(objCustomeReturnedType) 

ya da hata durumunda

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

Umarım bu, bir HttpResponseException durumu oluşturulduktan hemen sonra rasgele zaman aşımı veya sunucu kullanılamayabilecek başka birine yardımcı olur.

Ayrıca, bir HttpResponseException döndürmenin, AuthToken'in tek sayfalık bir uygulamada yenilenmesi gerektiğinde, Visual Studio'nun İşlenmeyen bir özel durumun yararlı olmasına neden olmamasına ek bir yararı vardır.

Güncelleme: IIS Express zamanlaması ile ilgili ifademi geri çekiyorum, bu istemci tarafımdaki ajax geri çağrısında bir hata oldu, Ajax 1.8'in $ .ajax () ve $ .ajax. (). her ikisi de geri dönüş sözü verir, ancak aynı zincirleme sözü yerine getirmez () yürütme sırasının yanlış olmasına neden olan yeni bir söz döndürür. Yani then () sözü tamamlandığında bir komut dosyası zaman aşımı oldu. Garip gotcha ama IIS express sorunu değil Klavye ve sandalye arasında bir sorun.


0

Anlayabildiğim kadarıyla, bir istisna atıp atmadığınız veya Request.CreateErrorResponse döndürürseniz sonuç aynıdır. System.Web.Http.dll için kaynak koduna bakarsanız, o kadar çok göreceksiniz. Bu genel özete ve yaptığım çok benzer bir çözüme göz atın: Web Api, HttpError ve istisnaların davranışı


0

Hata durumlarında, mutlu yol nesnesi yerine istemcinin istediği formatta belirli bir hata ayrıntıları sınıfı döndürmek istedim.

Denetleyici yöntemlerimin etki alanına özgü mutlu yol nesnesini döndürmesini ve başka bir istisna atmasını istiyorum.

Sahip olduğum sorun, HttpResponseException yapıcılarının etki alanı nesnelerine izin vermemesiydi.

Eninde sonunda bunu buldum

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

Resulthata ProviderCollectionyollarını içeren bir sınıf , benim mutlu yol sonucum.


0

Muhalif cevabı severim

Her neyse, miras alınan İstisnayı yakalamak için bir yola ihtiyacım vardı ve bu çözüm tüm ihtiyaçlarımı karşılamıyor.

Bu yüzden OnException'ı nasıl işlediğini değiştirdim ve bu benim versiyonum

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

Çekirdek, istisna türünün kayıtlı türde bir alt sınıf olup olmadığını kontrol ettiğim bu döngüdür.

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

my2cents

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.