WebApi - 使用反射检查表单值是否为空以便为实体设置值是否不好
本文关键字:是否 实体 设置 检查 反射 检查表 表单 WebApi | 更新日期: 2023-09-27 18:37:17
我是Web服务(WebApi)开发的新手,但到目前为止,:),这是一次很棒的经历。但是现在,我对在Web服务中处理Put()请求的方式感到困惑。
我有一个接收多部分/表单数据的 Put() 请求。在更新相应的实体之前,我必须检查表单正文值是否为空。
如果实体的特定属性为空,即正文中不存在,则我不应对属性进行任何更改,在这种情况下,属性将具有先前设置的值。如果属性的主体中存在值,则需要更新实体的相应值。
我使用了 if-else,但它导致了大量代码,因为我有大约 10 个实体属性。所以我删除了所有的if-else,并使用反射来实现这一点。这是我目前使用的代码,
[AuthorizationRequired]
[Route("v1/product/updateproduct/")]
[HttpPut]
public bool Put()
{
var httpRequest = HttpContext.Current.Request;
string pdfFolderPath = HttpContext.Current.Server.MapPath("~/Pdf/");
string imageFolderPath = HttpContext.Current.Server.MapPath("~/Images/");
ProductEntity productToUpdate = new ProductEntity();
int id = int.Parse(httpRequest["ProductId"].ToString());
if (id > 0)
{
//Get the existing product entity for the ID
ProductEntity existingProduct = _productServices.GetProductById(id);
if (existingProduct != null)
{
//Check if any files are sent in the PUT Request
//If there are files with appropriate names, then delete the existing files with the new files sent
if (httpRequest.Files.Count > 0)
{
//Handle Files.
}
//Updating the changed properties of Product by using Reflection.
PropertyInfo[] properties = productToUpdate.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
//Check if the property of the Product class exists in the Form Body of Put.
//If it exists, take the corresponding value of property and update it to the product.
//If it doesn't exist, retain the value present in the existing product as it is.
if (httpRequest.Form.AllKeys.Contains(property.Name, StringComparer.OrdinalIgnoreCase))
{
int formPropertyIndex = Array.FindIndex(httpRequest.Form.AllKeys, str => str.Equals(property.Name, StringComparison.OrdinalIgnoreCase));
string propertyToFind = httpRequest.Form.AllKeys[formPropertyIndex];
if (String.Equals(propertyToFind, "FacilityId", StringComparison.OrdinalIgnoreCase))
{
productToUpdate.GetType().GetProperty(propertyToFind, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).SetValue(productToUpdate, Convert.ToInt32(httpRequest[property.Name]));
}
else
{
productToUpdate.GetType().GetProperty(propertyToFind, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).SetValue(productToUpdate, httpRequest[property.Name].ToString());
}
}
else
{
var existingValue = existingProduct.GetType().GetProperty(property.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(existingProduct);
productToUpdate.GetType().GetProperty(property.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).SetValue(productToUpdate, existingValue);
}
}
if (productToUpdate.ImagePath == null)
productToUpdate.ImagePath = existingProduct.ImagePath;
if (productToUpdate.AR_PdfPath == null)
productToUpdate.AR_PdfPath = existingProduct.AR_PdfPath;
if (productToUpdate.AR_Alt_PdfPath == null)
productToUpdate.AR_Alt_PdfPath = existingProduct.AR_Alt_PdfPath;
if (productToUpdate.EN_PdfPath == null)
productToUpdate.EN_PdfPath = existingProduct.EN_PdfPath;
if (productToUpdate.EN_Alt_PdfPath == null)
productToUpdate.EN_Alt_PdfPath = existingProduct.EN_Alt_PdfPath;
//Update LastModifiedBy & LastModifiedAt
string token = httpRequest.Headers.GetValues("Token").ToList().FirstOrDefault();
UserEntity user = _tokenServices.GetUserDetailsForToken(token);
productToUpdate.LastModifiedBy = user.UserName;
productToUpdate.LastModifiedAt = DateTime.Now;
return _productServices.UpdateProduct(id, productToUpdate);
}
else
{
return false;
}
}
return false;
}
上面的代码完成了这项工作,但问题是 - 这是唯一的方法还是有更好的方法来实现我想要做的事情?如果有的话,关于这些方法的指示很少,将不胜感激。
提前致谢:)
我听说过反射方法,我"慢",比其他方法慢,但是当我不知道类结构时,我已经使用它。
如果你知道类结构是个好主意,请使用他的属性。
如果可以修改类,则应使用带有数据注释(https://msdn.microsoft.com/en-us/library/dd901590(VS.95).aspx)的验证来检查对象。
MCV 做得很好,其中之一是从通过 HttpRequest 发布的 html 表单中"重新创建"方法中的对象。在访问原始发布数据之前,我每次都会尝试使用此函数。
在你的情况下,你知道类型,你知道属性名称,所以我认为你可以将你的代码简化为更简单和标准的模式
例如:
[HttpPut]
public HttpResponseMessage Put(int productId, [FromBody] Product product)
{
//..
}
对象产品是从 mvc 引擎为您重新创建的,因此您可以以更舒适的方式使用它