Начинаем делать RESTful web-сервисы на WCF и Nelibur

Original author: Sergey Morenko
  • Translation
  • Tutorial
WCF — реально мощная штука, но раз за разом для новых проектов мы вынуждены создавать новые, похожие друг на друга веб-сервисы. В этой статье (переводе) мы увидим, как создать повторно используемый RESTful message based веб-сервис с помощью Nelibur. Nelibur — это Message based web service framework на чистом WCF. Давайте посмотрим, как начать создание web-сервисов на WCF с использованием Nelibur.

Шаг 1. Создание приложения


Для простоты хостить WCF-сервис будет консольное приложение. Так что просто добавляем новый консольный проект.


Шаг 2. Инсталлируем Nelibur


Самый простой способ установить Nelibur — воспользоваться NuGet package manager.


То же самое можно сделать с помощью Package Manager Console


Теперь мы готовы создать RESTful WCF message based сервис.

Шаг 3. Создаем WCF-сервис


Для примера, возмем следующие требования к WCF-сервису:

Nelibur уже содержит нужную нам реализацию: JsonServicePerCall.
Итак, добавляем код запуска нашего сервиса.
internal class Program
{
    private static WebServiceHost _service;

    private static void Main()
    {
        _service = new WebServiceHost(typeof(JsonServicePerCall));
        _service.Open();

        Console.WriteLine("ShipTrackingService is running");
        Console.WriteLine("Press any key to exit\n");

        Console.ReadKey();
        _service.Close();
    }
} 

Прописываем конфигурацию
<system.serviceModel>
    <services>
        <service name="Nelibur.ServiceModel.Services.Default.JsonServicePerCall">
            <host>
                <baseAddresses>
                    <add baseAddress="http://localhost:9095/ShipTrackingService" />
                </baseAddresses>
            </host>
            <endpoint binding="webHttpBinding"
                        contract="Nelibur.ServiceModel.Contracts.IJsonService" />
        </service>
    </services>
</system.serviceModel>


Реализуем бизнес-логику


Наш сервис должен уметь:
  • Добавлять корабль
  • Получать корабль по ShipId

Создаем команду AddShipCommand
public sealed class AddShipCommand
{
    public string ShipName { get; set; }
} 

Результатом выполнения команды должен стать объект ShipInfo
public sealed class ShipInfo
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

Добавляем запрос ShipLocationQuery, результатом выполнения которого должен быть объект ShipLocation
public sealed class ShipLocationQuery
{
    public Guid ShipId { get; set; }
}
 
public sealed class ShipLocation
{
    public string Location { get; set; }
    public Guid ShipId { get; set; }
}

Теперь нам нужно сделать обработчик команды и запроса
public sealed class ShipProcessor : IPost<AddShipCommand>,
                                    IGet<ShipLocationQuery>
{
    private static readonly Dictionary<Guid, Ship> _ships = new Dictionary<Guid, Ship>();

    public object Get(ShipLocationQuery request)
    {
        if (_ships.ContainsKey(request.ShipId))
        {
            return new ShipLocation
            {
                Location = "Sheldonopolis",
                ShipId = request.ShipId
            };
        }
        throw new WebFaultException(HttpStatusCode.BadRequest);
    }

    public object Post(AddShipCommand request)
    {
        var ship = new Ship(request.ShipName, Guid.NewGuid());
        _ships[ship.Id] = ship;
        return new ShipInfo
        {
            Id = ship.Id,
            Name = ship.Name
        };
    }
} 

Связываем команду и запрос с обработчиком
internal class Program
{
    private static WebServiceHost _service;

    private static void ConfigureService()
    {
        NeliburRestService.Configure(x =>
        {
            x.Bind<AddShipCommand, ShipProcessor>();
            x.Bind<ShipLocationQuery, ShipProcessor>();
        });
    }

    private static void Main()
    {
        ConfigureService();

        _service = new WebServiceHost(typeof(JsonServicePerCall));
        _service.Open();

        Console.WriteLine("ShipTrackingService is running");
        Console.WriteLine("Press any key to exit\n");

        Console.ReadKey();
        _service.Close();
    }
}

Все, сервис закончен. Как вы заметили, вы можете добавлять любые операции без изменения WCF-сервиса…

Клиент, использующий наш WCF-сервис


В качестве клиента можно использовать:

Fiddler


Добавление нового корабля (с помощью POST-запроса):


Получение корабля по ShipId (с помощью GET-запроса):


JsonServiceClient


Для создания своего клиента — добавляем еще одно консольное приложение.
Вот код клиента:
internal class Program
{
    private static void Main()
    {
        var client = new JsonServiceClient(Settings.Default.ServiceAddress);
        var shipInfo = client.Post<ShipInfo>(new AddShipCommand { ShipName = "Star" });
        Console.WriteLine("The ship has added: {0}", shipInfo);

        var shipLocation = client.Get<ShipLocation>(new ShipLocationQuery { ShipId = shipInfo.Id });
        Console.WriteLine("The ship {0}", shipLocation);

        Console.ReadKey();
    }
} 

Запускаем наш клиент и видим результат выполнения:

На стороне сервиса


На стороне клиента


Дополнительная литература




Вот и все


Я надеюсь, вам понравилось. Спасибо за чтение статьи (перевода).
Исходники можно скачать с оригинала.

От переводчика


При чтении статьи рекомендую обратить внимание на код связки запросов и обработчиков:
    private static void ConfigureService()
    {
        NeliburRestService.Configure(x =>
        {
            x.Bind<AddShipCommand, ShipProcessor>();
            x.Bind<ShipLocationQuery, ShipProcessor>();
        });
    }

Добавление нового функционала в сервис сведется к созданию класса запроса\команды, класса-обработчика и их связки. Легко и непринужденно организуется и используется милый сердцу CQRS. Nelibur позволяет организовать это чудо с минимальными трудозатратами. А если проявить немного смекалки, то связку запросов\команд и обработчиков можно делать автоматически и тогда магия станет полной :)

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 9

    +9
    Какой-то странный у вас REST. Больше похоже на RPC-over-HTTP.
      0
      Действительно, приведенный в примере сервис не соответствует стилю RESTful
      0
      Какой-то странный у вас REST. Больше похоже на RPC-over-HTTP.

      А никто и не говорит, что у нас REST. У нас message based RESTful.
        +1
        Не могли бы вы вкратце объяснить отличие между «message based RESTful» и «REST»?
          0
          Присоединяюсь к вопросу. А еще лучше — дать формальное определение message-based, с пояснениями, чем же оно принципиально отличается от всего остального.
        0
        В чем профит от использования WCF по сравнению со всем тем же самым, сделанным на WebAPI?
          0
          При чтении статьи рекомендую обратить внимание на код связки запросов и обработчиков:

          Обращаем:

          NeliburRestService.Configure
          


          Конфигурация через статический класс? Вы серьезно?

          Легко и непринужденно организуется и используется милый сердцу CQRS.

          «Милый сердцу CQRS» лучше все-таки делать либо на честных сервисах без намеков на messaging (как у Грега Янга в каноническом тексте), либо уж сразу на честных message queues, чтобы получить все преимущества сообщений. А тут что-то промежуточное.

        Only users with full accounts can post comments. Log in, please.