如果你绝对想避免 DTO 和 [JsonIgnore],并且真的想使用自定义属性,你可能不得不使用一些反射。我将提出一个远非最佳选择的解决方案,但它可以为您提供一些想法。
首先,创建一个自定义属性来标记不应该通过公共 API 显示的模型属性:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
class DontSendInPublicApiAttribute : Attribute { }
您必须创建一种方法来“擦除”您不想显示的对象属性上的数据。
public static void RemoveSecretData(object obj)
{
// Retrieve all public instance properties defined for the object's type and marked with [DontSendInPublicApi]
var propertiesToHide = obj.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.GetCustomAttribute<DontSendInPublicApiAttribute>() != null);
foreach (var prop in propertiesToHide)
{
// Set all of these properties in the given object to their default values.
// VALUE TYPES (ints, chars, doubles, etc.) will be set to default(TheTypeOfValue), by calling Activator.CreateInstance(TheTypeOfValue).
// REFERENCE TYPES will simply be set to null.
var propertyType = prop.PropertyType;
if (propertyType.IsValueType)
prop.SetValue(obj, Activator.CreateInstance(prop.PropertyType));
else
prop.SetValue(obj, null);
}
}
然后将该属性应用于模型中您希望隐藏的任何字段:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
[DontSendInPublicApi]
public string Occupation { get; set; }
[DontSendInPublicApi]
public int Salary { get; set; }
}
下面是一个如何调用它的示例:
var person = new Person() { Name = "John", Age = 29, Occupation = "Engineer", Salary = 200000 };
RemoveSecretData(person);
在执行RemoveSecretData(person) 后,您会将person 对象的Occupation 和Salary 属性分别设置为null 和0。
关于此解决方案的说明:
- 仅适用于属性。如有必要,您必须修改
RemoveSecretData() 方法以也使用字段。
- 不递归访问对象图。如果您的对象引用另一个对象的某些属性标记为
[DontSendInPublicApi],则该属性不会被隐藏。如有必要,您必须修改 RemoveSecretData() 方法以对更深的对象执行递归调用。如果您打算这样做,请注意循环引用。
- 隐藏属性仍将显示在输出 JSON 中,但 value-typed 属性将始终呈现
0(零)的值,reference-typed 属性将始终显示 null 的值。