我试图弄清楚如何以标准方式返回我的数据。我的意思是,当我返回json或xml时,对所有内容(成功和错误)使用一种格式会很好。

说我有以下json结果。

{
  "person": {
    "id": 12345,
    "firstName": "John",
    "lastName": "Doe",
    "phones": {
      "home": "800-123-4567",
      "work": "888-555-0000",
      "cell": "877-123-1234"
    },
    "email": [
      "jd@example.com",
      "jd@example.org"
    ],
    "dateOfBirth": "1980-01-02T00:00:00.000Z",
    "registered": true,
    "emergencyContacts": [
      {
        "name": "",
        "phone": "",
        "email": "",
        "relationship": "spouse|parent|child|other"
      }
    ]
  }
}


一切都很好,但是现在如果出现验证错误,该怎么办

我可以使用内置方法CreateErrorResponse

{
  "Message": "The request is invalid.",
  "ModelState": {
    "item": [
      "Required property 'Name' not found in JSON. Path '', line 1, position 14."
    ],
    "item.Name": [
      "The Name field is required."
    ],
    "item.Price": [
      "The field Price must be between 0 and 999."
    ]
  }
}


*是的,我知道数据没有意义并且是不同的,但是数据无关紧要,只是结构。

现在,如果我有一个错误,并且在这种情况下,它有一个自定义的错误代码,该怎么办。

我可以返回这样的东西(使用HttpError)

{
  "Message": "My custom error message",
  "CustomErrorCode": 37
}


现在您可以看到我返回了3种不同格式的json。现在在客户端上,我必须这样做


检查HttpStatusCode

如果为200,则在这种情况下使用Person格式解析json。
如果为400,则可能是验证错误或服务器错误。
如果发现客户错误,则使用该格式,否则使用modlestate。



我一直在与foursquare一起工作,似乎他们总是将相同的格式返回给用户,但是我不知道如何在执行该操作时获得相同的结果。

  {
          "meta": {
            "code": 200,
             ...errorType and errorDetail...
          },
          "notifications": {
             ...notifications...
          },
          "response": {
             ...results...
          }
        }


我想做类似的事情

可以的请求。

{
    "meta": {
        "code": 200,
         "ModelState": {}
    },
    "response": {
        "person": {
            "id": 12345,
            "firstName": "John",
            "lastName": "Doe",
            "phones": {
                "home": "800-123-4567",
                "work": "888-555-0000",
                "cell": "877-123-1234"
            },
            "email": [
                "jd@example.com",
                "jd@example.org"
            ],
            "dateOfBirth": "1980-01-02T00:00:00.000Z",
            "registered": true,
            "emergencyContacts": [
                {
                    "name": "",
                    "phone": "",
                    "email": "",
                    "relationship": "spouse|parent|child|other"
                }
            ]
        }
    }
}


服务器错误看起来像这样

{
    "meta": {
        "code": 500,
        "message": "this is a server error",
        "ModelState": {}
    },
    "response": {}
}


验证看起来像这样

{
    "meta": {
        "code": 400,
        "message": "validation errors",
        "Message": "The request is invalid.",
        "ModelState": {
            "item": [
                "Required property 'Name' not found in JSON. Path '', line 1, position 14."
            ],
            "item.Name": [
                "The Name field is required."
            ],
            "item.Price": [
                "The field Price must be between 0 and 999."
            ]
        }
    },
    "response": {}
}


但是就像我说的那样,我不确定该怎么做,而不是100%地确定这仍然是最好的方法。至少应该是一种格式呢?

编辑
@埃里克·飞利浦

当我只做asp.net mvc项目时,我会做这样的事情。

public readonly IValidation validation;

public PersonService(IValidation validation)
{
    this.validation = validation;
}

public Person GetPerson(int id)
{

    try
    {
       return FindPerson(id);
    }
    catch(Exception ex)
    {
        //log real error with elmah
        validation.addError("internal", "Something went wrong");
    }
}


public class PersonController
{
     public readonly IPersonService personService;
     public PersonController(IPersonService personService)
     {
       this.personService = personService;
     }

    public ActionResult GetPerson(int id)
    {
        personService.GetPerson(id);

        if(personService.Validation.IsValid)
        {
          // do something
        }
        else
        {
          // do something else
        }

        return View();
    }
}


我喜欢您的设置方式,但我希望保持这种方式。我认为我不能使用界面,但是我在想这样的事情

public PersonService()
{

}

public ResponseResult<Person> GetPerson(int id)
{
    var result = ResponseResult<Person>();
    try
    {
       return FindPerson(id);
    }
    catch(Exception ex)
    {
       result.Errorcode = 200;
       result.Msg = "Failed";
    }
}


public class PersonController
{
     public readonly IPersonService personService;
     public PersonController(IPersonService personService)
     {
       this.personService = personService;
     }

    public HttpResponseMessage GetPerson(int id)
    {
       var result = personService.GetPerson(id);
       if(result.isValid)
       {
          Request.CreateResponse<ResponseResult<Person>>(HttpStatusCode.OK, result);
       }

         Request.CreateResponse<ResponseResult<Person>>(HttpStatusCode.BadRequest, result);
    }
}

最佳答案

这是一个很大的问题,因为它是发送数据的设计,它包含多个部分,但是我相信这是一个相当简单,小巧而优雅的解决方案。

这并不是我所使用的,但这是一个很好的例子:

首先,让我们建立一个模型,该模型表示所有响应所需要的模型,或者在不需要结果数据时可以使用的模型:

public class ResponseResult
{
    public ResponseResult()
    {
    }

    public ResponseResult(ModelStateDictionary modelState)
    {
        this.ModelState = new ModelStateResult (modelState);
    }

    // Is this request valid, in the context of the actual request
    public bool IsValid { get; set; }
    // Serialized Model state if needed
    public ModelStateResult ModelState { get; set; }
}


接下来,可能会有大量不同类型的结果要返回,这里泛型派上了用场:

public class ResponseResult<T> : ResponseResult
{
    public ResponseResult() : base()
    {
    }

    public ResponseResult(ModelStateDictionary modelState)
        : base(modelState)
    {
    }

    public ResponseResult(T Data, ModelStateDictionary modelState)
        : base (modelState)
    {
        this.Data = Data;
    }

    public T Data { get; set; }
}


因此,现在如果您需要返回Person,则可以返回:

var result = ResponseResult<Person>();

result.Data = person;

//serialize result and send to client.


我的API可以被Javascript使用,因此我更改了Http Status代码,并提供了有关如何使用jQuery重定向和使用数据的示例。

request = $.ajax({
  type: "POST",
  url: url,
  data: data,
  success: function(data, textStatus, jqXHR)
  {
    processResponseResult(data);
  }
  complete: function(e, xhr, settings)
  {
    if(e.status === 401)
    {
      // login to
    }
    // else if (e.status == )
    else
    {
      // unknown status code
    }
)};


您可能希望扩展结果,以供将来甚至不使用http(WCF)的客户端使用:

public class ResponseResult
{
   ....
   ....
   public int ErrorCode { get; set; }
   public string ErrorMessage { get; set; }
}


或进一步:

public class ResponseErrorBase
{
   public int ErrorCode { get; set; }
   public string ErrorMessage { get; set; }
}

public class ResponseResult
{
   ....
   ....
   public ResponseErrorBase Error { get; set; }
}


因此您将来可以添加更多错误类型/信息。

每条评论更新

评论1:如果您有一群人,那么您就有..

List<Person> persons = new List<Person>();
var result = new ResponseResult<List<Person>>();
result.Data = persons;


评论2:共有2个课程。

如果您的API调用了FileExists(fileName),那么您实际上不必返回对象,只需调用成功即可。

var result = new ResponseResult();
result.IsValid = FileExists(fileName);


如果您的API要返回新的Person的ID,则可以返回新的ID。

var result = new ResponseResult<Guid?>();
result.IsValid = CreatePerson(personInfo);
if (result.IsValid)
{
  result.Data = personInfo.ID;
}


或者您可以返回一个成功的Person对象,如果不成功,则返回null。

var result = new ResponseResult<Person>();
result.IsValid = CreatePerson(personInfo);
if (result.IsValid)
{
  result.Data = Person;
}


每条评论更新

我推荐的是我之前写的内容,并在ResponseResult中包含ResponseErrorBase

public class ResponseResult
{
  public ResponseResult()
  {
  }

  public ResponseResult(ModelStateDictionary modelState)
  {
    this.ModelState = new ModelStateResult (modelState);
  }

  public bool IsValid { get; set; }
  public ModelStateResult ModelState { get; set; }
  public ResponseErrorBase Error { get; set; }
}


然后将您的错误从基础导出到特定的内容:

// this isn't abstract because you may want to just return
// non-specific error messages
public class ResponseErrorBase
{
  public int Code { get; set; }
  public string Message { get; set; }
}

public class InternalResponseError : ResponseErrorBase
{
  // A Property that is specific to this error but
  // not for all Errors
  public int InternalErrorLogID { get; set; }
}


然后返回它(返回值的示例,您将需要更多逻辑):

var result = new ResponseResult<Person>();

try
{
  result.Data = db.FindPerson(id);
}
catch (SqlException ex)
{
  var error = ResponseErrorBase();
  error.Code = 415;
  error.Message = "Sql Exception";
}
catch (Exception ex)
{
  var error = InternalResponseError();
  error.InternalErrorLogID  = Log.WriteException(ex);
  error.Code = 500;
  error.Message = "Internal Error";
}

// MVC might look like:
return this.Json(result);

关于c# - 如何以标准方式返回数据?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16115049/

10-10 22:02
查看更多