ASP.NET Web API 中简单 属性 的自定义类型转换器
Custom Type Converter on a Simple Property in ASP.NET Web API
在一个 ASP.NET Web API 项目中,我想加密所有响应中的所有实体 ID 并解密所有请求中的加密值。
(注意:我知道如何 encrypt/decrypt 数据,这不是我的问题。)
我认为如果我只用自定义属性装饰 responses/requests 中需要 encrypted/decrypted 的属性就好了。
这就是我喜欢的工作方式:
public class Person
{
[EncryptDecrypt]
public int PersonID {get; set;}
public string Name {get; set;}
public IEnumerable<Order> Orders {get; set;}
}
public class Order
{
[EncryptDecrypt]
public long OrderID {get; set;}
public string Title {get; set;}
public float Price {get; set;}
}
然后在 Web API 方法中:
// GET: api/persons/xhj$j78dPs (xhj$j78dPs is an encrypted PersonID)
public Person Get([EncryptDecrypt]int personId)
{
// Now, I expect personId to be a normal ID, like: 187356
Person person = _repository.GetPerson(personId);
return person;
}
以上网站API的期望回复是:
{
"personId": "xhj$j78dPs",
"name": "Joe Williams",
"orders": [
{
"orderId": "a#jd75mlzed0ihd",
"title": "Buying a new item",
"price": 19.99
}
]
}
这是另一个例子,这次是 PUT 动词的 Web API:
/* PUT Request body: */
{
"orderId": "a#jd75mlzed0ihd",
"title": "Buying a new item - edited",
"price": 13.00
}
相关网站API方法:
// PUT: api/persons/xhj$j78dPs/orders/ (xhj$j78dPs is an encrypted PersonID)
public void Put([EncryptDecrypt]int personId, Order editedOrder)
{
// I expect personId to be a normal ID, like: 187356
// I expect editedOrder.OrderID to be a normal ID, like: 10000089765
_repository.UpdateOrder(personId, editedOrder);
}
如何开发 [EncryptDecrypt]
属性?
[EncryptDecrypt]
实际上应该是 JsonConverter attribute? Or should I develop a custom Media Formatter 或模型绑定器或值提供程序或参数绑定器?我很困惑。
How can I develop the [EncryptDecrypt] attribute?
Is [EncryptDecrypt] should be actually a JsonConverter attribute? Or should I develop a custom Media Formatter or Model Binder or Value Provider or Parameter Binder? I am confused.
你需要两者兼顾;用于将(加密的 int
/long
)值绑定到端点参数的自定义 JsonConverter
for (de)serializing the JSON
data, and a custom ModelBinder
。
尝试这样的事情:
public class EncryptDecrypt : JsonConverter, IModelBinder
{
public override bool CanConvert(Type objectType)
{
return typeof(int).IsAssignableFrom(objectType) ||
typeof(long).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Deserialize the provided value as string
// and decrypt it to its exprected int/long type
var value = serializer.Deserialize<string>(reader);
return Decrypt(value, objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// obviously Encrypt() should convert the int/ long value
// to its encrypted string representation.
var encrypted = Encrypt(value);
writer.WriteValue(encrypted);
}
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
if (!CanConvert(bindingContext.ModelType)) return false;
var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (val == null) return false;
// bindingContext.ModelType should tell us whether the decrypted value
// is expected as an int/ long.
var decrypted = Decrypt(val.RawValue as string, bindingContext.ModelType);
if (decrypted != null)
{
bindingContext.Model = decrypted;
return true;
}
bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Cannot convert value");
return false;
}
}
然后您可以像这样装饰模型:
public class Person
{
[JsonConverter(typeof(EncryptDecrypt))]
public int PersonID { get; set; }
public string Name { get; set; }
public IEnumerable<Order> Orders { get; set; }
}
public class Order
{
[JsonConverter(typeof(EncryptDecrypt))]
public long OrderID { get; set; }
public string Title { get; set; }
public float Price { get; set; }
}
至于 Web API 方法,您需要这样装饰它:
public IHttpActionResult Get([ModelBinder(typeof(EncryptDecrypt))] int personId)
{
// Now, I expect personId to be a normal ID, like: 187356
Person person = _repository.GetPerson(personId);
return Json(person);
}
public void Put([ModelBinder(typeof(EncryptDecrypt))] int personId, Order editedOrder)
{
// I expect personId to be a normal ID, like: 187356
// I expect editedOrder.OrderID to be a normal ID, like: 10000089765
_repository.UpdateOrder(personId, editedOrder);
}
在一个 ASP.NET Web API 项目中,我想加密所有响应中的所有实体 ID 并解密所有请求中的加密值。
(注意:我知道如何 encrypt/decrypt 数据,这不是我的问题。)
我认为如果我只用自定义属性装饰 responses/requests 中需要 encrypted/decrypted 的属性就好了。
这就是我喜欢的工作方式:
public class Person
{
[EncryptDecrypt]
public int PersonID {get; set;}
public string Name {get; set;}
public IEnumerable<Order> Orders {get; set;}
}
public class Order
{
[EncryptDecrypt]
public long OrderID {get; set;}
public string Title {get; set;}
public float Price {get; set;}
}
然后在 Web API 方法中:
// GET: api/persons/xhj$j78dPs (xhj$j78dPs is an encrypted PersonID)
public Person Get([EncryptDecrypt]int personId)
{
// Now, I expect personId to be a normal ID, like: 187356
Person person = _repository.GetPerson(personId);
return person;
}
以上网站API的期望回复是:
{
"personId": "xhj$j78dPs",
"name": "Joe Williams",
"orders": [
{
"orderId": "a#jd75mlzed0ihd",
"title": "Buying a new item",
"price": 19.99
}
]
}
这是另一个例子,这次是 PUT 动词的 Web API:
/* PUT Request body: */
{
"orderId": "a#jd75mlzed0ihd",
"title": "Buying a new item - edited",
"price": 13.00
}
相关网站API方法:
// PUT: api/persons/xhj$j78dPs/orders/ (xhj$j78dPs is an encrypted PersonID)
public void Put([EncryptDecrypt]int personId, Order editedOrder)
{
// I expect personId to be a normal ID, like: 187356
// I expect editedOrder.OrderID to be a normal ID, like: 10000089765
_repository.UpdateOrder(personId, editedOrder);
}
如何开发 [EncryptDecrypt]
属性?
[EncryptDecrypt]
实际上应该是 JsonConverter attribute? Or should I develop a custom Media Formatter 或模型绑定器或值提供程序或参数绑定器?我很困惑。
How can I develop the [EncryptDecrypt] attribute?
Is [EncryptDecrypt] should be actually a JsonConverter attribute? Or should I develop a custom Media Formatter or Model Binder or Value Provider or Parameter Binder? I am confused.
你需要两者兼顾;用于将(加密的 int
/long
)值绑定到端点参数的自定义 JsonConverter
for (de)serializing the JSON
data, and a custom ModelBinder
。
尝试这样的事情:
public class EncryptDecrypt : JsonConverter, IModelBinder
{
public override bool CanConvert(Type objectType)
{
return typeof(int).IsAssignableFrom(objectType) ||
typeof(long).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Deserialize the provided value as string
// and decrypt it to its exprected int/long type
var value = serializer.Deserialize<string>(reader);
return Decrypt(value, objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// obviously Encrypt() should convert the int/ long value
// to its encrypted string representation.
var encrypted = Encrypt(value);
writer.WriteValue(encrypted);
}
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
if (!CanConvert(bindingContext.ModelType)) return false;
var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (val == null) return false;
// bindingContext.ModelType should tell us whether the decrypted value
// is expected as an int/ long.
var decrypted = Decrypt(val.RawValue as string, bindingContext.ModelType);
if (decrypted != null)
{
bindingContext.Model = decrypted;
return true;
}
bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Cannot convert value");
return false;
}
}
然后您可以像这样装饰模型:
public class Person
{
[JsonConverter(typeof(EncryptDecrypt))]
public int PersonID { get; set; }
public string Name { get; set; }
public IEnumerable<Order> Orders { get; set; }
}
public class Order
{
[JsonConverter(typeof(EncryptDecrypt))]
public long OrderID { get; set; }
public string Title { get; set; }
public float Price { get; set; }
}
至于 Web API 方法,您需要这样装饰它:
public IHttpActionResult Get([ModelBinder(typeof(EncryptDecrypt))] int personId)
{
// Now, I expect personId to be a normal ID, like: 187356
Person person = _repository.GetPerson(personId);
return Json(person);
}
public void Put([ModelBinder(typeof(EncryptDecrypt))] int personId, Order editedOrder)
{
// I expect personId to be a normal ID, like: 187356
// I expect editedOrder.OrderID to be a normal ID, like: 10000089765
_repository.UpdateOrder(personId, editedOrder);
}