我有一个MVC 4 WebAPI应用程序。我想要做的是过滤掉由于在发送/过帐期间发送的格式错误的数据而发生的任何ModelState
错误。
我有一个ActionFilterAttribute
来检查ModelState
是否有效。我想将状态ErrorMessage
发送给用户。这部分工作正常。
/// <summary>
/// This filter will validate the models that are used in the webapi
/// </summary>
public class MyValidationFilter :System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
//ErrorResponse is just a simple data structure used to hold response
ErrorResponse errorResponse = new ErrorResponse();
//loop through each key(field) and see if it has any errors
foreach (var key in actionContext.ModelState.Keys)
{
var state = actionContext.ModelState[key];
if (state.Errors.Any())
{
string validationMessage = state.Errors.First().ErrorMessage;
errorResponse.ErrorMessages.Add(new ErrorMessage(validationMessage));
}
}
//this is a custom exception class that i have that sends the response to the user.
throw new WebAPIException(HttpStatusCode.BadRequest, errorResponse );
}
}
}
正常验证(必需,StringLength,Regex)都可以正常工作,因为我可以控制这些消息。
[Required(ErrorMessage = "ID is required")]
public string ID { get; set; }
但是,如果有人传递格式不正确的XML或JSON数据,我无法控制该消息。如果发生这种情况,那么我可能会得到
未终止的字符串。预期分隔符:\“。路径'',第1行,位置 9。
或
解析属性名称后的字符无效。预期':'但得到: }。路径'',第1行,第9位。
或显示我的命名空间的那些。
将值\“Medium \”转换为type时出错 'MyNameSpace.Tenant.WebAPIs.Library.IndividualRegistrationInfo'。路径 '',第1行,第8位。
第1行位置出错7.期待元素 命名空间中的“IndividualRegistrationInfo” 'http://schemas.datacontract.org/2004/07/MyNameSpace.Tenant.WebAPIs.Library.IndividualRegistrationInfo' .. 遇到名为'asdf'的'元素',命名空间''
当发生这种情况时,我想以某种方式发回通用的“无效数据”消息。是否有我可以使用的其他过滤器,或其他可以捕获并覆盖这些消息的地方?
更新
以下是我根据克里斯的建议最终做的事情:
我为JSON和XML创建了2个新的格式化程序。
public class JsonFormatter : JsonMediaTypeFormatter
{
public override System.Threading.Tasks.Task<object> ReadFromStreamAsync(Type type, System.IO.Stream stream, System.Net.Http.Headers.HttpContentHeaders contentHeaders, IFormatterLogger formatterLogger)
{
System.Threading.Tasks.Task<object> task = base.ReadFromStreamAsync(type, stream, contentHeaders, formatterLogger);
//parse error if null
if (task.Result == null)
{
//handle error here.
}
return task;
}
}
public class XMLFormatter : XmlMediaTypeFormatter
{
public override System.Threading.Tasks.Task<object> ReadFromStreamAsync(Type type, System.IO.Stream stream, System.Net.Http.Headers.HttpContentHeaders contentHeaders, IFormatterLogger formatterLogger)
{
System.Threading.Tasks.Task<object> task = base.ReadFromStreamAsync(type, stream, contentHeaders, formatterLogger);
//parse error if null
if (task.Result == null)
{
//handle error here
}
return task;
}
}
和global.asax中的Application_Start
方法
GlobalConfiguration.Configuration.Formatters.Insert(0, new JsonFormatter());
GlobalConfiguration.Configuration.Formatters.Insert(1, new XMLFormatter());
我不确定是否有更好的方法,但这似乎有用。
答案 0 :(得分:0)
以下是我根据克里斯的建议最终做的事情:
为JSON和XML创建了2个新的格式化程序。
public class JsonFormatter : JsonMediaTypeFormatter{
public override System.Threading.Tasks.Task<object> ReadFromStreamAsync(Type type, System.IO.Stream stream, System.Net.Http.Headers.HttpContentHeaders contentHeaders, IFormatterLogger formatterLogger)
{
System.Threading.Tasks.Task<object> task = base.ReadFromStreamAsync(type, stream, contentHeaders, formatterLogger);
//parse error if null
if (task.Result == null)
{
//handle error here.
}
return task;
}}
public class XMLFormatter : XmlMediaTypeFormatter
{
public override System.Threading.Tasks.Task ReadFromStreamAsync(Type type, System.IO.Stream stream, System.Net.Http.Headers.HttpContentHeaders contentHeaders, IFormatterLogger formatterLogger)
{
System.Threading.Tasks.Task task = base.ReadFromStreamAsync(type, stream, contentHeaders, formatterLogger);
//parse error if null
if (task.Result == null)
{
//handle error here
}
return task;
}
}
和global.asax中的Application_Start方法
GlobalConfiguration.Configuration.Formatters.Insert(0, new JsonFormatter());
GlobalConfiguration.Configuration.Formatters.Insert(1, new XMLFormatter());
我不确定是否有更好的方法,但这似乎有用。
答案 1 :(得分:0)
所以这就是问题:
MediaTypeFormatter
消耗与HTTP请求关联的System.IO.Stream
; IFormatterLogger.OnError(string,Exception)
,但第一个参数只是一个'路径'(然而解析器选择构思它)而不是输入本身的副本。所以是的,如果你想查看并对导致错误的请求作出反应(或记录),你需要实现并注册自己的MediaTypeFormatter,自己进行解析/反序列化,并根据到你自己的协议(除了WebApi协议)。