C# 如何实现补丁HTTP?
我正在用MicrosoftWebAPI2开发一个web服务 我有个人控制器,我会处理补丁HTTP请求。下面是我的个人控制器:C# 如何实现补丁HTTP?,c#,asp.net-web-api2,patch,C#,Asp.net Web Api2,Patch,我正在用MicrosoftWebAPI2开发一个web服务 我有个人控制器,我会处理补丁HTTP请求。下面是我的个人控制器: namespace MyAssembly.WebApi.Controllers { [RoutePrefix("api/Person")] public class PersonController : BaseController { [HttpGet] public IHttpActionResult GetAl
namespace MyAssembly.WebApi.Controllers
{
[RoutePrefix("api/Person")]
public class PersonController : BaseController
{
[HttpGet]
public IHttpActionResult GetAll(int id)
{
// get logic...
}
[HttpPost]
[Route("api/Person/{id:int}")]
public IHttpActionResult Create(int id, Person dto)
{
// post logic...
}
[HttpPatch]
[Route("api/Person/{id:int}")]
public IHttpActionResult Update(int id, object dto)
{
Person currentPerson = myRepo.Get(id);
currentPerson.patch(dto); // <-- How can I "patch" currentPerson object?
myRepo.Update(id, currentPerson);
return Ok();
}
}
我的目标是用dto
对象中的所有指定属性更新currentPerson
对象的所有属性
我的HTTP修补程序请求应如下所示:
PATCH /api/Person/1
Host: localhost
Content-Type: application/json
Cache-Control: no-cache
{
"Name": "Alessia",
"PreferredNumbers": [1,2,3],
"PreferredSerieTV": ["Serie1", "Serie2"]
}
public IHttpActionResult Update(int id, Delta<Person> dto) { ... }
我尝试过使用Delta对象,但整数矩阵存在一个已知问题。我之前的签名如下:
PATCH /api/Person/1
Host: localhost
Content-Type: application/json
Cache-Control: no-cache
{
"Name": "Alessia",
"PreferredNumbers": [1,2,3],
"PreferredSerieTV": ["Serie1", "Serie2"]
}
public IHttpActionResult Update(int id, Delta<Person> dto) { ... }
thown异常的代码行如下所示:
private static void updateObjectPropertyCore<TObject>(TObject target, string propertyName, object value) where TObject : class
{
var type = typeof(TObject);
var property = type.GetPropertyCaseInsensitive(propertyName);
if (property != null && property.CanWrite)
{
property.SetValue(target, value); <---
}
}
private static void updateObjectPropertyCore(TObject目标,字符串propertyName,对象值),其中TObject:class
{
var类型=类型(TObject);
var property=type.getPropertyCaseSensitive(propertyName);
if(property!=null&&property.CanWrite)
{
SetValue(target,value);我对PUT和PATCH请求都做了类似的操作
仅接受属性以更改重构操作以接受IDictionary
以保存更改的属性以进行更新/修补
[HttpPatch]
[Route("api/Person/{id:int}")]
public IHttpActionResult Update(int id, [FromBody] Dictionary<string, object> dto) { ... }
[HttpPatch]
[路由(“api/Person/{id:int}”)]
公共IHttpActionResult更新(int id,[FromBody]字典dto){…}
然后,可以通过以下扩展方法使用反射来访问匹配的属性
public static void patchObject<TObject>(this TObject target, Dictionary<string, object> values) where TObject : class {
if (target != null) {
foreach (var kvp in values) {
updateObjectPropertyCore<TObject>(target, kvp.Key, kvp.Value);
}
}
}
private static void updateObjectPropertyCore<TObject>(TObject target, string propertyName, object value) where TObject : class {
var type = typeof(TObject);
var property = type.GetPropertyCaseInsensitive(propertyName);
if (property != null && property.CanWrite) {
object coercedValue;
var destinationType = property.PropertyType;
try {
coercedValue = Convert.ChangeType(value, destinationType, CultureInfo.CurrentCulture);
} catch {
return destinationType.IsValueType ? null : Activator.CreateInstance(destinationType);
}
property.SetValue(target, coercedValue);
}
}
/// <summary>
/// Gets a property by name, ignoring case and searching all interfaces.
/// </summary>
/// <param name="type">The type to inspect.</param>
/// <param name="propertyName">The property to search for.</param>
/// <returns>The property or null if not found.</returns>
public static PropertyInfo GetPropertyCaseInsensitive(this Type type, string propertyName) {
var typeList = new List<Type> { type };
if (type.IsInterface()) {
typeList.AddRange(type.GetInterfaces());
}
var flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance;
return typeList
.Select(interfaceType => interfaceType.GetProperty(propertyName, flags))
.FirstOrDefault(property => property != null);
}
publicstaticvoidpatchobject(这个TObject目标,字典值),其中TObject:class{
如果(目标!=null){
foreach(值中的var kvp){
updateObjectPropertyCore(目标,kvp.Key,kvp.Value);
}
}
}
私有静态void updateObjectPropertyCore(ToObject目标,字符串propertyName,对象值),其中ToObject:class{
var类型=类型(TObject);
var property=type.getPropertyCaseSensitive(propertyName);
if(property!=null&&property.CanWrite){
对象强制值;
var destinationType=property.PropertyType;
试一试{
强制值=Convert.ChangeType(值、destinationType、CultureInfo.CurrentCulture);
}抓住{
返回destinationType.IsValueType?null:Activator.CreateInstance(destinationType);
}
SetValue(目标,强制值);
}
}
///
///按名称获取属性,忽略大小写并搜索所有接口。
///
///要检查的类型。
///要搜索的属性。
///属性,如果未找到,则返回null。
公共静态PropertyInfo GetPropertyCaseSensitive(此类型,字符串propertyName){
var typeList=新列表{type};
if(type.IsInterface()){
typeList.AddRange(type.GetInterfaces());
}
var flags=BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance;
返回类型列表
.Select(interfaceType=>interfaceType.GetProperty(propertyName,标志))
.FirstOrDefault(属性=>属性!=null);
}
因此,现在您可以对要修补的对象调用扩展方法
[HttpPatch]
[Route("api/Person/{id:int}")]
public IHttpActionResult Update(int id, [FromBody] Dictionary<string, object> dto) {
var currentPerson = myRepo.Get(id);
if(currentPerson == null)
return NotFound();
currentPerson.patchObject(dto); // <-- matching keys in dto will modify target object
myRepo.Update(id, currentPerson);
return Ok();
}
[HttpPatch]
[路由(“api/Person/{id:int}”)]
公共IHttpActionResult更新(int id,[FromBody]字典dto){
var currentPerson=myRepo.Get(id);
if(currentPerson==null)
返回NotFound();
patchObject(dto);//我对PUT和PATCH请求都做了类似的操作
仅接受属性以更改重构操作以接受IDictionary
以保存更改的属性以进行更新/修补
[HttpPatch]
[Route("api/Person/{id:int}")]
public IHttpActionResult Update(int id, [FromBody] Dictionary<string, object> dto) { ... }
[HttpPatch]
[路由(“api/Person/{id:int}”)]
公共IHttpActionResult更新(int id,[FromBody]字典dto){…}
然后,可以通过以下扩展方法使用反射来访问匹配的属性
public static void patchObject<TObject>(this TObject target, Dictionary<string, object> values) where TObject : class {
if (target != null) {
foreach (var kvp in values) {
updateObjectPropertyCore<TObject>(target, kvp.Key, kvp.Value);
}
}
}
private static void updateObjectPropertyCore<TObject>(TObject target, string propertyName, object value) where TObject : class {
var type = typeof(TObject);
var property = type.GetPropertyCaseInsensitive(propertyName);
if (property != null && property.CanWrite) {
object coercedValue;
var destinationType = property.PropertyType;
try {
coercedValue = Convert.ChangeType(value, destinationType, CultureInfo.CurrentCulture);
} catch {
return destinationType.IsValueType ? null : Activator.CreateInstance(destinationType);
}
property.SetValue(target, coercedValue);
}
}
/// <summary>
/// Gets a property by name, ignoring case and searching all interfaces.
/// </summary>
/// <param name="type">The type to inspect.</param>
/// <param name="propertyName">The property to search for.</param>
/// <returns>The property or null if not found.</returns>
public static PropertyInfo GetPropertyCaseInsensitive(this Type type, string propertyName) {
var typeList = new List<Type> { type };
if (type.IsInterface()) {
typeList.AddRange(type.GetInterfaces());
}
var flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance;
return typeList
.Select(interfaceType => interfaceType.GetProperty(propertyName, flags))
.FirstOrDefault(property => property != null);
}
publicstaticvoidpatchobject(这个TObject目标,字典值),其中TObject:class{
如果(目标!=null){
foreach(值中的var kvp){
updateObjectPropertyCore(目标,kvp.Key,kvp.Value);
}
}
}
私有静态void updateObjectPropertyCore(ToObject目标,字符串propertyName,对象值),其中ToObject:class{
var类型=类型(TObject);
var property=type.getPropertyCaseSensitive(propertyName);
if(property!=null&&property.CanWrite){
对象强制值;
var destinationType=property.PropertyType;
试一试{
强制值=Convert.ChangeType(值、destinationType、CultureInfo.CurrentCulture);
}抓住{
返回destinationType.IsValueType?null:Activator.CreateInstance(destinationType);
}
SetValue(目标,强制值);
}
}
///
///按名称获取属性,忽略大小写并搜索所有接口。
///
///要检查的类型。
///要搜索的属性。
///属性,如果未找到,则返回null。
公共静态PropertyInfo GetPropertyCaseSensitive(此类型,字符串propertyName){
var typeList=新列表{type};
if(type.IsInterface()){
typeList.AddRange(type.GetInterfaces());
}
var flags=BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance;
返回类型列表
.Select(interfaceType=>interfaceType.GetProperty(propertyName,标志))
.FirstOrDefault(属性=>属性!=null);
}
因此,现在您可以对要修补的对象调用扩展方法
[HttpPatch]
[Route("api/Person/{id:int}")]
public IHttpActionResult Update(int id, [FromBody] Dictionary<string, object> dto) {
var currentPerson = myRepo.Get(id);
if(currentPerson == null)
return NotFound();
currentPerson.patchObject(dto); // <-- matching keys in dto will modify target object
myRepo.Update(id, currentPerson);
return Ok();
}
[HttpPatch]
[路由(“api/Person/{id:int}”)]
公共IHttpActionResult更新(int id,[FromBody]字典dto){
var currentPerson=myRepo.Get(id);
if(currentPerson==null)
返回NotFound();
currentPerson.patchObject(dto);//为什么在补丁操作中使用对象dto
?这不应该是Parson dto
?嗨,Nkosi,dto对象也可以是Person类型。我看不出如何使用“Person”type可以解决这个问题。你能给我一些提示吗?谢谢但是整数矩阵有一个已知的问题。我以前的签名如下:
已知的问题是什么?为什么对象dto
在补丁操作中?不应该是这样吗