使用 Postsharp Contracts 验证反序列化对象
Validating deserialised object with Postsharp Contracts
[这是一个明显的问题,但我找不到任何相关信息 - 如果有人可以参考我,那就太好了。]
在 WebAPI 项目中:
public class MyObject
{
[PostSharp.Patterns.Contract.Required]
public string Name {get;set;}
}
public class MyController : ApiController
{
public HttpResponseMessage Post([FromBody]MyObject obj)
{
/// ...
}
}
在编译期间,我猜想 PostSharp 的验证将它们自己放在属性的设置器中,所以当 obj
从请求的正文中反序列化时,它的字段没有被验证。
那么,best/clean 验证该对象的方法是什么?
干杯
目前没有干净的方法来实现这种验证,因为假定曾经序列化的对象已经有效。
为了强制验证逻辑,需要使用 ISerializationCallback
接口的 OnDeserialized
方法,遍历属性并将它们强制设置为当前值以强制验证。
这可以通过 PostSharp 方面来完成,但这肯定是非常重要的。另一种可能性是使用 reflection/expression 树来实现相同的目的。
如果您认为这是 PostSharp 的一个不错的功能,您可以投票 PostSharp's UserVoice page。
正如 Daniel Balas 所写,没有简单的解决方案可以在反序列化对象后触发 PostSharp 的验证,除了实现 ISerializationCallback
接口的 OnDeserialized
方法。所以我 post 我写了一个方面,通过反射一个一个地深度复制 public 对象的属性,从而激活 setter 中的验证。
[Serializable]
public sealed class ArgsValidationAspect : MethodInterceptionAspect
{
public override bool CompileTimeValidate(MethodBase method)
{
if (!method.GetParameters().Any(p => p.ParameterType.IsClass))
{
Message.Write(method, SeverityType.Error, "MY001", "Cannot apply HttpObjectValidationAspect to method '{0}'.", method);
return false;
}
return true;
}
public override void OnInvoke(MethodInterceptionArgs args)
{
foreach (var arg in args.Arguments)
{
try
{
RecursiveCopyInstance(arg);
}
catch (Exception e)
{
throw e.InnerException ?? e;
}
}
base.OnInvoke(args);
}
private static object RecursiveCopyInstance(object origin)
{
var type = origin.GetType();
var instance = Activator.CreateInstance(type);
foreach (var prop in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
{
var val = prop.GetValue(origin);
if (val != null && !prop.PropertyType.IsPrimitive && !prop.PropertyType.Equals(typeof(string)))
{
val = RecursiveCopyInstance(val);
}
prop.SetValue(instance, val);
}
return instance;
}
}
[这是一个明显的问题,但我找不到任何相关信息 - 如果有人可以参考我,那就太好了。]
在 WebAPI 项目中:
public class MyObject
{
[PostSharp.Patterns.Contract.Required]
public string Name {get;set;}
}
public class MyController : ApiController
{
public HttpResponseMessage Post([FromBody]MyObject obj)
{
/// ...
}
}
在编译期间,我猜想 PostSharp 的验证将它们自己放在属性的设置器中,所以当 obj
从请求的正文中反序列化时,它的字段没有被验证。
那么,best/clean 验证该对象的方法是什么?
干杯
目前没有干净的方法来实现这种验证,因为假定曾经序列化的对象已经有效。
为了强制验证逻辑,需要使用 ISerializationCallback
接口的 OnDeserialized
方法,遍历属性并将它们强制设置为当前值以强制验证。
这可以通过 PostSharp 方面来完成,但这肯定是非常重要的。另一种可能性是使用 reflection/expression 树来实现相同的目的。
如果您认为这是 PostSharp 的一个不错的功能,您可以投票 PostSharp's UserVoice page。
正如 Daniel Balas 所写,没有简单的解决方案可以在反序列化对象后触发 PostSharp 的验证,除了实现 ISerializationCallback
接口的 OnDeserialized
方法。所以我 post 我写了一个方面,通过反射一个一个地深度复制 public 对象的属性,从而激活 setter 中的验证。
[Serializable]
public sealed class ArgsValidationAspect : MethodInterceptionAspect
{
public override bool CompileTimeValidate(MethodBase method)
{
if (!method.GetParameters().Any(p => p.ParameterType.IsClass))
{
Message.Write(method, SeverityType.Error, "MY001", "Cannot apply HttpObjectValidationAspect to method '{0}'.", method);
return false;
}
return true;
}
public override void OnInvoke(MethodInterceptionArgs args)
{
foreach (var arg in args.Arguments)
{
try
{
RecursiveCopyInstance(arg);
}
catch (Exception e)
{
throw e.InnerException ?? e;
}
}
base.OnInvoke(args);
}
private static object RecursiveCopyInstance(object origin)
{
var type = origin.GetType();
var instance = Activator.CreateInstance(type);
foreach (var prop in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
{
var val = prop.GetValue(origin);
if (val != null && !prop.PropertyType.IsPrimitive && !prop.PropertyType.Equals(typeof(string)))
{
val = RecursiveCopyInstance(val);
}
prop.SetValue(instance, val);
}
return instance;
}
}