我试图按照建议将错误返回给控制器 This link以便客户可以采取适当的行动。 控制器由javascript通过jquery AJAX调用。只有在我没有将状态设置为错误时才会返回Json对象。 这是示例代码
if (response.errors.Length > 0)
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(response);
如果我没有设置状态代码,我会得到Json。 如果我设置状态代码,我会返回状态代码,但不会返回Json错误对象。
更新 我想将一个Error对象作为JSON发送,以便可以处理ajax的错误回调。
答案 0 :(得分:32)
我找到了解决方案here
我必须创建一个动作过滤器来覆盖MVC的默认行为
这是我的异常类
class ValidationException : ApplicationException
{
public JsonResult exceptionDetails;
public ValidationException(JsonResult exceptionDetails)
{
this.exceptionDetails = exceptionDetails;
}
public ValidationException(string message) : base(message) { }
public ValidationException(string message, Exception inner) : base(message, inner) { }
protected ValidationException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}
请注意,我有构造函数来初始化我的JSON。这是动作过滤器
public class HandleUIExceptionAttribute : FilterAttribute, IExceptionFilter
{
public virtual void OnException(ExceptionContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (filterContext.Exception != null)
{
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
filterContext.Result = ((ValidationException)filterContext.Exception).myJsonError;
}
}
现在我有了动作过滤器,我将使用过滤器属性
来装饰我的控制器[HandleUIException]
public JsonResult UpdateName(string objectToUpdate)
{
var response = myClient.ValidateObject(objectToUpdate);
if (response.errors.Length > 0)
throw new ValidationException(Json(response));
}
当抛出错误时,调用实现IExceptionFilter的动作过滤器,并在错误回调时返回客户端上的Json。
答案 1 :(得分:22)
我发现的最新解决方案是创建自己的JsonResult,扩展原始实现并允许您指定HttpStatusCode:
public class JsonHttpStatusResult : JsonResult
{
private readonly HttpStatusCode _httpStatus;
public JsonHttpStatusResult(object data, HttpStatusCode httpStatus)
{
Data = data;
_httpStatus = httpStatus;
}
public override void ExecuteResult(ControllerContext context)
{
context.RequestContext.HttpContext.Response.StatusCode = (int)_httpStatus;
base.ExecuteResult(context);
}
}
然后您可以在控制器操作中使用它,如下所示:
if(thereWereErrors)
{
var errorModel = new { error = "There was an error" };
return new JsonHttpStatusResult(errorModel, HttpStatusCode.InternalServerError);
}
答案 2 :(得分:20)
这个问题有一个非常优雅的解决方案,只需通过web.config配置您的网站:
<system.webServer>
<httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough"/>
</system.webServer>
答案 3 :(得分:5)
根据Richard Garside的回答,这里是ASP.Net核心版
public class JsonErrorResult : JsonResult
{
private readonly HttpStatusCode _statusCode;
public JsonErrorResult(object json) : this(json, HttpStatusCode.InternalServerError)
{
}
public JsonErrorResult(object json, HttpStatusCode statusCode) : base(json)
{
_statusCode = statusCode;
}
public override void ExecuteResult(ActionContext context)
{
context.HttpContext.Response.StatusCode = (int)_statusCode;
base.ExecuteResult(context);
}
public override Task ExecuteResultAsync(ActionContext context)
{
context.HttpContext.Response.StatusCode = (int)_statusCode;
return base.ExecuteResultAsync(context);
}
}
然后在您的控制器中,返回如下:
// Set a json object to return. The status code defaults to 500
return new JsonErrorResult(new { message = "Sorry, an internal error occurred."});
// Or you can override the status code
return new JsonErrorResult(new { foo = "bar"}, HttpStatusCode.NotFound);
答案 4 :(得分:4)
设置StatusCode后,您必须自己返回JSON错误对象,如此...
if (BadRequest)
{
Dictionary<string, object> error = new Dictionary<string, object>();
error.Add("ErrorCode", -1);
error.Add("ErrorMessage", "Something really bad happened");
return Json(error);
}
另一种方法是拥有JsonErrorModel
并填充它
public class JsonErrorModel
{
public int ErrorCode { get; set;}
public string ErrorMessage { get; set; }
}
public ActionResult SomeMethod()
{
if (BadRequest)
{
var error = new JsonErrorModel
{
ErrorCode = -1,
ErrorMessage = "Something really bad happened"
};
return Json(error);
}
//Return valid response
}
同时查看答案here
答案 5 :(得分:4)
您需要决定是否需要“HTTP级别错误”(错误代码的用途)或“应用程序级别错误”(您的自定义JSON响应的用途)。
如果错误代码设置为非2xx(成功范围),则使用HTTP的大多数高级对象都不会查看响应流。在您的情况下,您明确将错误代码设置为失败(我认为403或500)并强制XMLHttp对象忽略响应的主体。
要修复 - 要么在客户端处理错误条件,要么不设置错误代码并返回带有错误信息的JSON(有关详细信息,请参阅Sbossb回复)。
答案 6 :(得分:3)
如果你的需求没有Sarath那么复杂,你可以用更简单的东西逃脱:
[MyError]
public JsonResult Error(string objectToUpdate)
{
throw new Exception("ERROR!");
}
public class MyErrorAttribute : FilterAttribute, IExceptionFilter
{
public virtual void OnException(ExceptionContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (filterContext.Exception != null)
{
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
filterContext.Result = new JsonResult() { Data = filterContext.Exception.Message };
}
}
}
答案 7 :(得分:3)
对我有用的东西(以及我从another stackoverflow response获得的东西)是设置标志:
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/menuNightMode" android:title="@string/MainPageMenuNight" />
</menu>
答案 8 :(得分:1)
几个响应依赖于抛出的异常并在OnException重写中对其进行处理。就我而言,如果用户传递了错误的ID,我想返回诸如错误请求之类的状态。对我有用的是使用ControllerContext:
var jsonResult = new JsonResult { JsonRequestBehavior = JsonRequestBehavior.AllowGet, Data = "whoops" };
ControllerContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
return jsonResult;
答案 9 :(得分:0)
一种向Json发送错误的简单方法是控制响应对象的Http状态代码并设置自定义错误消息。
控制器
public JsonResult Create(MyObject myObject)
{
//AllFine
return Json(new { IsCreated = True, Content = ViewGenerator(myObject));
//Use input may be wrong but nothing crashed
return Json(new { IsCreated = False, Content = ViewGenerator(myObject));
//Error
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return Json(new { IsCreated = false, ErrorMessage = 'My error message');
}
JS
$.ajax({
type: "POST",
dataType: "json",
url: "MyController/Create",
data: JSON.stringify(myObject),
success: function (result) {
if(result.IsCreated)
{
//... ALL FINE
}
else
{
//... Use input may be wrong but nothing crashed
}
},
error: function (error) {
alert("Error:" + erro.responseJSON.ErrorMessage ); //Error
}
});
答案 10 :(得分:0)
我正在运行Asp.Net Web Api 5.2.7,看来JsonResult类已更改为使用泛型和异步执行方法。我最终改变了Richard Garside's solution:
public class JsonHttpStatusResult<T> : JsonResult<T>
{
private readonly HttpStatusCode _httpStatus;
public JsonHttpStatusResult(T content, JsonSerializerSettings serializer, Encoding encoding, ApiController controller, HttpStatusCode httpStatus)
: base(content, serializer, encoding, controller)
{
_httpStatus = httpStatus;
}
public override Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var returnTask = base.ExecuteAsync(cancellationToken);
returnTask.Result.StatusCode = HttpStatusCode.BadRequest;
return returnTask;
}
}
按照Richard的示例,您可以像下面这样使用此类:
if(thereWereErrors)
{
var errorModel = new CustomErrorModel("There was an error");
return new JsonHttpStatusResult<CustomErrorModel>(errorModel, new JsonSerializerSettings(), new UTF8Encoding(), this, HttpStatusCode.InternalServerError);
}
不幸的是,您不能对内容使用匿名类型,因为您需要将具体类型(例如:CustomErrorType
)传递给JsonHttpStatusResult
初始化程序。如果您想使用匿名类型,或者只是想变得很聪明,可以通过子类化ApiController
来为HttpStatusCode
方法添加Json
参数来建立此解决方案:)< / p>
public abstract class MyApiController : ApiController
{
protected internal virtual JsonHttpStatusResult<T> Json<T>(T content, HttpStatusCode httpStatus, JsonSerializerSettings serializerSettings, Encoding encoding)
{
return new JsonHttpStatusResult<T>(content, httpStatus, serializerSettings, encoding, this);
}
protected internal JsonHttpStatusResult<T> Json<T>(T content, HttpStatusCode httpStatus, JsonSerializerSettings serializerSettings)
{
return Json(content, httpStatus, serializerSettings, new UTF8Encoding());
}
protected internal JsonHttpStatusResult<T> Json<T>(T content, HttpStatusCode httpStatus)
{
return Json(content, httpStatus, new JsonSerializerSettings());
}
}
然后,您可以将其与这样的匿名类型一起使用:
if(thereWereErrors)
{
var errorModel = new { error = "There was an error" };
return Json(errorModel, HttpStatusCode.InternalServerError);
}