วิธีปฏิบัติที่ดีที่สุดในการส่งคืนข้อผิดพลาดใน ASP.NET Web API


384

ฉันมีความกังวลเกี่ยวกับวิธีที่เราส่งคืนข้อผิดพลาดไปยังลูกค้า

เราจะส่งคืนข้อผิดพลาดทันทีโดยการขว้างHttpResponseExceptionเมื่อเราพบข้อผิดพลาด

public void Post(Customer customer)
{
    if (string.IsNullOrEmpty(customer.Name))
    {
        throw new HttpResponseException("Customer Name cannot be empty", HttpStatusCode.BadRequest) 
    }
    if (customer.Accounts.Count == 0)
    {
         throw new HttpResponseException("Customer does not have any account", HttpStatusCode.BadRequest) 
    }
}

หรือเราสะสมข้อผิดพลาดทั้งหมดจากนั้นส่งกลับไปที่ลูกค้า:

public void Post(Customer customer)
{
    List<string> errors = new List<string>();
    if (string.IsNullOrEmpty(customer.Name))
    {
        errors.Add("Customer Name cannot be empty"); 
    }
    if (customer.Accounts.Count == 0)
    {
         errors.Add("Customer does not have any account"); 
    }
    var responseMessage = new HttpResponseMessage<List<string>>(errors, HttpStatusCode.BadRequest);
    throw new HttpResponseException(responseMessage);
}

นี่เป็นเพียงโค้ดตัวอย่างมันไม่สำคัญว่าจะเกิดข้อผิดพลาดในการตรวจสอบหรือเซิร์ฟเวอร์เกิดข้อผิดพลาดฉันแค่อยากจะรู้วิธีปฏิบัติที่ดีที่สุดข้อดีและข้อเสียของแต่ละวิธี


1
ดูstackoverflow.com/a/22163675/200442ModelStateคุณควรจะใช้
Daniel Little

1
โปรดทราบว่าคำตอบที่นี่ครอบคลุมเฉพาะข้อยกเว้นที่เกิดขึ้นกับคอนโทรลเลอร์เท่านั้น หาก API ของคุณส่งกลับ IQueryable <Model> ที่ยังไม่ได้ดำเนินการข้อยกเว้นจะไม่อยู่ในตัวควบคุมและไม่ถูกจับ ...
Jess

3
เป็นคำถามที่ดีมาก แต่อย่างใดฉันไม่ได้รับตัวสร้างHttpResponseExceptionคลาสที่มากเกินไปซึ่งใช้พารามิเตอร์สองตัวที่กล่าวถึงในโพสต์ของคุณ - HttpResponseException("Customer Name cannot be empty", HttpStatusCode.BadRequest) นั่นคือHttpResponseException(string, HttpStatusCode)
RBT

คำตอบ:


293

สำหรับฉันฉันมักจะส่งกลับHttpResponseExceptionและตั้งรหัสสถานะขึ้นอยู่กับข้อยกเว้นที่ส่งออกมาและหากข้อยกเว้นร้ายแรงหรือไม่จะตัดสินว่าฉันส่งกลับHttpResponseExceptionทันทีหรือไม่

ในตอนท้ายของวันเป็น API ที่ส่งการตอบกลับไม่ใช่มุมมองดังนั้นฉันคิดว่าการส่งข้อความกลับพร้อมข้อยกเว้นและรหัสสถานะให้กับผู้บริโภคเป็นเรื่องดี ขณะนี้ฉันไม่ต้องการสะสมข้อผิดพลาดและส่งกลับเนื่องจากข้อยกเว้นส่วนใหญ่มักเกิดจากพารามิเตอร์ที่ไม่ถูกต้องหรือการโทร ฯลฯ

ตัวอย่างในแอพของฉันคือบางครั้งไคลเอนต์จะขอข้อมูล แต่ไม่มีข้อมูลใด ๆ ดังนั้นฉันจึงโยนแบบกำหนดเองNoDataAvailableExceptionและปล่อยให้มันส่งไปที่แอพ Web API ซึ่งในตัวกรองที่กำหนดเองของฉันซึ่งจับมันส่งกลับ ข้อความที่เกี่ยวข้องพร้อมกับรหัสสถานะที่ถูกต้อง

ฉันไม่แน่ใจ 100% ว่าอะไรคือวิธีปฏิบัติที่ดีที่สุดสำหรับสิ่งนี้ แต่ตอนนี้ใช้ได้กับฉันแล้วนั่นคือสิ่งที่ฉันกำลังทำอยู่

อัปเดต :

เมื่อฉันตอบคำถามนี้มีการเขียนบล็อกโพสต์ในหัวข้อ:

https://weblogs.asp.net/fredriknormen/asp-net-web-api-exception-handling

(อันนี้มีคุณสมบัติใหม่บางอย่างในงานสร้างยามค่ำคืน) https://docs.microsoft.com/archive/blogs/youssefm/error-handling-in-asp-net-webapi

อัปเดต 2

อัปเดตเป็นกระบวนการจัดการข้อผิดพลาดของเราเรามีสองกรณี:

  1. สำหรับข้อผิดพลาดทั่วไปเช่นไม่พบหรือพารามิเตอร์ที่ไม่ถูกต้องถูกส่งผ่านไปยังการดำเนินการเรากลับHttpResponseExceptionเพื่อหยุดการประมวลผลทันที นอกจากนี้สำหรับข้อผิดพลาดในการดำเนินการรูปแบบของเราที่เราจะมอบพจนานุกรมรัฐรูปแบบที่จะขยายและห่อไว้ในRequest.CreateErrorResponse HttpResponseExceptionการเพิ่มผลลัพธ์พจนานุกรมสถานะรุ่นในรายการข้อผิดพลาดของโมเดลที่ส่งไปยังเนื้อหาตอบกลับ

  2. สำหรับข้อผิดพลาดที่เกิดขึ้นในเลเยอร์ที่สูงกว่าข้อผิดพลาดของเซิร์ฟเวอร์เราให้บับเบิ้ลข้อยกเว้นไปยังแอป Web API ที่นี่เรามีตัวกรองข้อยกเว้นส่วนกลางซึ่งดูที่ข้อยกเว้นบันทึกด้วย ELMAH และพยายามตั้งค่า HTTP ที่ถูกต้อง HttpResponseExceptionรหัสสถานะและข้อผิดพลาดที่เกี่ยวข้องเป็นมิตรร่างกายอีกครั้งใน สำหรับข้อยกเว้นที่เราไม่คาดว่าลูกค้าจะได้รับข้อผิดพลาดเซิร์ฟเวอร์ภายใน 500 ค่าเริ่มต้น แต่เป็นข้อความทั่วไปเนื่องจากเหตุผลด้านความปลอดภัย

อัปเดต 3

เมื่อเร็ว ๆ นี้หลังจากรับ Web API 2 เพื่อส่งกลับข้อผิดพลาดทั่วไปตอนนี้เราใช้ส่วนต่อประสานIHttpActionResultโดยเฉพาะคลาสที่มีอยู่แล้วในSystem.Web.Http.Resultsเนมสเปซเช่น NotFound, BadRequest เมื่อมันพอดีถ้าพวกมันไม่ขยาย ผลลัพธ์ NotFound พร้อมข้อความตอบกลับ:

public class NotFoundWithMessageResult : IHttpActionResult
{
    private string message;

    public NotFoundWithMessageResult(string message)
    {
        this.message = message;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(HttpStatusCode.NotFound);
        response.Content = new StringContent(message);
        return Task.FromResult(response);
    }
}

ขอบคุณสำหรับคำตอบของคุณ geepie มันเป็นประสบการณ์ที่ดีดังนั้นคุณต้องการส่ง expcetion ทันทีหรือไม่
cuongle

อย่างที่ฉันบอกว่ามันขึ้นอยู่กับข้อยกเว้นจริงๆ ข้อยกเว้นที่ร้ายแรงเช่นผู้ใช้ส่งพารามิเตอร์ที่ไม่ถูกต้องไปยังจุดสิ้นสุดของ Web Api จากนั้นฉันจะสร้าง HttpResponseException และส่งกลับไปยังแอพที่ใช้งาน
gdp

ยกเว้นในคำถามที่เป็นจริงมากขึ้นเกี่ยวกับการตรวจสอบดูstackoverflow.com/a/22163675/200442
Daniel Little

1
@DanielLittle อ่านคำถามของเขาอีกครั้ง ฉันพูด: "นี่เป็นเพียงตัวอย่างโค้ดมันไม่สำคัญว่าจะเกิดข้อผิดพลาดในการตรวจสอบหรือข้อผิดพลาดเซิร์ฟเวอร์"
gdp

@gdp ดังนั้นถึงแม้จะมีสององค์ประกอบจริง ๆ การตรวจสอบและการยกเว้นดังนั้นจึงเป็นการดีที่สุดที่จะครอบคลุมทั้งสองอย่าง
Daniel Little

184

ASP.NET Web API 2 ทำให้มันง่ายขึ้นจริงๆ ตัวอย่างเช่นรหัสต่อไปนี้:

public HttpResponseMessage GetProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        var message = string.Format("Product with id = {0} not found", id);
        HttpError err = new HttpError(message);
        return Request.CreateResponse(HttpStatusCode.NotFound, err);
    }
    else
    {
        return Request.CreateResponse(HttpStatusCode.OK, item);
    }
}

ส่งคืนเนื้อหาต่อไปนี้ไปยังเบราว์เซอร์เมื่อไม่พบรายการ:

HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
Date: Thu, 09 Aug 2012 23:27:18 GMT
Content-Length: 51

{
  "Message": "Product with id = 12 not found"
}

คำแนะนำ: อย่าโยน HTTP Error 500 เว้นแต่ว่ามีข้อผิดพลาดรุนแรง (ตัวอย่างเช่น WCF Fault Exception) เลือกรหัสสถานะ HTTP ที่เหมาะสมซึ่งแสดงถึงสถานะของข้อมูลของคุณ (ดูลิงค์ apigee ด้านล่าง)

ลิงค์:


4
ฉันจะไปอีกขั้นหนึ่งแล้วโยน ResourceNotFoundException จาก DAL / Repo ที่ฉันตรวจสอบใน Web Api 2.2 ExceptionHandler สำหรับ Type ResourceNotFoundException แล้วฉันจะส่งคืน "Product with id xxx not found" วิธีนี้จะยึดโดยทั่วไปในสถาปัตยกรรมแทนแต่ละการกระทำ
ปาสกาล

1
มีการใช้งานเฉพาะสำหรับความreturn Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState); แตกต่างระหว่างCreateResponseและCreateErrorResponse
Zapnologica

10
ตามที่w3.org/Protocols/rfc2616/rfc2616-sec10.htmlข้อผิดพลาดของไคลเอ็นต์คือรหัส 400 ระดับและข้อผิดพลาดเซิร์ฟเวอร์คือรหัสระดับ 500 ดังนั้นรหัสข้อผิดพลาด 500 อาจเหมาะสมมากในหลายกรณีสำหรับ Web API ไม่ใช่แค่ข้อผิดพลาด "หายนะ"
เจส

2
คุณต้องการusing System.Net.Http;ให้CreateResponse()วิธีการขยายแสดงขึ้น
Adam Szabo

สิ่งที่ฉันไม่ชอบเกี่ยวกับการใช้ Request.CreateResponse () คือการส่งคืนข้อมูลซีเรียลไลเซชันเฉพาะของ Microsoft ที่ไม่จำเป็นเช่น "<string xmlns =" schemas.microsoft.com/2003/10/Serialization/ " >ข้อผิดพลาดของฉันที่นี่ </ string >" สำหรับสถานการณ์ที่เหมาะสมกับสถานะ 400 ฉันพบว่า ApiController.BadRequest (ข้อความสตริง) ส่งคืนสตริง "<Error> <Message> ข้อผิดพลาดของฉันที่นี่ </Message> </Error>" ที่ดีกว่า แต่ฉันไม่พบสิ่งที่เทียบเท่ากับการคืนสถานะ 500 ด้วยข้อความง่ายๆ
vkelman

76

ดูเหมือนว่าคุณกำลังมีปัญหากับการตรวจสอบมากกว่าข้อผิดพลาด / ข้อยกเว้นดังนั้นฉันจะพูดเกี่ยวกับทั้งสองเล็กน้อย

การตรวจสอบ

โดยทั่วไปการกระทำของตัวควบคุมควรใช้รูปแบบการป้อนข้อมูลที่มีการประกาศการตรวจสอบความถูกต้องโดยตรงในรูปแบบ

public class Customer
{ 
    [Require]
    public string Name { get; set; }
}

จากนั้นคุณสามารถใช้ข้อความActionFilterที่ส่งการตรวจสอบความถูกต้องกลับไปยังลูกค้าโดยอัตโนมัติ

public class ValidationActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var modelState = actionContext.ModelState;

        if (!modelState.IsValid) {
            actionContext.Response = actionContext.Request
                 .CreateErrorResponse(HttpStatusCode.BadRequest, modelState);
        }
    }
} 

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการตรวจสอบนี้http://ben.onfabrik.com/posts/automatic-modelstate-validation-in-aspnet-mvc

การจัดการข้อผิดพลาด

เป็นการดีที่สุดที่จะส่งข้อความกลับไปยังลูกค้าที่แสดงถึงข้อยกเว้นที่เกิดขึ้น (พร้อมรหัสสถานะที่เกี่ยวข้อง)

นอกกรอบที่คุณต้องใช้Request.CreateErrorResponse(HttpStatusCode, message)หากคุณต้องการระบุข้อความ อย่างไรก็ตามสิ่งนี้จะผูกโค้ดกับRequestวัตถุซึ่งคุณไม่จำเป็นต้องทำ

ฉันมักจะสร้างข้อยกเว้น "ปลอดภัย" ประเภทของตัวเองที่ฉันคาดหวังว่าลูกค้าจะรู้วิธีจัดการและห่อหุ้มคนอื่น ๆ ทั้งหมดด้วยข้อผิดพลาด 500 ทั่วไป

การใช้ตัวกรองการกระทำเพื่อจัดการข้อยกเว้นจะมีลักษณะเช่นนี้:

public class ApiExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext context)
    {
        var exception = context.Exception as ApiException;
        if (exception != null) {
            context.Response = context.Request.CreateErrorResponse(exception.StatusCode, exception.Message);
        }
    }
}

จากนั้นคุณสามารถลงทะเบียนได้ทั่วโลก

GlobalConfiguration.Configuration.Filters.Add(new ApiExceptionFilterAttribute());

นี่คือประเภทข้อยกเว้นที่กำหนดเองของฉัน

using System;
using System.Net;

namespace WebApi
{
    public class ApiException : Exception
    {
        private readonly HttpStatusCode statusCode;

        public ApiException (HttpStatusCode statusCode, string message, Exception ex)
            : base(message, ex)
        {
            this.statusCode = statusCode;
        }

        public ApiException (HttpStatusCode statusCode, string message)
            : base(message)
        {
            this.statusCode = statusCode;
        }

        public ApiException (HttpStatusCode statusCode)
        {
            this.statusCode = statusCode;
        }

        public HttpStatusCode StatusCode
        {
            get { return this.statusCode; }
        }
    }
}

ตัวอย่างข้อยกเว้นที่ API ของฉันสามารถใช้งานได้

public class NotAuthenticatedException : ApiException
{
    public NotAuthenticatedException()
        : base(HttpStatusCode.Forbidden)
    {
    }
}

ฉันมีปัญหาเกี่ยวกับคำตอบการจัดการข้อผิดพลาดที่คำจำกัดความของคลาส ApiExceptionFilterAttribute ในวิธีการ OnException ข้อยกเว้นสถานะโค้ดไม่ถูกต้องเนื่องจากข้อยกเว้นคือ WebException ในกรณีนี้ฉันควรทำอย่างไร
razp26

1
@ razp26 หากคุณอ้างถึงสิ่งvar exception = context.Exception as WebException;ที่เป็นตัวพิมพ์ผิดมันควรจะเป็นApiException
Daniel Little

2
คุณช่วยเพิ่มตัวอย่างของคลาส ApiExceptionFilterAttribute ได้อย่างไร?
razp26

36

คุณสามารถส่ง HttpResponseException ได้

HttpResponseMessage response = 
    this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "your message");
throw new HttpResponseException(response);

23

สำหรับ Web API 2 วิธีการของฉันคืน IHttpActionResult อย่างสม่ำเสมอดังนั้นฉันจึงใช้ ...

public IHttpActionResult Save(MyEntity entity)
{
  ....

    return ResponseMessage(
        Request.CreateResponse(
            HttpStatusCode.BadRequest, 
            validationErrors));
}

คำตอบนี้ไม่เป็นไรในขณะที่คุณควรเพิ่มการอ้างอิงถึงSystem.Net.Http
Bellash

19

หากคุณใช้ ASP.NET Web API 2 วิธีที่ง่ายที่สุดคือการใช้ ApiController Short-Method สิ่งนี้จะทำให้ BadRequestResult

return BadRequest("message");

อย่างเคร่งครัดสำหรับข้อผิดพลาดในการตรวจสอบความถูกต้องของโมเดลฉันใช้โอเวอร์โหลดของ BadRequest () ที่ยอมรับวัตถุ ModelState:return BadRequest(ModelState);
timmi4sa

4

คุณสามารถใช้ ActionFilter ที่กำหนดเองใน Web Api เพื่อตรวจสอบรูปแบบ

public class DRFValidationFilters : ActionFilterAttribute
{

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (!actionContext.ModelState.IsValid)
        {
            actionContext.Response = actionContext.Request
                 .CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);

            //BadRequest(actionContext.ModelState);
        }
    }
    public override Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {

        return Task.Factory.StartNew(() => {

            if (!actionContext.ModelState.IsValid)
            {
                actionContext.Response = actionContext.Request
                     .CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);                    
            }
        });

    }

public class AspirantModel
{
    public int AspirantId { get; set; }
    public string FirstName { get; set; }
    public string MiddleName { get; set; }        
    public string LastName { get; set; }
    public string AspirantType { get; set; }       
    [RegularExpression(@"^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$", ErrorMessage = "Not a valid Phone number")]
    public string MobileNumber { get; set; }
    public int StateId { get; set; }
    public int CityId { get; set; }
    public int CenterId { get; set; }

}

    [HttpPost]
    [Route("AspirantCreate")]
    [DRFValidationFilters]
    public IHttpActionResult Create(AspirantModel aspirant)
    {
            if (aspirant != null)
            {

            }
            else
            {
                return Conflict();
            }
          return Ok();

}

ลงทะเบียนคลาส CustomAttribute ใน webApiConfig.cs config.Filters.Add (DRFValidationFilters ใหม่ ());


4

สร้างManish Jainคำตอบของ (ซึ่งมีไว้สำหรับ Web API 2 ซึ่งทำให้สิ่งต่าง ๆ ง่ายขึ้น):

1) ใช้โครงสร้างการตรวจสอบเพื่อตอบสนองข้อผิดพลาดในการตรวจสอบมากที่สุด โครงสร้างเหล่านี้สามารถใช้เพื่อตอบสนองต่อคำขอที่มาจากแบบฟอร์ม

public class FieldError
{
    public String FieldName { get; set; }
    public String FieldMessage { get; set; }
}

// a result will be able to inform API client about some general error/information and details information (related to invalid parameter values etc.)
public class ValidationResult<T>
{
    public bool IsError { get; set; }

    /// <summary>
    /// validation message. It is used as a success message if IsError is false, otherwise it is an error message
    /// </summary>
    public string Message { get; set; } = string.Empty;

    public List<FieldError> FieldErrors { get; set; } = new List<FieldError>();

    public T Payload { get; set; }

    public void AddFieldError(string fieldName, string fieldMessage)
    {
        if (string.IsNullOrWhiteSpace(fieldName))
            throw new ArgumentException("Empty field name");

        if (string.IsNullOrWhiteSpace(fieldMessage))
            throw new ArgumentException("Empty field message");

        // appending error to existing one, if field already contains a message
        var existingFieldError = FieldErrors.FirstOrDefault(e => e.FieldName.Equals(fieldName));
        if (existingFieldError == null)
            FieldErrors.Add(new FieldError {FieldName = fieldName, FieldMessage = fieldMessage});
        else
            existingFieldError.FieldMessage = $"{existingFieldError.FieldMessage}. {fieldMessage}";

        IsError = true;
    }

    public void AddEmptyFieldError(string fieldName, string contextInfo = null)
    {
        AddFieldError(fieldName, $"No value provided for field. Context info: {contextInfo}");
    }
}

public class ValidationResult : ValidationResult<object>
{

}

2) ชั้นบริการจะคืนค่าValidationResults โดยไม่คำนึงถึงการดำเนินการที่ประสบความสำเร็จหรือไม่ เช่น:

    public ValidationResult DoSomeAction(RequestFilters filters)
    {
        var ret = new ValidationResult();

        if (filters.SomeProp1 == null) ret.AddEmptyFieldError(nameof(filters.SomeProp1));
        if (filters.SomeOtherProp2 == null) ret.AddFieldError(nameof(filters.SomeOtherProp2 ), $"Failed to parse {filters.SomeOtherProp2} into integer list");

        if (filters.MinProp == null) ret.AddEmptyFieldError(nameof(filters.MinProp));
        if (filters.MaxProp == null) ret.AddEmptyFieldError(nameof(filters.MaxProp));


        // validation affecting multiple input parameters
        if (filters.MinProp > filters.MaxProp)
        {
            ret.AddFieldError(nameof(filters.MinProp, "Min prop cannot be greater than max prop"));
            ret.AddFieldError(nameof(filters.MaxProp, "Check"));
        }

        // also specify a global error message, if we have at least one error
        if (ret.IsError)
        {
            ret.Message = "Failed to perform DoSomeAction";
            return ret;
        }

        ret.Message = "Successfully performed DoSomeAction";
        return ret;
    }

3) API Controllerจะสร้างการตอบสนองตามผลการทำงานของบริการ

ทางเลือกหนึ่งคือการทำให้พารามิเตอร์เกือบทั้งหมดเป็นตัวเลือกและทำการตรวจสอบความถูกต้องที่กำหนดเองซึ่งส่งกลับการตอบสนองที่มีความหมายมากขึ้น นอกจากนี้ฉันกำลังดูแลที่จะไม่อนุญาตให้มีข้อยกเว้นใด ๆ นอกเหนือไปจากขอบเขตการให้บริการ

    [Route("DoSomeAction")]
    [HttpPost]
    public HttpResponseMessage DoSomeAction(int? someProp1 = null, string someOtherProp2 = null, int? minProp = null, int? maxProp = null)
    {
        try
        {
            var filters = new RequestFilters 
            {
                SomeProp1 = someProp1 ,
                SomeOtherProp2 = someOtherProp2.TrySplitIntegerList() ,
                MinProp = minProp, 
                MaxProp = maxProp
            };

            var result = theService.DoSomeAction(filters);
            return !result.IsError ? Request.CreateResponse(HttpStatusCode.OK, result) : Request.CreateResponse(HttpStatusCode.BadRequest, result);
        }
        catch (Exception exc)
        {
            Logger.Log(LogLevel.Error, exc, "Failed to DoSomeAction");
            return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, new HttpError("Failed to DoSomeAction - internal error"));
        }
    }


0

เพียงแค่อัปเดตสถานะปัจจุบันของ ASP.NET WebAPI ขณะนี้มีการเรียกIActionResultใช้อินเทอร์เฟซและการใช้งานไม่เปลี่ยนแปลงมากนัก:

[JsonObject(IsReference = true)]
public class DuplicateEntityException : IActionResult
{        
    public DuplicateEntityException(object duplicateEntity, object entityId)
    {
        this.EntityType = duplicateEntity.GetType().Name;
        this.EntityId = entityId;
    }

    /// <summary>
    ///     Id of the duplicate (new) entity
    /// </summary>
    public object EntityId { get; set; }

    /// <summary>
    ///     Type of the duplicate (new) entity
    /// </summary>
    public string EntityType { get; set; }

    public Task ExecuteResultAsync(ActionContext context)
    {
        var message = new StringContent($"{this.EntityType ?? "Entity"} with id {this.EntityId ?? "(no id)"} already exist in the database");

        var response = new HttpResponseMessage(HttpStatusCode.Ambiguous) { Content = message };

        return Task.FromResult(response);
    }

    #endregion
}

สิ่งนี้ดูน่าสนใจ แต่รหัสนี้วางไว้ที่ไหนโดยเฉพาะในโครงการ ฉันกำลังทำโครงการเว็บ api 2 ของฉันใน vb.net
ปิดทอง

มันเป็นแค่แบบจำลองสำหรับการคืนข้อผิดพลาดและสามารถอยู่ได้ทุกที่ คุณจะส่งคืนอินสแตนซ์ใหม่ของคลาสด้านบนในคอนโทรลเลอร์ของคุณ แต่ตามจริงแล้วฉันพยายามใช้คลาสที่มีอยู่ทุกเมื่อที่ทำได้: this.Ok (), CreatedAtRoute (), NotFound () ลายเซ็นของวิธีการคือ IHttpActionResult ไม่ทราบว่าพวกเขาเปลี่ยนแปลงสิ่งเหล่านี้ด้วย NetCore หรือไม่
Thomas Hagström

-2

สำหรับข้อผิดพลาดเหล่านั้นที่ modelstate.isvalid เป็นเท็จฉันมักจะส่งข้อผิดพลาดตามที่มันถูกโยนโดยรหัส มันเข้าใจง่ายสำหรับนักพัฒนาที่ใช้บริการของฉัน ฉันมักจะส่งผลลัพธ์โดยใช้รหัสด้านล่าง

     if(!ModelState.IsValid) {
                List<string> errorlist=new List<string>();
                foreach (var value in ModelState.Values)
                {
                    foreach(var error in value.Errors)
                    errorlist.Add( error.Exception.ToString());
                    //errorlist.Add(value.Errors);
                }
                HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.BadRequest,errorlist);}

สิ่งนี้จะส่งข้อผิดพลาดไปยังไคลเอนต์ในรูปแบบด้านล่างซึ่งเป็นรายการข้อผิดพลาด:

    [  
    "Newtonsoft.Json.JsonReaderException: **Could not convert string to integer: abc. Path 'Country',** line 6, position 16.\r\n   
at Newtonsoft.Json.JsonReader.ReadAsInt32Internal()\r\n   
at Newtonsoft.Json.JsonTextReader.ReadAsInt32()\r\n   
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter, Boolean inArray)\r\n   
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)",

       "Newtonsoft.Json.JsonReaderException: **Could not convert string to integer: ab. Path 'State'**, line 7, position 13.\r\n   
at Newtonsoft.Json.JsonReader.ReadAsInt32Internal()\r\n   
at Newtonsoft.Json.JsonTextReader.ReadAsInt32()\r\n   
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter, Boolean inArray)\r\n   
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)"
    ]

ฉันจะไม่แนะนำให้ส่งรายละเอียดในระดับนี้กลับมายกเว้นว่านี่เป็น API ภายนอก (เช่นเปิดเผยกับอินเทอร์เน็ตสาธารณะ) คุณควรทำงานเพิ่มเติมในตัวกรองและส่งกลับวัตถุ JSON (หรือ XML หากเป็นรูปแบบที่เลือก) ให้รายละเอียดข้อผิดพลาดแทนที่จะเป็นเพียงข้อ ToString
Sudhanshu Mishra

ไม่ถูกต้องไม่ส่งข้อยกเว้นนี้สำหรับ API ภายนอก แต่คุณสามารถใช้เพื่อแก้ไขข้อบกพร่องใน API ภายในและระหว่างการทดสอบ
Ashish Sahu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.