company_banner

Эффективное использование WebAPI: self hosting REST-сервисов

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

    Про возможности и применение WebAPI написано уже достаточно много статей, например, вы можете узнать о интересной функции самодокументирования API сервиса через ApiExplorer.

    Существует еще одна замечательная возможность WebAPI, про которую написано не так много — это возможность WebAPI осуществлять самостоятельный хостинг сервиса (self hosting). В этой статье на примере разбирается, как создавать и запускать REST selfhosting-сервисы на базе WebAPI.

    Self hosting REST-сервиса


    Для предоставления доступа к API сервиса не всегда является целесообразным разворачивать его на базе сервера IIS. Если сервис не является частью какого-либо веб-приложения, имеет смысл запускать его на базе собственной инфраструктуры.

    Другим вариантом использования механизма self hosting может быть запуск сервисов на платформах, которые не содержат сервер IIS либо на которых запуск IIS осложнен или излишен.

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

    Сервис внутри консольного приложения


    Рассмотрим функцию самостоятельного хостинга на простейшем примере консольного приложения. Создайте в Visual Studio 2012 консольное приложение на базе шаблона для языка C#.

    С помощью консоли пакетного менеджера NuGet установите пакет AspNetWebApi.Selfhost. Это можно проделать следующей командой:

    Install-package AspNetWebApi.Selfhost

    Данная команда установит все необходимые компоненты в проект консольного приложения. После этого добавьте в проект ссылку на сборку System.Web, если такой ссылки еще нет.

    Первым шагом для создания selfhosting-сервиса будет его конфигурирование. За конфигурирование отвечает класс HttpSelfHostConfiguration. Ниже пример конфигурирования сервиса:

    var selfHostConfiguraiton = new HttpSelfHostConfiguration("http://localhost:5555"); 
    
    selfHostConfiguraiton.Routes.MapHttpRoute( 
        name: "DefaultApiRoute", 
        routeTemplate: "api/{controller}", 
        defaults: null 
    ); 

    Первая строка создает экземпляр класса сервера с установленным адресом. Вторая строка конфигурирует механизм маршрутизации сервера для того, чтобы мы могли запускать на нем свои REST API.

    Следующим шагом будет запуск сервера, это достигается с помощью другого класса HttpSelfHostServer. Ниже код, который запускает сервер для selfhosting -сервисов:

    using (var server = new HttpSelfHostServer(selfHostConfiguraiton)) 
    { 
        server.OpenAsync().Wait(); 
        Console.ReadLine(); 
    }

    Пришло время добавить в наше приложение REST-сервис, который будет хоститься на нашем сервере. Для этого добавьте в проект новый элемент Web API Controller Class, например, с именем ProductController. Добавьте в проект новый класс с именем Product:

    public class Product 
    { 
        public int ID { get; set; } 
        public string Name { get; set; } 
        public string Description { get; set; } 
    }

    В только что созданном контроллере ProductController добавьте новый метод GetAllProducts:

    public IList<Product> GetAllProducts() 
    { 
        return new List<Product>(){ 
                new Product(){ID = 1, Name="Product 1", Description="Desc 1"}, 
                new Product(){ID = 2, Name="Product 2", Description="Desc 2"}, 
                new Product(){ID = 3, Name="Product 3", Description="Desc 3"}, 
        }; 
    }

    Для того чтобы избежать конфликтов, вам нужно будет удалить или закомментировать сгенерированный в шаблоне метод Get().

    В связи с тем, что наше приложение будет представлять собой сервер, слушающий определенные порты, приложение должно быть запущено с повышенными привилегиями. Вы можете запустить скомпилированный исполняемый файл от имени администратора самостоятельно либо запустить проект на исполнение в VS2012 запущенной от имени администратора. Другой возможностью может быть использование команды Netsh.exe для предоставления полномочий резервировать URL текущему пользователю.

    Запустите приложение на исполнение.

    Теперь, пока запущено наше приложение мы можем обращаться к selfhosting-сервису, который запушен без использования IIS. Просто перейдите по адресу http://localhost:5555/api/product/. Для тестирования можно воспользоваться браузером либо использовать Fiddler (рисунок 1).

    clip_image001
    Рис.1. Результат обращения к selfhosting-сервису

    Запуск selfhosting-сервисов в качестве сервиса Windows


    Для запуска selfhosting-сервиса хорошей идеей может стать запуск приложения-сервера в виде сервиса Windows. Сделать это достаточно просто.

    Для быстрого создания системных служб может использоваться очень удобный инструмент TopShelf. В консоли пакетного менеджера NuGet выполните команду установки пакета:

    install-package topshelf

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

    Немного изменим код нашего проекта. Во-первых, вынесем запуск сервера в отдельный класс ProductService:

    class ProductService 
    { 
        private readonly HttpSelfHostServer server; 
    
        public ProductService() 
        { 
            var selfHostConfiguraiton = new HttpSelfHostConfiguration("http://127.0.0.1:5555"); 
    
            selfHostConfiguraiton.Routes.MapHttpRoute( 
                name: "DefaultApiRoute", 
                routeTemplate: "api/{controller}", 
                defaults: null 
                ); 
    
            server = new HttpSelfHostServer(selfHostConfiguraiton); 
        } 
    
        public void Start() 
        { 
            server.OpenAsync(); 
        } 
    
        public void Stop() 
        { 
            server.CloseAsync(); 
            server.Dispose(); 
        } 
    
    }

    Затем модифицируем код метода Main для запуска сервиса с помощью API TopShelf:

    static void Main(string[] args) 
    { 
        HostFactory.Run(x => 
        { 
            x.Service<ProductService>(s => 
            { 
                s.SetServiceName("ProductService Example"); 
                s.ConstructUsing(name => new ProductService()); 
                s.WhenStarted(svc => svc.Start()); 
                s.WhenStopped(svc => svc.Stop()); 
            }); 
    
            x.RunAsLocalSystem(); 
            x.SetDescription("ProductService WebAPI selfhosting Windows Service Example"); 
            x.SetDisplayName("ProductService Example"); 
            x.SetServiceName("ProductService"); 
        }); 
    }

    Здесь с помощью специальных методов, которые предлагает TopShelf мы регистрируем сервис, задавая необходимый для запуска класс, его методы старта и прекращения работы, данные описание сервиса и его название.

    После необходимых модификаций скомпилируйте проект. Теперь вы можете запустить свое приложение в виде сервиса Windows, это делается с помощью команды:

    WebApiSelfhosting install

    Сервис будет установлен (рисунок 2).

    clip_image002
    Рис.2. Установка сервиса Windows

    Теперь, если вы перейдете в список системных служб Windows вы без труда обнаружите свое приложение (рисунок 3).

    clip_image003
    Рис.3. Служба в списке системных служб

    Вам может потребоваться запустить ваш сервис, если он не запущен (рисунок 4)

    clip_image004
    Рис.4. Запуск службы

    Проверим работу selfhosting-сервиса запущенного в качестве сервиса Windows в Fiddler и убедимся, что все работает.

    Удалить сервис из системы можно командой:

    WebApiSelfhosting uninstall

    Заключение


    В этой статье мы рассмотрели одну из функциональных возможностей ASP.NET WebAPI. С помощью механизма self hosting, который поддерживается в WebAPI вы можете создавать REST-сервисы, которые не требуют для своего запуска сервера IIS и могут быть запущены в том окружении, в котором вы захотите.

    ASP.NET WebAPI – это новый инструмент, доступный разработчикам в Visual Studio 2012. Вы можете загрузить новую версию Visual Studio 2012 RC по специальному короткому адресу: http://vs2012.ru/.

    Исходные коды финального проекта (со всеми пакетами и бинарными компонентами) доступны по ссылке sdrv.ms/K9F7Hs
    Microsoft
    708,00
    Microsoft — мировой лидер в области ПО и ИТ-услуг
    Поделиться публикацией

    Комментарии 36

      –5
      Это что обертка в виде wcf программки над другой программкой?
      Хост rest подобных подделок в wcf делается без помощи iis или asp.net.

      Изобрели очередное колесо, а не новый инструмент :)
        +6
        WCF здесь вообще нет

        непонятно, о каких «подделках» идет речь

        предлагаю вам лучше ознакомиться с предметом.
        –4
        Второе впечатление от нового инструмента, после ознакомления с asp web api.
        Это я как понял для asp.net программеров, которые сидят на mvc.

        XaocCPS, ты бы разложил по полочкам сразу.

        Суть оболочки: выдернут движок mvc & webforms и выделено в пакет.
        В чем же кайф юзать это, вместо нормального wcf?

        Расширить поле деятельности asp.net mvc программистов?
          +4
          создание REST-сервисов на нормальном WCF излишне усложнено абстракциями и концепциями SOA.

          WebAPI был создан (изначально в рамках WCF, кстати) чтобы значительно облегчить создание чистых REST-сервисов

          При этом, WCF никуда не делся, это по прежнему мощнейший инструмент незаменимый для своих задач

          И да, WCF естественно поддерживает self hosting, но в этой статьей речь про такую же возможность и для REST-сервисов WebAPI
            –3
            то есть кто-то уже выделил такую категорию REST подделок, как REST-сервис WebAPI?
            В WCF создание REST ничем не осложнено из названного выше.
            Там это делается в меньшее количество букв, я бы даже сказал.

            Странные тенденции…

            Может все таки, чтобы mvc программеры расширили поле деятельности?
              +4
              Ниже код полного restful-сервиса на WebAPI, покажите мне такой же на WCF

                  public class MyApiController : ApiController
                  {
                      public IEnumerable<string> Get()
                      {
                          return new string[] { "value1", "value2" };
                      }
                      public string Get(int id)
                      {
                          return "value";
                      }
                      public void Post(string value)
                      {
                      }
                      public void Put(int id, string value)
                      {
                      }
                      public void Delete(int id)
                      {
                      }
                  }
                –2
                [ServiceContract]
                public class Service
                {
                [OperationContract]
                [WebGet]
                public string EchoWithGet(string s)
                {
                return «You said » + s;
                }
                [OperationContract]
                [WebInvoke]
                public string EchoWithPost(string s)
                {
                return «You said » + s;
                }
                WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(«localhost:8000/»));
                ServiceEndpoint ep = host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "");
                host.Open();
                }

                можно, чтото убрать в xml конфиг, чтобы еще меньше стал код и переносимее.
                  +2
                  да в том то и дело, что web.config там будет больше самого кода, WebAPI вообще не требует конфигурации и всех этих аттрибутов
                    –1
                    в смысле этот код без config файла запускается :)
                    я имел ввиду, что можно убрать три строчки запуска в конфиг.
                    и тогда будет вместо
                    WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(«localhost:8000/»));
                    ServiceEndpoint ep = host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "");
                    host.Open();

                    ------>будет это:

                    ServiceHost host = new ServiceHost(typeof(Service));
                    host.Open();
                    Притом получим, настройки через config файл.

                    Кстати в вашем примере, не понятно, на какой адрес будет настроено.
                      +2
                      вот чтобы разработчикам не думать про эндпоинты, контракты, биндинги и прочее и был сделан чистый REST-инструмент WebAPI, который оперирует REST-понятиями: HTTP verbs, HTTP headers и заведомо работает поверх протокола HTTP/S
                        –2
                        при всем уважении и безотносительно к топику — как только МС начинает что-то двигать под девизом «Чтобы разработчику не думать про....» — получается такое редкостное Г, что становится страшно.

                        За примером далеко ходить не надо — WebForms сделано под девизом «Чтобы разработчику не думать про весь этот Web»
                          –2
                          мне кажется это вообще не МС двигает, а менеджерье какое то.
                          даже название не лаконичное.
                          –2
                          про разработчиком на mvc полагаю все таки речь?
                          сознайтесь, уже.

                          еще с вас, более полный пример, который хоть где-то в себе прописывает адрес и порт.
                        –3
                        и кстати, хорошо сказывается, да не так хорош размер :)
                        в случае webapi мы получаем дутик из движка mvc& webforms.
                        в wcf же, голяк. токо .net и все.
                          +2
                          вы ошибаетесь, еще раз предлагаю вам изучить предмет обсуждения
                            0
                            +1
                            Понравилось. Спасибо. Сменил некоторые самописные велосипеды на WebAPI.
                            И, кстати, не только для mvc. Можно тут взять — http://aspnetwebstack.codeplex.com/ и к формам прикрутить.
                              0
                              кстати, к WebForms прикручивается из коробки
                                0
                                К версиям < 4.5?
                            –1
                            хорошо изучил.
                            в составе mvc идет.
                            но mvc не идет в составе .net4.

                            и не нужно, меня отсылать к предмету обсуждения.
                            можно, тут дополнять свою статью про эффективные REST подделки.
                        +2
                        А как-же приятная плюшка в виде oData? :-)
                          0
                          И как тут с HTTP кешированием, с аторизацией, с безпроблемным доступом ко всем полям пришедшего HTTP запроса?
                            0
                            Спасибо за код, понятно что много времени прошло, но в поиске проблемы для WebApi SelfHost, наткнулся на Ваш пример и решил не мелочиться и переписать сервис на более универсальное решение.
                    0
                    Xaoc закрой вопросы оставшиеся за тобой. А то как то повисло все на тебе.
                      0
                      Xaoc,

                      Итак, у вас появилась Идея! Надо срочно поделиться с людьми для того, чтобы они проникнулись Идеей, а не сидели во мраке невежества. Не спешите,…

                      Не стоит делать пост и сразу же уходить спать в счастливом неведении. Работа с читателем после написания статьи так же важна, как и сама статья.

                      План плох, если:

                      во вступлении раскрыта суть статьи и Идеи;

                      Я прочитав эти цитаты, задумался. Зачем же писались эти цитаты?
                        0
                        Помню как я мучался настраивая WCF на поддержку разнообразных RESTfull запросов. Как я пытался оперировать заголовками http запроса, внедрял поддержку jsonp запросов, занимался проблемами кеширования и выдачей результата в разных форматах (json и xml)
                        На WCF это было одна сплошная головная боль, не говоря о понимании кода через какое то время.
                        WebAPI это то что должно было появиться вместе с WCF
                        Кстати на счет self hosting для WebAPI это первое что мне пришло на ум после изучения WebAPI
                        Молодцы что так быстро заполнили этот пробел.
                          –1
                          Kano, зачем прошлое ворошить, не зная настоящего?
                          Все что ты пытался тогда делать, уже сделано внутри WCF, через behaviours.
                          Так что webapi кхм, кхм.
                          Вроде я мысль правильную толкаю, расширения кругозора для mvc программистов.
                            0
                            Именно через behaviours я это проворачивал и еще много через что.
                            Все это выглядело настолько «красиво» что прям хоть не придумывай свой web api :)
                            А при чем тут mvc программисты?
                              0
                              не понимаю, как это так проворачивали через behaviours?
                              ведь просто ставим нужные и получаем все.
                                0
                                а как вы сделаете поддержку jsonp и поддержку своих http заголовков используя только стандартные behaviours?
                                  0



                                  вот так.
                                  CrossDomainScriptAccessEnabled=true

                                  свои http это уже совсем просто WebInvoke имеет собственно свойство в которое вписывается интересующий вас заголовок.
                                  [WebInvoke(Method = «PUTXAOC», UriTemplate = "")]
                                    0
                                    молодцы в 4 фреймворке догадались доделать поддержку jsonp
                                    на счет своих http заголовков это довольно скупой пример
                                      0
                                      да уже с 2010 года как.
                                      вроде как не отставая от появления самого jsonp.
                                      судя по статьям в инете, интерес к jsonp приходится даже на 2011 год.
                                      точной даты нигде нету.

                                      но вспомни:
                                      Kano, зачем прошлое ворошить, не зная настоящего?
                                      0
                                      чтото, на хабер убогая писалка комментов, и не пропускает обычный xml.
                                      поэтому в прыдущем посте пустота.
                                      пишу еще раз: httpgetenabled=«true» + CrossDomainScriptAccessEnabled=true

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