Architect's Log

I'm a Cloud Architect. I'm highly motivated to reduce toils with driving DevOps.

【ASP.NET Web API】WindowsサービスでREST APIを公開する

ASP.NET Web APIを使って、WindowsサービスでREST APIを公開する方法を紹介します。

開発環境・動作環境

今回はプロジェクトの都合で、Visual Studio 2010、.NET 4を使いました。

作り方

以下のリンク先の ASP.NET Web API 1を使ったコンソールアプリのチュートリアルを参考にしました。
www.asp.net

VS2010・.NET 4の場合、ASP.NET Web API 2は使えません。

NugetのコンソールからMicrosoft ASP.NET Web Api Self Hostをインストールします。

Install-Package AspNetWebApi.SelfHost

なお、ASP.NET Web API 2の場合は、OWINが使えるようです。
miso-soup3.hateblo.jp

ソースコード

Service.cs

using System.Net.Http.Formatting;
using System.ServiceProcess;
using System.Web.Http;
using System.Web.Http.SelfHost;

namespace ApiService {
    public partial class Service : ServiceBase {
        private HttpSelfHostServer server = null;

        public Service() {
            InitializeComponent();
        }

        protected override void OnStart(string[] args) {
            this.StartHttpServer();
        }

        protected override void OnStop() {
            this.StopHttpServer();
        }

        private void StartHttpServer() {
            HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://localhost:8080");

            // クエリパラメータでレスポンスのフォーマットを指定できるようにする。
            config.Formatters.XmlFormatter.AddQueryStringMapping("format", "xml", "application/xml");
            config.Formatters.JsonFormatter.AddQueryStringMapping("format", "json", "application/json");

            config.Routes.MapHttpRoute("API Default", "api/{controller}/");

            this.server = new HttpSelfHostServer(config);
            this.server.OpenAsync().Wait();
        }

        private void StopHttpServer() {
            if (this.server != null)
                this.server.Dispose();
        }
    }
}

PersonController.cs

using System.Web.Http;

namespace ApiService {
    public class PersonController : ApiController {
        public Person Get(string id) {
            return new PersonRepository().GetPersonByID(id);
        }
    }
}

Person.cs

namespace ApiService {
    public class Person {
        public string ID { get; set; }

        public string Name { get; set; }

        public override string ToString() {
            return string.Format("ID:[{0}], Name:[{1}]", this.ID, this.Name);
        }
    }
}

PersonRepository.cs

using System.Collections.Generic;
using System.Linq;

namespace ApiService {
    /// <summary>
    /// 通常は永続化したデータを取得するが、サンプルなのでオンメモリで。
    /// </summary>
    class PersonRepository {
        private List<Person> personList;

        public PersonRepository() {
            this.personList = new List<Person>() {
                new Person() { ID = "1", Name = "佐藤太郎" },
                new Person() { ID = "2", Name = "鈴木太郎" },
                new Person() { ID = "3", Name = "田中太郎" },
            };
        }

        public Person GetPersonByID(string id) {
            return this.personList.FirstOrDefault(person => person.ID == id);
        }
    }
}

動作確認

JSON

1. 以下のリクエストを投げます。

http://localhost:8080/api/person/?id=2&format=json

2. 以下のレスポンスが返されます。

{"ID":"2","Name":"鈴木太郎"}

XML

1. 以下のリクエストを投げます。

http://localhost:8080/api/person/?id=3&format=xml

2. 以下のレスポンスが返されます。

<?xml version="1.0"?>
-<Person xmlns="http://schemas.datacontract.org/2004/07/ApiService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><ID>3</ID><Name>田中太郎</Name></Person>

はまったこと

  • PersonControllerクラスをpublicにする必要があります。internalの場合は404のエラーになります。
  • サービスのログオンアカウントに管理者権限がないと、サービスの起動でエラーになります。