Как использовать Json.NET для JSON-моделирования в проекте MVC5?
Я просматривал интернет для ответа или примера, но пока не нашел его. Я просто хотел бы изменить по умолчанию JSON-сериализатор, который используется для десериализации JSON при привязке модели к библиотеке JSON.NET.
Я нашел эту запись SO, но не могу ее реализовать до сих пор, я даже не вижу пространства имен System.Net.Http.Formatters
, и я не могу увидеть GlobalConfiguration
.
Что мне не хватает?
- Удаление десериализации полиморфных classов json без информации о типе с использованием json.net
- Использование пользовательской десериализации тела WCF без изменения десериализации шаблона URI
- JSON.NET - как десериализовать сборку интерфейсных экземпляров?
- Как использовать JSON.NET для десериализации в вложенный / рекурсивный словарь и список?
- Как изменить имена свойств при сериализации с помощью Json.net?
ОБНОВИТЬ
У меня есть проект ASP.NET MVC, это был в основном проект MVC3. В настоящее время я нацелен на .NET 4.5 и использует ASP.NET MVC 5 и связанные с ним пакеты NuGet.
Я не вижу сборки System.Web.Http или любого подобного пространства имен. В этом контексте я хотел бы добавить JSON.NET, который будет использоваться как связующее устройство модели по умолчанию для запросов типа JSON.
- Как я могу разбирать JSON с C #?
- Уничтожить вложенные JSON в объекты C #
- C # JSON.NET - десериализация ответа, использующего необычную структуру данных
- Json.Net - Сериализовать имя свойства без кавычек
- Как показать «вставить class Json» в visual studio 2012, нажав на «Специальная вставка»?
- JSON.NET Parser * кажется * будет двойной сериализацией моих объектов
- Json.Net: свойство Serialize / Deserialize в качестве значения, а не как объект
- JSON.Net Обнаружен собственный цикл привязки
Наконец-то я нашел ответ. В основном мне не нужен материал MediaTypeFormatter
, который не предназначен для использования в среде MVC, но в ASP.NET Web API, поэтому я не вижу этих ссылок и пространств имен (кстати, они включены в Microsoft.AspNet.WeApi
NuGet).
Решение заключается в использовании фабрики изготовителей настраиваемых значений. Вот код, необходимый.
public class JsonNetValueProviderFactory : ValueProviderFactory { public override IValueProvider GetValueProvider(ControllerContext controllerContext) { // first make sure we have a valid context if (controllerContext == null) throw new ArgumentNullException("controllerContext"); // now make sure we are dealing with a json request if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) return null; // get a generic stream reader (get reader for the http stream) var streamReader = new StreamReader(controllerContext.HttpContext.Request.InputStream); // convert stream reader to a JSON Text Reader var JSONReader = new JsonTextReader(streamReader); // tell JSON to read if (!JSONReader.Read()) return null; // make a new Json serializer var JSONSerializer = new JsonSerializer(); // add the dyamic object converter to our serializer JSONSerializer.Converters.Add(new ExpandoObjectConverter()); // use JSON.NET to deserialize object to a dynamic (expando) object Object JSONObject; // if we start with a "[", treat this as an array if (JSONReader.TokenType == JsonToken.StartArray) JSONObject = JSONSerializer.Deserialize>(JSONReader); else JSONObject = JSONSerializer.Deserialize(JSONReader); // create a backing store to hold all properties for this deserialization var backingStore = new Dictionary(StringComparer.OrdinalIgnoreCase); // add all properties to this backing store AddToBackingStore(backingStore, String.Empty, JSONObject); // return the object in a dictionary value provider so the MVC understands it return new DictionaryValueProvider
И вы можете использовать его в своем методе Application_Start
:
// remove default implementation ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType().FirstOrDefault()); // add our custom one ValueProviderFactories.Factories.Add(new JsonNetValueProviderFactory());
Вот сообщение, которое указывало мне на правильное направление, а также это дало хорошее объяснение поставщикам стоимости и модельным машинам.
У меня тоже была такая проблема. Я отправлял JSON в действие, но мои имена JsonProperty были проигнорированы. Таким образом, мои свойства модели всегда были пустыми.
public class MyModel { [JsonProperty(PropertyName = "prop1")] public int Property1 { get; set; } [JsonProperty(PropertyName = "prop2")] public int Property2 { get; set; } [JsonProperty(PropertyName = "prop3")] public int Property3 { get; set; } public int Foo { get; set; } }
Я отправляю в действие с помощью этой пользовательской функции jquery:
(function ($) { $.postJSON = function (url, data, dataType) { var o = { url: url, type: 'POST', contentType: 'application/json; charset=utf-8' }; if (data !== undefined) o.data = JSON.stringify(data); if (dataType !== undefined) o.dataType = dataType; return $.ajax(o); }; }(jQuery));
И я называю это так:
data = { prop1: 1, prop2: 2, prop3: 3, foo: 3, }; $.postJSON('/Controller/MyAction', data, 'json') .success(function (response) { ...do whatever with the JSON I got back });
К сожалению, только foo когда-либо получал привязку (нечетно, так как случай не тот, но я думаю, что по умолчанию modelbinder не чувствителен к регистру)
[HttpPost] public JsonNetResult MyAction(MyModel model) { ... }
Решение оказалось довольно простым
Я только что внедрил универсальную версию связующего устройства для модели Dejan, которая работает очень хорошо для меня. Вероятно, он может использовать некоторые фиктивные проверки (например, убедиться, что запрос на самом деле является приложением / json), но сейчас он делает трюк.
internal class JsonNetModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { controllerContext.HttpContext.Request.InputStream.Position = 0; var stream = controllerContext.RequestContext.HttpContext.Request.InputStream; var readStream = new StreamReader(stream, Encoding.UTF8); var json = readStream.ReadToEnd(); return JsonConvert.DeserializeObject(json, bindingContext.ModelType); } }
Когда я хочу использовать его для определенного действия, я просто скажу, что вместо этого хочу использовать свое обычное JSP-образное связующее:
[HttpPost] public JsonNetResult MyAction([ModelBinder(typeof(JsonNetModelBinder))] MyModel model) { ... }
Теперь мои [JsonProperty (PropertyName = “”)] атрибуты больше не игнорируются в MyModel, и все связано правильно!
В моем случае мне пришлось десериализовать сложные объекты, включая интерфейсы и динамически загружаемые типы и т. Д., Поэтому предоставление настраиваемого поставщика значений не работает, поскольку MVC все еще нуждается в попытках выяснить, как создавать экземпляры интерфейсов, а затем терпит неудачу.
Поскольку мои объекты уже были должным образом аннотированы для работы с Json.NET, я выбрал другой маршрут: я применил настраиваемое связующее устройство и использовал Json.NET для явного десериализации данных тела запроса следующим образом:
internal class CustomModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { // use Json.NET to deserialize the incoming Position controllerContext.HttpContext.Request.InputStream.Position = 0; // see: http://stackoverflow.com/a/3468653/331281 Stream stream = controllerContext.RequestContext.HttpContext.Request.InputStream; var readStream = new StreamReader(stream, Encoding.UTF8); string json = readStream.ReadToEnd(); return JsonConvert.DeserializeObject(json, ...); } }
Взаимодействие настраиваемой модели зарегистрировано в Global.asax.cs
:
ModelBinders.Binders.Add(typeof(MyClass), new CustomModelBinder();