読者です 読者をやめる 読者になる 読者になる

だるろぐ

とてもだるだるした日記です http://about.daruyanagi.jp/

お知らせ

WebMatrix:フィードを読み込むときに System.Xml.XmlException が発生する

WebMatrix ASP.net Web Pages

ASP.NET Web Pages 製の BOT が、ある日を境に突然、System.Xml.XmlException エラーを吐くようになった。

The element with name 'RDF' and namespace 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' is not an allowed feed format.

某サイトのリニューアルで、RSS 2.0 が RSS 1.0 になったせいでフィードが読めなくなったらしい/(^o^)\

Classes That Model Syndication Feeds and Items

  • SyndicationFeed - represents a syndication feed. Has properties like Title, Description, Links, and Items. The Items property represents the collection of content items expressed in the feed.
  • SyndicationItem - represents a specific syndication feed item and includes properties like Title, Summary, PublishDate, Authors, and so on.

Classes That Transform Syndication Feeds To/From XML

  • Rss20FeedFormatter - can take a SyndicationFeed object and turn it into XML that conforms to the RSS 2.0 specification. Also, can be used to consume a properly-formatted RSS 2.0 feed, turning the XML into a SyndicationFeed object with its properties set based on the data in the consumed XML.
  • Atom10FeedFormatter - same as the Rss20FeedFormatter, but uses the Atom 1.0 standard.
Syndicating and Consuming RSS 1.0 (RDF) Feeds in ASP.NET 3.5 - 4GuysFromRolla.com

Rss10FeedFormatter は標準で用意されていないみたいなので、自分で実装する必要がある。

幸い、コードが GitHub に転がっていたので拝借(見覚えのあるアイコンの人だなぁ……)。おおきにさんきゅーやで!

f:id:daruyanagi:20160603190721p:plain

これを以下のように呼び出してやれば、解決。めでたしめでたし。

try
{
    feed = SyndicationFeed.Load(reader);
}
catch
{
    // エラーがでたら RSS 1.0 ってことにしておく
    var formatter = new Rss10FeedFormatter();
    formatter.ReadFrom(reader);
    feed = formatter.Feed;
}

WebMatrix:改修工廠の早見表がほしかったので作ってみた

艦これ WebMatrix ASP.net Web Pages

f:id:daruyanagi:20150919201617p:plain

今週は超忙しい&体調がよろしくなかった“ので”、合間を見つけて前々からほしかった改修工廠の早見表を作ってみた。接続詞が間違っているというツッコミが入りそうだけど、こういうのって、そういうときにこそやりたくならない?

最初に作ったヤツ

f:id:daruyanagi:20150919201737p:plain

ASP.NET Web Pages + SQL Server Compact で作ってみたけど、だいぶ遅かった。遅いのは多分、自分が SQL わかってないせいだと思う(SELECT でごっそりとってきたデータを LINQ で加工するとかいうわけのわからないことをやっていた)。SQL が分かんないのは一朝一夕に改善できないので、とりあえずデータベースへの問い合わせ結果をキャッシュしまくってみたけれど、スタートアップの遅さは改善できない。Web サイトがスタンバイ(スリープ? なに?)したら、キャッシュを一から再構築しなきゃいけないのも困った。

――というわけで、廃棄する予定。

二番目に作ったヤツ

f:id:daruyanagi:20150919202146p:plain

で、ちょっと考えてみたんだけど、こういうデータっていうのは稀にあるサーバーのメンテナンスのときにしか更新されないわけだ。だったら、なにもデータベースに入れる必要はなかった(CURD のうち R しかやらへんやん?)。JSON か何かでデータを用意しておいて、サーバーのスタートアップ時に読み込めばいい。

俺ってアホだなーと思いながら、ぐちゃぐちゃっと今日半日で作ったら(ロジック組むより、データ打ち込む方がよっぽど時間かかった)、最初に作ったヤツよりだいぶ早くて満足。コードを整理しながらロジック見直せばもうちょっと早くなりそう。なんせ今のは cshtml に foreach が腐るほど埋まってるという正真正銘のクソコードだし……ちょうどいいから今度 GitHub にあげて、GitHub Flow ってのを勉強するネタにしようと思う。

ほんとうはこれを Windows Phone に移植しておでコンに出したかったけれど、いつの間にか締め切り過ぎてたみたい。残念。艦これ Android 版が出るらしいし、Android アプリにするのもアリかなぁ? 

WebMatrix: URL にドットを含めたい

WebMatrix ASP.net Web Pages

f:id:daruyanagi:20150913032211p:plain

Wiki エンジンなんかを作るときなど、「ドット(.)」を URL に含めたい場合は、Web.config に一行、以下のように加えるといいみたい。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />
    </system.webServer>
</configuration>

静的リソースまでアプリケーションで処理するようになる(?)ので、効率が悪そうだけど。もっとちゃんと対策したければ、以下の URL が参考になりそう。

お前ら喜べ! Windows 10 でも WebMatrix が使えるぞ!!

WebMatrix

f:id:daruyanagi:20150707204808p:plain

@shibayan からもたらされた極秘情報によると、6月30日に WebMatrix 3.1 がリリースされていたらしい。


変更点が相変わらずよくわからなかったので、その日はそのまま寝て、このこともすっかり忘れていたのだけど、ふと思い立って Windows 10 にインストールしてみたところ……

f:id:daruyanagi:20150707205443p:plainf:id:daruyanagi:20150707205450p:plainf:id:daruyanagi:20150707205447p:plainf:id:daruyanagi:20150707205454p:plainf:id:daruyanagi:20150707205502p:plain

キタ━(゚∀゚)━(∀゚ )━(゚  )━(  )━(  )━(  ゚)━( ゚∀)━(゚∀゚)━!!

ちょっと端っこが欠けてるような気がするけど、きっと気にしたら負けだ!! ちゃんと息をしてくれているだけで、おじさんは満足です。これでいちいちわざわざゴニャゴニャしなくても、Windows 10 でちゃんと WebMatrix がインストールできる!

みんな大好き Visual Basic 6 ともども、Windows 10 でも WebMatrix をよろしくお願いいたします(^v^)ノ

おまけ

f:id:daruyanagi:20150707205943p:plain

もしお手すきでしたらこれも直していただければ幸いです(`・ω・́)ゝ

WebMatrix:フィードを読み込んでデータベースへつっこむときに System.Data.SqlServerCe.SqlCeException が発生する。

WebMatrix ASP.net Web Pages SQL CE

だいぶ悩んで、Visual Studio まで立ち上げていろいろデバッグしていたのだけど、原因は簡単だった。

datetime

300 分の 1 秒、つまり 3.33 ミリ秒の精度で、1753 年 1 月 1 日から 9999 年 12 月 31 日までの日付と時刻のデータを格納するデータ型です。値は .000、.003、または .007 ミリ秒の単位になるように丸められます。

2 つの 4 バイト整数として格納されます。最初の 4 バイトは、base date である 1900 年 1 月 1 日からの日数、またはこの日までの日数を格納します。基準日とは、システムが参照する日付です。datetime 型の値には、1753 年 1 月 1 日より前の日付を使用できません。もう一方の 4 バイトは、午前 0 時から数えた時間をミリ秒単位で格納します。秒の有効範囲は 0 から 59 までです。

データ型

f:id:daruyanagi:20150625045042p:plain

一方、C# の default(DateTime)0001/01/01 0:00:00。つまり、SyndicationFeed オブジェクトの LastUpdateTime プロパティあたりにちゃんと値がセットされてなくて(そういうフィードを配信しているサイトは割とある)、default(DateTime) を返してくるとき、それをそのまま SQL CE データベースに格納しようとするとエラーになる。

f:id:daruyanagi:20150625050249p:plain

SQL CE の datetime 型を扱う場合は、事前に値の範囲に収まるかチェックして、ダメな場合はハネておかないといけないんだね。

var min_date = new DateTime(1753, 1, 1); // ほんとは readonly でどこかに
var updated_at = item.LastUpdatedTime.UtcDateTime < min_date 
    ? new DateTimeOffset(DateTime.Now).UtcDateTime 
    : item.LastUpdatedTime.UtcDateTime;

// Database.Execute();

教訓

ちゃんとマニュアルは読もう。

先生助けてっ! WebMatrix ちゃんが息をしてないのっっ!!

WebMatrix

f:id:daruyanagi:20150428022417p:plain

WebMatrix 3 does not support IIS Express 10. You will not be able to run WebMatrix 3 on the same machine with any version of Visual Studio 2015 that includes IIS Express 10

とうとうこの日が来たかーって感じですね! 一応、IIS Express 10 に対応した WebMatrix(WebMatrix 4)がリリースされるという可能性もなきにしもあらずですが、あんまり期待はもてなさそう。また、Visual Studio 2015 を使わないという手もありますが……WebMatrix と Visual Studio だったら Visual Studio 選びますわな。

まぁ、でも、WebMatrix のおかげでいろいろ楽しかったです。Visual Studio がジェット戦闘機ならば、WebMatrix はレシプロ複葉機みたいなもんですが、自分みたいな趣味として片手間で触るような人間にはぴったりでした。入門向けとしてはなかなかいいツールではないかと思うのですが、あんまり普及しなくて残念です。

というわけで、完全に死んだ頃を見計らってお葬式イベントでもやりたいと思います。

追伸

これで WebMatrix とかを完全に捨てられますね!

Monaco上のファイルを一括ダウンロードする - xin9le.net

ぐぬぬ(^v^)

WebMatrix: 伊予鉄も止まったので、早速、遅延情報をゲットしてみる。

WebMatrix

f:id:daruyanagi:20150126102626p:plain

WebMatrix: JR四国が止まったので、運行情報の取得プログラム作るのが捗った。 - だるろぐ で喜んでたら、今朝は伊予鉄にも遅れが出た。これで、伊予鉄の運行情報もとれるぞ!

伊予鉄の運行情報ページの構造は、

<p class="about">電車・バス 現在通常通り運行しております。</p>
<p class="date">2015/01/26(月) 10:26</p>

<!-- 遅延がある場合だけ↓ -->
<table class=default>
:
:
</table>

こんな感じになってるみたい。ということは、このテーブルがある前提で遅延情報を解析・出力、途中で例外が発生すれば正常運行とみなすという方針でよさそうだ。

public static List<DelayInfo> GetIyotestu()
{
    const string name = "伊予鉄";
    const string url = "http://www.iyotetsu.co.jp/kinkyu/";

    return GetDelayInfo(name, url, Encoding.UTF8, _ => 
    {
        var doc = new HtmlAgilityPack.HtmlDocument();

        doc.LoadHtml(_);

        try
        {
            // 遅延情報のテーブルを取得。発見できなければ例外 → 正常運行
            var rows = doc
                .DocumentNode
                // table.default のなかにある tr タグを取得
                .SelectNodes(@"//table[@class=""default""]//tr")
                // テキストノードなどは読み飛ばす
                .Where(n => n.NodeType == HtmlNodeType.Element);

            var result = new List<DelayInfo>();

            foreach (var row in rows)
            {
                var td = row.ChildNodes
                    // テキストノードなどは読み飛ばす
                    .Where(n => n.NodeType == HtmlNodeType.Element)
                    // セルの結合があるので、ほしい情報のインデックスが列によって違う!
                    // → 後ろから読む
                    .Reverse() 
                    .ToList();

                result.Add(
                    new DelayInfo()
                    {
                        Line = td[1].InnerHtml,
                        Status = td[0].InnerHtml.IndexOf("通常運行") < 0
                            ? "運休・遅延あり"
                            : "正常運行",
                        Message = td[0].InnerHtml,
                    }
                );
            }

            return result;
        }
        catch
        {
            // p.about の内容を解析して、正常運行というデータを返す    
            var text = doc.DocumentNode
                .SelectSingleNode(@"//p[@class=""about""]")
                .InnerText;
            var line = text.Split(' ')[0];
            var message = text.Split(' ')[1];
            return new List<DelayInfo>()
            {
                new DelayInfo()
                {
                    Line = line,
                    Status = "正常運行",
                    Message = message,
                },
            };
        }
    });
}

GetDelayInfo(name, url, encodsing, processor) は、指定した URL からソースコードの取得を取得するもので、キャッシュを Get/Set も行う(定型処理なので分離した)。HTML の解釈を string processor(string src) に委譲しているので、今回はその中身だけを書けばよい。

とくに難しいことはないのだけど、ただ一点、テーブルのセルがところどころ結合されている関係で、列によって取得したい情報のセルのインデックスがずれる。しかし、後ろから数えた場合のインデックスは変わらないので、Reverse() してから読んでやればいい。

f:id:daruyanagi:20150126104125p:plain

これで数日様子を見てみる。