В первой части я рассмотрел действительно базовый сценарий, и одной из странных вещей, которые у нас были, было имя представления для возврата коллекции.
Использование 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 ?


