[这是一个显而易见的问题,但我找不到任何关于它的东西 - 如果有人可以引用我,它会很棒。]
在 WebAPI项目中:
public class MyObject
{
[PostSharp.Patterns.Contract.Required]
public string Name {get;set;}
}
public class MyController : ApiController
{
public HttpResponseMessage Post([FromBody]MyObject obj)
{
/// ...
}
}
在编译期间,我猜PostSharp的验证将自己置于属性的setter中,因此当从请求的主体反序列化obj
时,其字段不会被验证。
那么,验证该对象的最佳/干净方式是什么?
干杯
答案 0 :(得分:0)
目前还没有干净的方法来实现这样的验证,因为假定曾经序列化的对象已经有效。
为了强制验证逻辑,需要使用ISerializationCallback
接口的OnDeserialized
方法,遍历属性并强制将它们设置为当前值以强制执行验证。
这可以通过PostSharp方面来完成,但它肯定是非平凡的。其他可能性是使用反射/表达树来实现相同的目标。
如果您认为这是PostSharp的一个不错的功能,您可以投票PostSharp's UserVoice page。
答案 1 :(得分:0)
Daniel Balas写道,除了实现OnDeserialized
接口的ISerializationCallback
方法之外,没有简单的解决方案可以在反序列化对象后触发PostSharp的验证。所以我发布了一个我写的Aspect,它通过反射逐个深度复制对象的公共属性,从而激活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;
}
}