В первой части я рассмотрел действительно базовый сценарий, и одной из странных вещей, которые у нас были, было имя представления для возврата коллекции.
Использование Negotiate
дает больше гибкости в отношении того, что мы можем вернуть, что позволяет нам настраивать ответ так, чтобы он по-разному реагировал на разные типы носителей или возвращал частичное содержимое в некоторых сценариях.
Возвращаясь к моему предыдущему посту, я сказал, что мы сможем использовать тот же API для создания нашего веб-сайта, что и мы. Но что делать, когда мы хотим разместить на веб-сайте дополнительную информацию, которая не предоставляется клиенту?
Допустим, у вас есть каталог продуктов, и вы можете просмотреть конкретный продукт на своем веб-сайте. Вы также позволяете людям извлекать контент с вашего сайта для отображения на своем веб-сайте в виде какой-либо партнерской системы. Но когда вы представляете свой продукт, у вас может быть специальное предложение, но когда вы отправляете продукт клиенту-потребителю, вы не хотите включать специальное предложение для него, так как это что-то особенное для вашего сайта.
Покажи мне кодез!
Итак, давайте обновим, Product
чтобы включитьSpecialPrice
public class Product { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } public decimal? SpecialPrice { get; set; } }
Примечание: а также обновите репозиторий, чтобы возвращать Специальную цену для каждогоProduct
Мы также собираемся представить новую модель под названием PartialProduct
. Возможно, есть более подходящее название, но я выбрал его для демонстрации. Это будет так же, как Product
без SpecialPrice
собственности.
public class PartialProduct { public PartialProduct() { } public PartialProduct(Product product) { Id = product.Id; Name = product.Name; Price = product.Price; } public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } }
Конструктор используется для заполнения модели на основе Product
. Вы можете использовать что-то вроде AutoMapper, чтобы сделать это для вас, или написать несколько методов расширения и т. Д.
Теперь с нашим маршрутом, мы хотим вернуть PartialProduct
при ответе application/json
илиapplication/xml
Get["/{id}"] = _ => { var product = productRepository.Get((int)_.id); return Negotiate.WithView("product") .WithModel(product) .WithMediaRangeModel(MediaRange.FromString("application/json"), new PartialProduct(product)) .WithMediaRangeModel(MediaRange.FromString("application/xml"), new PartialProduct(product)); };
Таким образом, мы говорим, что мы хотим согласовать ответ с представлением, product
используя модель product
, но если MediaRange — это application/json
мы хотим вернуть частичный продукт, аналогично, если application/xml
мы хотим также вернуть частичную модель. (если это выглядит много, не волнуйтесь, мы можем привести в порядок это)
Теперь, когда мы настраиваем наш почтальон, text/html
мы получаем SpecialPrice
возвращенный продукт:
Однако, если мы обновим его до, application/json
мы получим:
Anddddd application/xml
мы получаем:
Но… Нам пришлось написать много кода для медиа-диапазонов. Методы расширения, однако, замечательны, поэтому мы можем привести их в порядок, представив наши собственные методы расширения:
public static class NegotiateExtensions { public static Negotiator ForJson(this Negotiator negotiator, object model) { return negotiator.WithMediaRangeModel(MediaRange.FromString("application/json"), model); } public static Negotiator ForXml(this Negotiator negotiator, object model) { return negotiator.WithMediaRangeModel(MediaRange.FromString("application/xml"), model); } }
Это уменьшает вещи до:
Get["/{id}"] = _ => { var product = productRepository.Get((int)_.id); return Negotiate.WithView("product") .WithModel(product) .ForJson(new PartialProduct(product)) .ForXml(new PartialProduct(product)); };
Все еще слишком много? Мы можем ввести еще одно расширение
public static Negotiator OrPartial(this Negotiator negotiator, object model) { return negotiator.ForJson(model).ForXml(model); }
И теперь все, что у нас есть, это
Get["/{id}"] = _ => { var product = productRepository.Get((int)_.id); return Negotiate.WithView("product") .WithModel(product) .OrPartial(new PartialProduct(product)); };
Очевидно, вы можете поиграть, чтобы выяснить, что вам подходит. Но это дает нам гибкость в настройке выходов для разных типов носителей.
В третьей части я расскажу о реализации вашего собственного Media Type ?