私は、列挙型を指定すると、WebApi によってシリアル化されたときに XML/Json として見栄えの良い出力を提供するオブジェクトを返す汎用関数を作成しようとしています。
このメソッドは、JSON としてシリアル化すると問題なく動作しますが、XML では動作しません。返されたオブジェクトを XmlSerializer または DataContractSerializer を使用して手動でシリアル化すると、期待どおりの結果が得られます。一方、WebApi 自体が HttpRequest からシリアル化しようとすると、次のようなエラーが発生します。
System.Runtime.Serialization.SerializationException
データ コントラクト名が 'Priority:http://schemas.datacontract.org/2004/07/' のタイプ 'Priority' は想定されていません。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) );
}
何か案は?