Development

[ASP.NET MVC] さくっと RSS フィードを出力する

Qiita ASP.NET Advent Calendar 2015 の18日目と Qiita プロ生ちゃん Advent Calendar 2015 15日目(穴埋め)の投稿です。

RSS フィードを作る

プロ生ちゃんこと暮井 慧らが活躍する Web コミック「すぱこー」。Web マンガ更新チェッカー【ピンガ】でも更新チェックできます(少し反映遅いかも?)。このピンガでの取り扱いがきっかけで、コミックのみの RSS フィードを作りました

すぱこー

すぱこーでも活躍するプロ生ちゃんが、「アキバで見かけた萌えキャラコンテスト」にエントリーされています。「暮井 慧(プロ生ちゃん)」への投票お願いします(12/18 20時まで)。プレゼントも当たります。

というわけで、さくっと RSS フィードなど XML 文書を返すサービスを ASP.NET MVC 5 での作り方を紹介します。

ASP.NET プロジェクト作成

開発環境は Visual Studio 2015 Update 1 です。新規に Visual Basic の ASP.NET プロジェクトを作ります。Web API を選択。「認証の変更」ボタンから認証なしを選びます。

ASP.NET

コントローラーの追加

ソリューションエクスプローラーの Controllers フォルダーのコンテキストメニューから[追加]-[コントローラー]を選びます。空のコントローラーを追加します。

ASP.NET

ASP.NET

Controller クラスの実装

Controller クラスができました。

SpacoController.vb
Imports System.Net
Imports System.Web.Http

Namespace Controllers
    Public Class SpacoController
        Inherits ApiController
    End Class
End Namespace

Get メソッドでアクセスされたとき、XML ファイルを返すようにします。次のメソッドを SpacoController クラスへ追加します。

SpacoController.vb
<HttpGet>
Public Function GetALl(Optional offset As Integer = 0,
                       Optional count As Integer = 100) As HttpResponseMessage
    If offset < 0 Then
        offset = 0
    End If

    If count < 0 OrElse count > 100 Then
        count = 100
    End If

    Dim res = New HttpResponseMessage(HttpStatusCode.OK)
    res.Content = New StringContent(CreateFeed(offset, count), Encoding.UTF8, "application/xml")
    Return res
End Function

今から作成する CreateFeed で XML の文字列を返します。Blog などの普通の(?)RSS フィードとは違って、アプリから Web コミックのデータ取得用にも使いたいので、位置と件数をクエリーで指定できるようにしています。

XML 文書の作成

CreateFeed を実装して、XML 文字列を作ります。フィード内の各項目となるクラスは次のように用意しました。すぱこーを公開するための最低限の内容です。

Model.vb
Public Class ComicItem
    Property Title As String
    Property Description As String
    Property PubDate As DateTime
    Property ModifiedDate As DateTime
    Property Link As String
    Property Id As String
    Property Volume As Integer
    Property IsAvailable As Boolean
    Property MediaUrl As String
    Property ThumbnailUrl As String
    Property Creator As String
    Property Guid As String
End Class

XML 文字列を作る CreateFeed メソッドの内容は次の通り。Web コミックのデータ取得部分は、ここでは扱いません。代わりにダミーを用意します。

SpacoController.vb
Private Function CreateFeed(offset As Integer, count As Integer) As String

    ' ダミーデータ作成
    Dim channelPubDate = Now
    Dim items = New List(Of ComicItem)

    For i = offset + 1 To count
        Dim item = New ComicItem With {
            .Title = "タイトル" & i.ToString,
            .PubDate = Now.AddDays(count - i),
            .ModifiedDate = Now.AddDays(count - i),
            .Link = "http://pronama.jp/?" & i.ToString,
            .Id = i.ToString,
            .Volume = i,
            .IsAvailable = True,
            .MediaUrl = "http://pronama.jp/?media" & i.ToString,
            .ThumbnailUrl = "http://pronama.jp/?thumbnail" & i.ToString,
            .Creator = "Creator",
            .Guid = "http://pronama.jp/?" & i.ToString}

        items.Add(item)
    Next

    ' XDocument 作成
    Dim xml =
    <?xml version="1.0" encoding="UTF-8"?>
    <rss version="2.0"
        xmlns:dc="http://purl.org/dc/elements/1.1/"
        xmlns:dcndl="http://ndl.go.jp/dcndl/terms/"
        xmlns:media="http://search.yahoo.com/mrss/"
        xmlns:p="http://pinga.mu/terms/"
        >
        <channel>
            <title>すぱこー</title>
            <link>https://pronama.jp/tag/spaco/</link>
            <description>高校生の暮井 慧(プロ生ちゃん)と、部活「情報処理研究会」のメンバー 戸増千由莉とフィネス・ヒルヴィレッジが活躍する Web 4コマ漫画「すぱこー」!</description>
            <pubDate><%= channelPubDate.ToString("r") %></pubDate>
            <image>https://pronama.jp/wp-content/uploads/2015/05/spaco_banner.png</image>
            <dc:creator>池村ヒロイチ/プログラミング生放送</dc:creator>
            <%= From i In items
                Select <item>
                            <title><%= i.Title %></title>
                            <dc:creator><%= i.Creator %></dc:creator>
                            <link><%= i.Link %></link>
                            <pubDate><%= i.PubDate.ToString("r") %></pubDate>
                            <description><%= i.Description %></description>
                            <dcndl:volume><%= i.Volume %></dcndl:volume>
                            <dc:modified><%= i.ModifiedDate.ToString("s") %></dc:modified>
                            <p:isAvailable><%= If(i.IsAvailable, "true", "false") %></p:isAvailable>
                            <media:content url=<%= i.MediaUrl %>></media:content>
                            <media:thumbnail url=<%= i.ThumbnailUrl %>></media:thumbnail>
                            <guid isPermaLink="false"><%= i.Guid %></guid>
                        </item>
            %>
        </channel>
    </rss>

    ' XML 文字列を返す
    Return xml.ToString
End Function

XML リテラル と、XML リテラルへの式とクエリーの埋め込み便利すぎでしょ……。上記のように直接コード内に XML を記述でき、変数やループ処理などを埋め込み XML 文書を作れます。RSS 以外の拡張した項目も好きなだけ追加できます。

XML 名前空間は、次のようにファイル冒頭で宣言しておきます。

SpacoController.vb
Imports <xmlns:dc="http://purl.org/dc/elements/1.1/">
Imports <xmlns:dcndl="http://ndl.go.jp/dcndl/terms/">
Imports <xmlns:media="http://search.yahoo.com/mrss/">
Imports <xmlns:p="http://pinga.mu/terms/">

完成

以上で、完成です。

必要に応じて、App_Start/WebApiConfig.vb でルーティングを変更します。規定では http://localhost:****/api/spaco のようにアクセスできます。

feed

http://localhost:****/api/spaco?offset=5&count=10 のようにパラメーターの指定もできます。

出力キャッシュを指定

Nuget で Strathweb.CacheOutput.WebApi2 をインストールすると、ASP.NET MVC の Web API で出力キャッシュが使えます。RSS フィードのように更新頻度が低いものは指定しておくと良いです。

次のように属性を指定します。

SpacoController.vb
<HttpGet>
<CacheOutput(ClientTimeSpan:=100, ServerTimeSpan:=100)>
Public Function GetALl(Optional offset As Integer = 0, Optional count As Integer = 100) As HttpResponseMessage
    ' ...
End Sub

不要なコントローラーやファイルの削除

プロジェクトにはいろいろファイルがありますが、ほとんど未使用です。不要なコントローラーなどは削除しておきましょう。

余談

RSS フィードなど XML の出力は、もちろん今回の内容の方法だけではありません。RSS/Atom を表す SyndicationFeed クラスなども .NET Framework にはあります。