如何验证集合的类型?
Posted
技术标签:
【中文标题】如何验证集合的类型?【英文标题】:How to validate type of collections? 【发布时间】:2019-04-22 06:44:14 【问题描述】:如何验证和捕获 System.Web.Http.ApiController 类的集合类型转换(JSON 字符串数组到 C# 长集合)(如果可能,在模型初始化之前)?
我想验证并捕获 JSON 数组中的任何非数字元素,以作为错误的请求响应返回(可能以某种方式带有数据注释)。
当包含非数字 JSON 元素(要转换为长集合)时,它们无法解析并在模型传递给 ApiController 方法之前被剥离。鉴于以下类,有效输入应仅包含“PerferredNutTypes”和“GeographyIDs”的数值。
类
public class SquirrelController : ApiController
[HttpPost]
[Route("api/squirrels/search")]
[SwaggerResponse(HttpStatusCode.OK, Type = typeof(SquirrelsResponse))]
public HttpResponseMessage Squirrels(SquirrelsRequest model)
// model already parsed by the time breakpoint reaches here and non-convertable elements already stripped
...
...
...
SquirrelsResponse results = Targeting.SearchForSquirrels(model);
return Request.CreateResponse(HttpStatusCode.OK, results);
public class SquirrelsRequest
public SquirrelsRequest()
public List<long> PreferredNutTypes get; set; = new List<long>();
public GeographySearch geographySearch get; set; = new GeographySearch();
public class GeographySearch
public GeographySearch()
public BooleanOperator Operator get; set; = BooleanOperator.OR;
public List<long> GeographyIDs get; set; = new List<long>();
public enum BooleanOperator
AND,
OR
示例:
//"Toronto" sould be an invalid input when converting from JSON string array to c# long collection.
"PreferredNutTypes": [34,21],
"GeographySearch":
"Operator": 1,
"GeographyIDs": ["Toronto"]
,
// This is what the model currently looks like in public HttpResponseMessage Squirrels(SquirrelsRequest model)
new SquirrelsRequest()
PreferredNutTypes = new List<long>() 34, 21 ,
GeographySearch = new GeographySearch()
Operator = 1
GeographyIDs = new List<long>()
期望:
理想情况下捕获任何非数字值并将它们作为错误请求返回。类似于如何验证到如何使用数据注释来验证范围。 可以接受数据注释解决方案。 理想情况下,这是一种比访问 ModelState 和解析错误消息/密钥更清晰的方法。 理想情况下,可以普遍应用于任何集合。我尝试过的事情:
尝试了自定义数据注释验证器,但只能在解析后访问值。 尝试通过 HttpActionContext 的 ModelState 访问验证错误,但充其量只能获取这些值...System.Web.Http.Controllers.HttpActionContext actionContext.ModelState.["model.GeographySearch.GeographyIDs[0]"].Errors[0].Exception.Message => "Error converting value \"sonali7678687\" to type 'System.Int64'. Path 'subjectSearch.writingAbout[0]', line 6, position 36."
System.Web.Http.Controllers.HttpActionContext actionContext.ModelState.["model.GeographySearch.GeographyIDs[0]"].Errors[0].Exception.InnerException.Message => "Input string was not in a correct format."
...肯定有更好的验证方式吗?
更新 1: 改写问题以使解释和意图更清楚。
【问题讨论】:
ModelState
错误告诉你想要是无效的(即在你给出的例子中,它告诉你GeographyIDs
的第一个值是无效的)所以它不清楚你在期待什么或想做。
我认为您可以从Request["GeographySearch.GeographyId"]
获取当前值,但如果结果不为空,我将只查看ModelState.Where(m => m.Errors.Count > 0)
并返回通用Response.StatusCode = 404
以保持简单。跨度>
【参考方案1】:
为什么你的字体很长?另外,你会使用小数吗?如果没有,您需要的是 int.TryParse()。无论您在哪里使用 int.parse(或您的情况下的 long.parse()),都将其替换为 int.TryParse()。 TryParse 返回一个布尔值(True 或 False),让您知道要解析的字符串是否为数字。
示例:
bool isNumber = int.TryParse("Data I'm Trying to parse but it's a string", variableTheResultWillGetStoredToifSuccessful);
这将返回错误,并且我永远不应该使用的超长变量名将保持为空或不变。因此,您可以这样做
if(isNumber == false)
//skip storing the number
else
//keep doing what you're doing;
你也可以这样做,更简洁地重写上面的内容:
if(isNumber)
//keep doing what you're doing
或多或少,这就是它的摘要。 TryParse 将根据解析是否成功返回 true 或 false 而不会导致代码崩溃,然后您可以使用该信息继续您看起来合适的方式。
如果您要使用小数,请使用 double 而不是 int。
【讨论】:
【参考方案2】:您可以尝试 JSON Schema 验证器,修改您的方法以接收 JSON 正文,先对其进行验证,然后将其转换为模型。
public class SquirrelController : ApiController
[HttpPost]
[Route("api/squirrels/search")]
public SquirrelsResponse Squirrels(PostBody model)
var generator = new JSchemaGenerator();
var schema = generator.Generate(typeof(SquirrelsRequest));
var body = JObject.Parse(model.Body);
bool valid = body.IsValid(schema, out IList<string> messages);
if (!valid)
// Fail, do something
// Success
public class PostBody
public string Body get; set;
获取更多信息...Validating JSON with JSON SchemaJson.NET Schema
【讨论】:
你不能这样验证它,因为如果它是无效的消息将是空的 @Marc 如果你只是像我说的那样接受请求作为字符串,而不是模型,它不会无效。 对不起,我错过了那部分,但后来他改变了 api。客户看到一个字符串而不是一个长列表会感到困惑以上是关于如何验证集合的类型?的主要内容,如果未能解决你的问题,请参考以下文章