3

CommandMessageタイプのパラメーターを持つWebAPIコントローラーアクションがあります。そのタイプには、基本タイプCommandBaseのリストがあります。私の問題は、それらを派生型(この例ではMyCommand)にすることができないことです。

WebAPIcontribプロジェクトのJsonNetFormatterを使用しています。シリアライザーとしてJson.Netを使用しています。

Web APIコントローラー:

public class CommandController : ApiController
{
    public HttpResponseMessage Post(CommandMessage command)
    {
        //command.Commands[0].GetType().Name is always "CommandBase" instead of "MyCommand"
        var message = new HttpResponseMessage(HttpStatusCode.OK)
                          {
                              Content = new StringContent(string.Format("Type of command 1 is '{0}'", command.Commands[0].GetType().FullName))
                          };
        return message;
    }
}

これは私のリクエストです:

private void When()
    {
        using (client)
        {
            command = new MyCommand
                          {
                              CommandId = Guid.NewGuid(),
                              Id = Guid.NewGuid(),
                              Name = "Martin"
                          };

            var message = new CommandMessage(Guid.NewGuid(),new List<CommandBase> {command});

            var requestMessage = GetHttpRequestMessage(message);
            var task = client.PostAsync("http://localhost.:16218/api/command", requestMessage.Content);
            task.Wait();
            responseMessage = task.Result;
        }
    }

private static HttpRequestMessage GetHttpRequestMessage<T>(T data)
    {
        var mediaType = new MediaTypeHeaderValue("application/json");
        var jsonFormatter = new JsonNetFormatter(DefaultJsonSettings.Settings());

        var requestMessage = new HttpRequestMessage<T>(data, mediaType, new[] {jsonFormatter});

        return requestMessage;
    }

そしてJSONとして:

{
  "$type": "PostToBaseClassList.Models.CommandMessage, PostToBaseClassList",
  "Commands": [
    {
      "$type": "PostToBaseClassList.Models.MyCommand, PostToBaseClassList",
      "Id": "45923a41-0c15-46e3-907d-64dd06840539",
      "Name": "Martin"
    }
  ],
  "MessageId": "c873970a-8621-4223-806e-b809039438ab"
}

APIコントローラーアクションからの戻りメッセージは次のとおりです。

コマンド1のタイプは「PostToBaseClassList.Models.CommandBase」です。

コマンドクラス:

 [DataContract]
[XmlRoot]
public class MyCommand : CommandBase
{
    private readonly string name;

    public MyCommand()
    {
    }

    public MyCommand(Guid id, string name)
    {
        this.name = name;
        Id = id;
    }

    [DataMember(Order = 1)]
    [XmlElement]
    public Guid Id { get; set; }

    [DataMember(Order = 2)]
    [XmlElement]
    public string Name { get; set; }
}

 [DataContract]
[KnownType("GetKnownTypes")]
public class CommandBase
{
    public Guid CommandId { get; set; }

    public static Type[] GetKnownTypes()
    {
        var query =
            from type in typeof (CommandBase).Assembly.GetTypes()
            where typeof (CommandBase).IsAssignableFrom(type)
            select type;

        var types = query.ToArray();
        return types;
    }
}

[DataContract]
[Serializable]
[XmlRoot]
public class CommandMessage
{
    public CommandMessage()
    {
    }

    public CommandMessage(Guid messageId, IEnumerable<CommandBase> commands)
    {
        MessageId = messageId;
        Commands = new List<CommandBase>(commands);
    }

    [DataMember]
    [XmlElement]
    public List<CommandBase> Commands { get; set; }

    [DataMember]
    [XmlElement]
    public Guid MessageId { get; set; }
}

Json.Net設定:

//DefaultJsonSettings.Settings()
var settings = new JsonSerializerSettings
                           {
                               NullValueHandling = NullValueHandling.Ignore,
                               TypeNameHandling = TypeNameHandling.Objects,
                               Converters = new List<JsonConverter>
                                                {
                                                    new IsoDateTimeConverter
                                                        ()
                                                }
                           };

private static void RegisterFormatters(HttpConfiguration config)
    {
        var jsonNetFormatter = new JsonNetFormatter(DefaultJsonSettings.Settings());
        config.Formatters.Insert(0, jsonNetFormatter);
    }

何か案は?

4

2 に答える 2

2

Json.NETは属性を尊重しないKnownTypesため、独自のコンバーターを提供する必要があります。

この質問は、この問題に対するいくつかの異なる解決策を提供します 。Json.NETコンバーターを使用してプロパティを逆シリアル化する

于 2012-05-16T09:20:16.550 に答える
0

この行をRegisterFormatters()に追加した後は機能しました

config.Formatters.Remove(config.Formatters.JsonFormatter);

これでは不十分でした

config.Formatters.Insert(0, jsonNetFormatter);

完全版

private void RegisterFormatters()
{
    config.Formatters.Remove(config.Formatters.JsonFormatter);
    var jsonNetFormatter = new JsonNetFormatter(DefaultJsonSettings.Settings());
    config.Formatters.Insert(0, jsonNetFormatter);
}
于 2012-05-17T06:10:42.120 に答える