【发布时间】:2012-11-30 05:08:18
【问题描述】:
我正在尝试创建一个通用函数,当给定枚举类型时,它将返回一个对象,当被 WebApi 序列化时,该对象将提供漂亮的 XML/Json 输出。
当序列化为 JSON 时,此方法工作得非常好,但我无法让它与 XML 一起使用。如果我使用 XmlSerializer 或 DataContractSerializer 手动序列化返回的对象,我会得到预期的结果。另一方面,当 WebApi 本身尝试从 HttpRequest 序列化它时,我收到如下错误:
System.Runtime.Serialization.SerializationException
使用数据合同名称键入“优先级” '优先级:http://schemas.datacontract.org/2004/07/' 不是预期的。 考虑使用 DataContractResolver 或添加任何未知类型 静态地添加到已知类型的列表中——例如,通过使用 KnownTypeAttribute 属性或通过将它们添加到已知列表中 传递给 DataContractSerializer 的类型。
我尝试使用 GlobalConfiguration.Configuration.Formatters.XmlFormatter.SetSerializer 为生成的类型设置序列化程序,我知道它可以通过设置断点来工作,但它似乎只是忽略它并引发相同的异常。枚举将由整数支持,并保证每个条目都有唯一的值。这是我用来生成类型并返回它的实例的代码。
public object GetSerializableEnumProxy( Type enumType ) {
if ( enumType == null ) {
throw new ArgumentNullException( "enumType" );
}
if ( !enumType.IsEnum ) {
throw new InvalidOperationException();
}
AssemblyName assemblyName = new AssemblyName("DataBuilderAssembly");
AssemblyBuilder assemBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemBuilder.DefineDynamicModule("DataBuilderModule");
TypeBuilder typeBuilder = moduleBuilder.DefineType( enumType.Name, TypeAttributes.Class | TypeAttributes.Public );
// Add the [DataContract] attribute to our generated type
typeBuilder.SetCustomAttribute(
new CustomAttributeBuilder( typeof(DataContractAttribute).GetConstructor( Type.EmptyTypes ), new object[] {} )
);
CustomAttributeBuilder dataMemberAttributeBuilder = new CustomAttributeBuilder(
typeof(DataMemberAttribute).GetConstructor(Type.EmptyTypes), new object[] {}
);
// For each name in the enum, define a corresponding public int field
// with the [DataMember] attribute
foreach ( var value in Enum.GetValues(enumType).Cast<int>() ) {
var name = Enum.GetName( enumType, value );
var fb = typeBuilder.DefineField( name, typeof(int), FieldAttributes.Public );
// Add the [DataMember] attribute to the field
fb.SetCustomAttribute( dataMemberAttributeBuilder );
// Set the value of our field to be the corresponding value from the Enum
fb.SetConstant( value );
}
// Return an instance of our generated type
return Activator.CreateInstance( typeBuilder.CreateType() );
}
Web Api 控制器方法:
private static IEnumerable<Type> RetrievableEnums = new Type[] {
typeof(Priority), typeof(Status)
};
[GET("enum/{enumName}")]
public HttpResponseMessage GetEnumInformation( string enumName ) {
Type enumType = RetrievableEnums.SingleOrDefault( type =>
String.Equals( type.Name, enumName, StringComparison.InvariantCultureIgnoreCase));
if ( enumType == null ) {
return Request.CreateErrorResponse( HttpStatusCode.NotFound, "The requested enum could not be retrieved" );
}
return Request.CreateResponse( HttpStatusCode.OK, GetSerializableEnumProxy(enumType) );
}
有什么想法吗?
【问题讨论】:
-
能否包含在返回 XML 时重现此错误的 web api 方法?我想我知道问题出在哪里,但我需要看看您是如何尝试将此枚举作为内容返回的。
-
@AndrasZoltan 使用示例 Web API 方法编辑了我的原始问题
-
正如我所怀疑的那样 - 将对象作为
object传递到内容中 - 我可以从接受中看到我建议的解决方案有效:) -
@AndrasZoltan 确实做到了 - 很棒的解决方案,完美运行 - 谢谢!
标签: c# reflection asp.net-web-api