场景:
WebService中的传入/传出参数是一个字段非常多的一个对象,我们往往是在业务逻辑层来引用WebService,而值是从页面层传入的,因此需要自己定义一个实体,来实现页面层往业务逻辑层之间的传值。
如果两个实体之间字段非常多的话,可以利用反射来实现两个实体之间的转换。
首先,我们自定义一个Attribute,用于表示实体中某个属性,在WSDL中的名称(WSDL中的属性名称与自定义的不一定一致,比如用Java开发的WebService,在C#中调用,属性的编码规范不一样):
[AttributeUsage(AttributeTargets.All, AllowMultiple=true)]
public class WSDLFieldNameAttribute : Attribute
{
public string FieldName
{
get;
set;
}
public Type FieldType
{
get;
set;
}
public WSDLFieldNameAttribute(string Field)
{
FieldName = Field;
FieldType = typeof(string);
}
public WSDLFieldNameAttribute(string Field, Type type)
{
FieldName = Field;
FieldType = type;
}
}
使用方法:
[WSDLFieldNameAttribute("fromDate")]
[Description("开始日期,格式“yyyyMMdd”")]
public string FromDate
{
get;
set;
}
转换类:
public static class WSDLFieldMappingUtil
{
/// <summary>
/// fill wsdl entity from entity
/// </summary>
/// <param name="wsdlObject"></param>
/// <param name="entity"></param>
public static void FillInWSDLEntity(object wsdlObject, object entity)
{
Type wsdlType = wsdlObject.GetType();
Type entityType = entity.GetType();
PropertyInfo wsdlProperty;
PropertyInfo[] pi = entityType.GetProperties();
foreach (PropertyInfo entityProperty in pi)
{
WSDLFieldNameAttribute[] myAttribute = (WSDLFieldNameAttribute[])entityProperty.GetCustomAttributes(typeof(WSDLFieldNameAttribute), false);
if (myAttribute.Length == 0)
{
continue;
}
if (entityProperty.PropertyType.IsEnum)
{
if (myAttribute.Length == 1 && myAttribute[0].FieldType == typeof(string))
{
wsdlProperty = wsdlType.GetProperty(myAttribute[0].FieldName);
if (wsdlProperty == null)
continue;
var value = entityProperty.GetValue(entity, null);
if (value != null)
{
wsdlProperty.SetValue(wsdlObject, EnumAttributeHelper.GetSqlByEnum(value), null);
}
}
else
{
throw new Exception(string.Empty);
}
}
else
{
wsdlProperty = wsdlType.GetProperty(myAttribute[0].FieldName);
if (wsdlProperty == null)
continue;
var value = entityType.GetProperty(entityProperty.Name).GetValue(entity, null);
if (value != null)
{
if (wsdlProperty.PropertyType != entityProperty.PropertyType)
{
if (wsdlProperty.PropertyType.IsEnum)
{
value = Enum.Parse(wsdlProperty.PropertyType, value.ToString());
}
else if (entityProperty.PropertyType == typeof(DateTime))
{
value = ((DateTime)value).ToString("yyyyMMdd");
}
else
{
value = Convert.ChangeType(value, wsdlProperty.PropertyType);
}
}
wsdlProperty.SetValue(wsdlObject, value, null);
}
else
{
if (wsdlProperty.PropertyType == typeof(string))
{
wsdlProperty.SetValue(wsdlObject, "", null);
}
}
}
}
}
/// <summary>
/// fill entity from wsdl entity
/// </summary>
/// <param name="wsdlObject"></param>
/// <param name="entity"></param>
public static void FillInEntityFromWSDLObject(object entity, object wsdlObject)
{
if (wsdlObject == null)
return;
Type wsdlType = wsdlObject.GetType();
Type entityType = entity.GetType();
PropertyInfo wsdlProperty;
PropertyInfo[] pi = entityType.GetProperties();
foreach (PropertyInfo entityProperty in pi)
{
WSDLFieldNameAttribute[] myAttribute = (WSDLFieldNameAttribute[])entityProperty.GetCustomAttributes(typeof(WSDLFieldNameAttribute), false);
if (myAttribute.Length == 0)
{
continue;
}
if (entityProperty.PropertyType.IsEnum)
{
if (myAttribute.Length == 1 && myAttribute[0].FieldType == typeof(string))
{
wsdlProperty = wsdlType.GetProperty(myAttribute[0].FieldName);
if (wsdlProperty == null)
continue;
var value = wsdlProperty.GetValue(wsdlObject, null);
if (value != null && value.ToString() != "")
{
entityProperty.SetValue(entity, EnumAttributeHelper.GetEnumBySqlValue(entityProperty, value.ToString()), null);
}
}
else
{
throw new Exception(string.Empty);
}
}
else
{
wsdlProperty = wsdlType.GetProperty(myAttribute[0].FieldName);
if (wsdlProperty == null)
continue;
var value = wsdlProperty.GetValue(wsdlObject, null);
if (value != null)
{
if (value.ToString() == "")
{
if (entityProperty.PropertyType == typeof(string))
{
entityProperty.SetValue(entity, value, null);
}
continue;
}
if (wsdlProperty.PropertyType != entityProperty.PropertyType)
{
if (entityProperty.PropertyType == typeof(DateTime))
{
if (value.ToString().Length == 8)
{
value = value.ToString().Substring(0, 4) + "-" + value.ToString().Substring(4, 2) + "-" + value.ToString().Substring(6, 2);
}
}
value = Convert.ChangeType(value, entityProperty.PropertyType);
}
entityProperty.SetValue(entity, value, null);
}
}
}
}
}
上面代码需要注意的是,在某些时候,某个属性在传输的时候是以字符串的形式传输或者存储的,而在我们自定义的实体中,为了提高代码的可读性,而使用枚举
如:在数据库中存储的值分别是:O,C,P,D
public enum DcoumentStatusEnum
{
[SqlValue("O")]
Open = 0,
[SqlValue("C")]
Close = 1,
[SqlValue("P")]
Paid = 2,
[SqlValue("D")]
Delivered = 3
}
因此需要对枚举做些特殊处理,自定义一个SqlValueAttribute:
[AttributeUsage(AttributeTargets.All)]
public class SqlValueAttribute : Attribute
{
public string Text
{
get;
set;
}
public SqlValueAttribute(string text)
{
Text = text;
}
}
利用反射,根据SqlValue获取枚举,或者根据枚举获取SqlValue,性能可能会比较低,暂时也没想出什么好的办法。
public static object GetEnumBySqlValue(PropertyInfo pInfo, string sqlValue)
{
FieldInfo[] pi = pInfo.PropertyType.GetFields();
foreach (FieldInfo p in pi)
{
SqlValueAttribute[] myAttribute = (SqlValueAttribute[])p.GetCustomAttributes(typeof(SqlValueAttribute), false);
foreach (SqlValueAttribute m in myAttribute)
{
if (m.Text == sqlValue.Trim())
{
string a = p.ToString();
return Enum.Parse(pInfo.PropertyType, p.Name);
}
}
}
return null;
}
public static string GetSqlByEnum(object enumValue)
{
FieldInfo[] pi = enumValue.GetType().GetFields();
foreach (FieldInfo p in pi)
{
if (p.Name == enumValue.ToString())
{
SqlValueAttribute[] myAttribute = (SqlValueAttribute[])p.GetCustomAttributes(typeof(SqlValueAttribute), false);
foreach (SqlValueAttribute m in myAttribute)
{
return m.Text;
}
}
}
return null;
}