Ошибка привязки модели с помощью пользовательского MediaTypeFormatter в ASP.Net Web API - PullRequest
2 голосов
/ 19 марта 2012

Я использую JsonNetFormatter найденный здесь с бета-проектом Web API, размещенным на бета-сайте ASP.Net MVC 4, и обнаружил, что привязка модели работает немного иначе, чем при использованиипо умолчанию JsonMediaTypeFormatter.После переключения на JsonNetFormatter привязка модели, похоже, игнорирует параметры, заданные в URL.Например, следующий код прекрасно работает со значением по умолчанию JsonMediaTypeFormatter, но когда я использую JsonNetFormatter, возникает эта ошибка:

"The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Net.Http.HttpResponseMessage Put(Int32, WebAPISpike.Website.Api.Model.PutLesson)'...

JsonNetFormatter

public class JsonNetFormatter : MediaTypeFormatter
{
    private JsonSerializerSettings _jsonSerializerSettings;

    public JsonNetFormatter(JsonSerializerSettings jsonSerializerSettings)
    {
        _jsonSerializerSettings = jsonSerializerSettings ?? new JsonSerializerSettings();

        // Fill out the mediatype and encoding we support
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
        Encoding = new UTF8Encoding(false, true);
    }

    protected override bool CanReadType(Type type)
    {
        if (type == typeof(IKeyValueModel))
        {
            return false;
        }

        return true;
    }

    protected override bool CanWriteType(Type type)
    {
        return true;
    }

    protected override Task<object> OnReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext)
    {
        // Create a serializer
        JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings);

        // Create task reading the content
        return Task.Factory.StartNew(() =>
        {
            using (StreamReader streamReader = new StreamReader(stream, Encoding))
            {
                using (JsonTextReader jsonTextReader = new JsonTextReader(streamReader))
                {
                    return serializer.Deserialize(jsonTextReader, type);
                }
            }
        });
    }

    protected override Task OnWriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext, TransportContext transportContext)
    {
        // Create a serializer
        JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings);

        // Create task writing the serialized content
        return Task.Factory.StartNew(() =>
        {
            using (StreamWriter streamWriter = new StreamWriter(stream, Encoding))
            {
                using (JsonTextWriter jsonTextWriter = new JsonTextWriter(streamWriter))
                {
                    serializer.Serialize(jsonTextWriter, value);
                }
            }
        });
    }
}

Web API Config

var serializerSettings = new JsonSerializerSettings();  
serializerSettings.Converters.Add(new IsoDateTimeConverter());

GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.JsonFormatter);
GlobalConfiguration.Configuration.Formatters.Add(new JsonNetFormatter(serializerSettings));

Контроллер

public class LessonsController : ApiController {
    public HttpResponseMessage Put(int id, PutLesson updates) {
        // get lesson by id and update it with new values in from updates
        return new HttpResponseMessage(HttpStatusCode.OK);
    }
}

Модель

public class PutLesson {
    public string LessonName { get; set; }
    public string Overview { get; set; }
}

Я могу обойти эту проблему, переместив параметр id в мою модель PutLesson и затем установив его там, но тогда это не URI, который идентифицирует ресурс, это тело запроса,Чего-то не хватает в реализации JsonNetFormatter или в моей конфигурации?

1 Ответ

1 голос
/ 20 марта 2012

Это ошибка в бета-версии WebAPI (это происходит со всеми видами пользовательских MediaTypeFormatters, ее планируется исправить в следующей версии). На данный момент есть два обходных пути для этой проблемы. Наиболее «чистым» кажется добавление ActionFilter, который будет обрабатывать привязку этих параметров для вас. Подробнее об этом можно прочитать здесь:

Вы также можете найти там ссылку на обсуждение, которая содержит второй обходной путь.

...