Comments 57
В статье нет ответа на вопрос «почему не WebAPI?». Интересно, зачем это нужно?
WCF более универсальна. Например, может использовать разные транспорты, а не только HTTP. Более подробное сравнение технологий можно найти на MSDN. Для чего это нужно — по моему скромному мнению, чтобы писать, поддерживать и использовать веб-сервисы легко и с удовольствием. Данный подход позволяет этого достичь.
Транспорт-транспортом, но у вас контракт заточен под REST, так что это не имеет особого смысла.

«Правильное» решение подобной задачи — это вынести собственно бизнес-логику сервиса в отдельный «сервис» (в терминах слоев), который будет использоваться только внутри кода, а дальше выставлять к нему адаптеры в нужном виде. REST-адаптер — отдельно, SOAP-адаптер — отдельно. После этого REST можно делать на WebAPI (на котором его делать действительно легче, чем на WCF).
UFO landed and left these words here
А если заточен под REST (т.е., HTTP), то какие преимущества от использования WCF?
UFO landed and left these words here
Вот это я и спрашиваю: какие могут быть выгоды от использования WCF для REST-сервисов (по сравнению с WebAPI)?
… особенно учитывая, что, например, тот цирк, на который в статье идут ради получения query object, в WebAPI делается в один прием с помощью model binding.
UFO landed and left these words here
Что касается примера с Amazon — вы правда не видите разницы между приведенным вами примером (честный query string), и тем, что в посте — data=%7B%22Country%22%3A%22sheldonopolis%22%2C%22Status%22%3A%22pending%22%7D?

Что же касается «выбрать можно на сайте Microsoft»… понимаете, про то, как работать с REST в WCF, тоже можно прочитать на сайте Microsoft, однако нам принесли про это пост. Так что разумно спросить: раз уж вы принесли нам этот пост, объясните, зачем делать это так, когда есть альтернативные и намного более удобные способы?
UFO landed and left these words here
В обоих случаях — это объект, как он представляется, дело 10е

Как раз нет. Для протоколов взаимодействия очень важно, как представляется объект. REST появился именно из-за того, что многим клиентам проще передавать информацию, представленную в виде конкретной читаемой строки, а не сериализованных данных.

Давайте посмотрим на примере Get, идеальная сигнатура — с точки зрения стабильности и повторного использования object Get(object request)

Во-первых, что такое «повторное использование» в данном контексте? Зачем (в каком именно сценарии использования) оно нужно?
А во-вторых, с точки зрения стабильности эта сигнатура как раз плоха — можно получить в request что угодно, а потом упасть на его преобразовании (ну или тратить ресурсы на проверку преобразуемости).

Можно ли этого добиться в WebAPI — можно, поддерживается ли такое поведение по умолчанию — нет, чтобы добиться такого поведения нужно будет создавать конверторы.

Можно ли такого же добиться в WCF — можно, поддерживается такое поведение поддерживается по умолчанию — да Message Get(Message request)

Вы определитесь, Message Get(Message) или object Get(object)? Потому что со вторым вам придется повозиться в обоих фреймворках, а первое поддерживается из коробки… в обоих. Вот как это выглядит в WebAPI: HttpResponseMessage Get(HttpRequestMessage message). Я вам больше того скажу, в обоих фреймворках с равным успехом можно маршрутизировать все операции сервиса на один объект.

Так что здесь строго на равных (при этом именно с нативными вещами, свойственными HTTP, в WebAPI работать намного проще).

Если сравнивать WCF и Web API как фреймворки, то WebAPI смотрится как поделка, т.к. расширений подобных WCF нет

Во-первых, каких именно актуальных для REST расширений нет в WebAPI (чтобы они при этом были в WCF?
А во-вторых… вы никогда не пробовали решить в WCF простейшую задачу: получить принятое и отправленное сообщение строго в том виде (посимвольно), как оно проходило транспорт (например, для нужд ЭЦП)? Я пробовал. Вы не поверите, но в WebAPI это делается из коробки, а в WCF этого сделать (не вмешиваясь в транспортный уровень) просто нельзя. Или вот, скажем, content negotiation вы как в WCF сделаете?

Так что говорить о поделке и расширениях несколько странно. Это разные фреймворки, для разных задач. WebAPI существенно лучше справляется с REST, WCF — с SOAP (и всяческим WS*).
UFO landed and left these words here
Когда речь идет о ServiceContract, то речь идет о внешнем API. Для внешнего апи важна стабильность, не для приложения

API object -> object — это не API, вы меня простите. Он ничего вообще не определяет, ни входящих параметров, ни исходящих. Это не контракт.

Message Get(Message) это был пример реализации object Get(object),

Как это реализуется в WebAPI — я показал.

Я повторю свой вопрос еще раз: чем конкретно WCF выгоднее, чем WebAPI, для реализации REST-сервисов?

И — тоже повторю — два прикладных вопроса:
— как в WCF получить точное (до символа) тело входящего и исходящего сообщения?
— как в WCF реализовать content negotiation?
UFO landed and left these words here
думаю на этот вопрос я неоднократно отвечал, выбрать можно исходя из требований, плиз читайте внимательнее

Приведите пример требований, при которых WCF выгоднее для REST, чем WebAPI.

боюсь, нужно в транспортный уровень лесть.

И потерять половину возможностей WCF?

насколько помню есть automaticFormatSelectionEnabled

Ага, ровно с двумя форматами: xml и json.
UFO landed and left these words here
Ну, собственно, на этом можно и закончить: вы до сих пор так и не смогли привести пример REST-сервиса, где WCF был бы удобнее/полезнее, чем WebAPI.
UFO landed and left these words here
Вы хоть читали абзац, следующий за таблицей? Так вот, там написано:

Use ASP.NET Web API if you are creating and designing new REST-style services. Although WCF provides some support for writing REST-style services, the support for REST in ASP.NET Web API is more complete and all future REST feature improvements will be made in ASP.NET Web API.


Так что даже MS явно говорит, что для REST надо использовать WebAPI.
UFO landed and left these words here
Message-based есть в WebAPI из коробки, и прекрасно там работает (более того, даже в чистом виде: IHttpController.ExecuteAsync). Поэтому вопрос, с которого начался тред — зачем так извращаться в WCF — остается открытым; и вы на него так ответить и не смогли.

Просто попробуйте переписать примеры из статьи на WebAPI, и вы увидите, насколько компактнее они станут. Только при этом WebAPI вам еще и предоставляет кучу дополнительных полезных возможностей, навроде маршрутизации, модел-биндинга, исходящего форматирования, стека обработчиков и так далее.

Ну и да, вы уж определитесь. Либо message-based, либо контракты. Message-based API по определению не предоставляет жесткого контракта, его там не из чего вычислять.
UFO landed and left these words here
Это все хорошо и возможно красиво, только вот WCF не заточен под REST. Ответьте хотя бы на эти 3 вопроса:
1. Как прикрутить аутентификацию по OpenId Connect или другим более сложным протоколам?
2. Как реализовать поддержку того же Collection+JSON или JSON API?
3. Работа с кастомными заголовками и версионирование апи по датам? (да да, не V1, V2, а версия Api от определенного числа?)

А после этого задумайтесь — а зачем, когда есть все готовое. Давно пора забыть про этот баиндинг, оставленный для обратной совместимости и POX сервисов. Про всякие OWIN можно даже и не заикаться)

С выбором все просто — если нужно что-то из WS-* используем WCF, если нет — WebApi или что другое(сокеты те же самые).
Ну и сама идея красиво выставлять SOAP и REST почти одинаковым способом — порочна, так как ограничена только очень простыми юзкейсами.

Года 3 назад была бы годная статья, а сейчас лучше бы разработчики не видели этого)

UFO landed and left these words here
возможно не понимается сути, что апи константен

Так не работает. Прикладные API должны развиваться, иначе они не отражают суть бизнеса.
UFO landed and left these words here
амазон как то смог и ничего

Что смог-то?

изменение апи это зло, т.к. ведет за собой кучу изменений и его нужно стараться делать как можно более устойчивым

Нужно стараться. Но в реалиях бизнеса это не работает — потому что бизнес неизбежно меняется.

(а Framework Design Guidelines вообще не про то, я бы понял, вы на Эрла ссылку дали)
1. То есть если у вас что-то сложнее пары логин/пароль — все идет лесом? Кому нужен такой Api тогда?
2. Не получится. Как минимум Вам необходим механизм генерации Url, который в WCF отсутствует.
3. Версионность необходма в принципе. Называть ее анахронизмом крутовато. У вас могу меняться наборы параметров, их имена, форматы возвращаемых значений, допустимые заголовки, валидация и много чего еще. Api постоянно эволюционирует.

WebHttpBinding — это обратная совместимость в рамках фреймворка, его нельзя выкинуть, хотя так команда которая его делала как раз разрабатывала WCF WebApi, а потом вынесла это все в Asp.Net WebApi. Поэтому и говорю что это биндинг для совместимости и старых POX сервисов. В разработках новых продуктов никто его не будет рекомендовать. Да и смысла нет, когда есть WebApi.

Реализация чего-то посложнее простейшей сериализации — по сути делать то, что делает WebApi.

REST это не только гонять данные. Это тот же HATEOAS, адекватную работу с которым без системы роутинга не сделать.

Вот пример представления полноценного ресурса(тэг Code почему-то не работает):
{ «collection»:
{
«version»: «1.0»,
«href»: «example.org/friends/»,

«links»: [
{«rel»: «feed», «href»: «example.org/friends/rss»},
{«rel»: «queries», «href»: «example.org/friends/?queries»},
{«rel»: «template», «href»: «example.org/friends/?template»}
],

«items»: [
{
«href»: «example.org/friends/jdoe»,
«data»: [
{«name»: «full-name», «value»: «J. Doe», «prompt»: «Full Name»},
{«name»: «email», «value»: «jdoe@example.org», «prompt»: «Email»}
],
«links»: [
{«rel»: «blog», «href»: «examples.org/blogs/jdoe», «prompt»: «Blog»},
{«rel»: «avatar», «href»: «examples.org/images/jdoe», «prompt»: «Avatar», «render»: «image»}
]
}
]
}
}

Сравните его со своим Dto.

UFO landed and left these words here
1. Вы пробовали прикручивать этого монстра на WCF? Этот топик датирован 09 годом. Я после выхода WebApi вообще не могу видеть это убожество. Менять контракт под один из способов аутентфикации и авторизации? С чего контракт сервиса должен принимать в этом участие?

2. Вы расскажите как роуты генерить будете в WCF.

3. Тогда разьясните что же вы имели ввиду.

Выше вам уже привели выдержку с MSDN. Просто не дай бог кто-то наткнется на эту статью и начнет лепить Http сервисы и называть их REST на устаревшем биндинге, и вместо получения опыта с актуальными технологиями, будет ковырять то, что никому не нужно.

UFO landed and left these words here
Кстати. Заявление
апи амазона, оно сделано в стиле MessageBased

ни на чем, кроме подозрений, не основано. Там внутри вполне может быть маппер, который разносит по конкретным обработчикам на основании Action.

Ну и наконец. Вам уже неоднократно сказали, что message-based прекрасно делается на WebAPI; то, что об этом не знают разработчики ServiceStack — это их проблемы.
И еще раз кстати. А кто вам вообще сказал, что апи амазона — REST?
UFO landed and left these words here
задумайтесь лучше над плюсами MessageBased, может тогда и апи будет стабильным

Не, не будет. В message-based API контракт определяется структурой сообщения. Эта структура эволюционирует вместе с нуждами бизнеса, следовательно, и контракт эволюционирует вслед за ними.
UFO landed and left these words here
Вот только API перестал быть стабильным, он меняется. Невозможно постоянно поддерживать устаревшую функциональность.

Ну а дальше становится понятно, что ровно тот же самый подход (параллельное существование нескольких версий API) можно сделать и без message based API. В чем его достоинства-то в этом конкретном случае?
Что вы понимаетп под «контрактом сервиса» в этом контексте?
UFO landed and left these words here
Я уже говорил, что метод object -> void — это не контракт, он ни к чему не обязывает. Что будет, если в ваш метод запихнуть AmazonSuperDto? Правильно, ошибка той или иной степени внятности.

Ваш фактический контракт в первой версии — это то, что сервис принимает OrderRequest1. Потом вы расширяете контракт, добавив обработку OrderRequest2 (расширение контрактов, в общем-то, сравнительно безопасная операция) — но теперь вы вынуждены поддерживать две версии обработчиков. Наконец, в какой-то момент расхождение между OrderRequest1 и OrderRequestN станет слишком большим, и вы отказываетесь от поддержки первой версии. Ваш фактический контракт в этот момент сократился.

Таким образом, контракт вашего сервиса меняется с каждым изменением бизнеса, просто часть (возможно, все) этих изменений безопасна для потребителей.
UFO landed and left these words here
Понятие «API» в сервисном взаимодействии не используется, используется понятие «контракт» (даже в том же WCF, если вы посмотрите). И если «API» не меняется, а контракт меняется — участники взаимодействия плачут горькими слезами.

Полиморфизм, говорите?.. Вернемся к моему примеру. Скажите, вы будете всегда поддерживать все версии OrderRequest?
UFO landed and left these words here
если будет решено отказаться от одной версии OrderRequest, то одна будет удалена. все как обычно. НО при этом интерфейс взаимодействия с клиентом не меняется, т.к. он абстрактен

Прекрасно. Что произойдет с теми клиентами, которые продолжают посылать первую версию OrderRequest?
UFO landed and left these words here
Вот вам и отличие API от контракта. API, в терминах .net-интерфейса, не изменился. Но контракт сервиса (в части preconditions) — изменился, и теперь разработчикам надо что-то делать. Поэтому стабильного контракта вы не получили, а стабильность API при нестабильном контракте меня, как разработчика клиента не интересует — мне все равно идти и переделывать.

Соответственно, дальше вопрос в том, как этого избежать. Понятное дело, что совсем избежать нельзя, но можно принять упреждающие меры — например, автоматически получать метаданные сервиса, описывающие его контракт, и сравнивать их с метаданными, на основании которых разработан клиент. Очевидно, что это можно делать только для тех сервисов, чей контракт имеет явное выражение в метаданных, и вот тут становится понятно, чем плохи сигнатуры object -> void.

Интереса ради, обратите внимание, что у ServiceStack сделано не так. У них сообщения в каждом конкретном случае строго типизованы, что делает возможным статический анализ контракта сервиса и генерацию метаданных.

(обо всем этом, кстати, хорошо написано у того же Эрла, как раз в районе обсуждения сервисных контрактов)
UFO landed and left these words here
забавно, сами убрали поддержки апи, а теперь стабильности нет, действительно нет

Я-то ничего не убирал, это люди, которые делают «контракты» с object на входе убирают поддержку апи.

вот и чем void Put(object request) не интерфейс

А тем, что он не перечисляет все сообщения, поддерживаемые сервисом, т.е. противоречит вашему определению контракта.

И нет, полиморфизм тут не при чем, потому что полиморфизм тесно связан с LSP, а отсутствие поддержки хотя бы одного наследника нарушает LSP.
UFO landed and left these words here
:)))) перечитайте плиз свои сообщения, особенно с момента что будет есть убрать поддержку OrderRequest1

Ну то есть вы согласны, что message based не делает контракт сервиса стабильнее, поскольку контракт подвержен все тем же изменениям, что и обычно при следовании за бизнесом? Мы же убрали поддержку OrderRequest1 строго в соответствии с требованиями бизнеса.

про определение, оно точно не мое, см © ну как не перечисляет… более чем перечисляет

Не перечисляет. «Все возможные объекты» — а именно так трактуется object — это не определенное множество, оно может изменяться со временем, поэтому не может считаться фиксированным контрактом.

про полиморфизм, откройте плиз и прочитайте о чем идет речь… неоднократно упоминал parametric polymorphism, их несколько

Вы опять не читаете свои же собственные ссылки. Цитирую (выделение мое):

Parametric polymorphism allows a function or a data type to be written generically, so that it can handle values identically without depending on their type. Parametric polymorphism is a way to make a language more expressive, while still maintaining full static type-safety.


Теперь смотрим. Ваша функция обрабатывает данные идентично вне зависимости от типа? Нет, она для одного типа объектов бросает эксепшн, для другого — нет. Значит, это не параметрический полиморфизм. Дополнительно: сохранятеся ли у вас статическая проверка типов? Нет, в функцию можно передать все, что угодно.

То, что вы пытаетесь сделать, могло бы называться ситуативным (ad hoc) полиморфизмом, но для ситуативного полиморфизма свойственно наличие нескольких функций, одной под каждый тип входных данных (чтобы сохранялась статическая типизация).
UFO landed and left these words here
убрали контракт, в соответствие с требованиями бизнеса значит он не стабилен — сильно

Это жизнь. Именно та, с которой вы пытались спорить.

ооч далеко от истины, есть еще DataContract

Где есть? Покажите уже конкретный пример.

абсолютно верно, DataContract и регистрация по типу творит чудеса

Пример в студию.

также стоит обратить внимание на паттерн Visitor и посмотреть что есть диспетчирезация по типу

Так сообщения разного типа, приходящие на вход этого метода, обрабатываются идентично или разным образом?
UFO landed and left these words here
UFO landed and left these words here
Only those users with full accounts are able to leave comments. Log in, please.