【C#】ASP.NET Core MVCを使ってみよう。-After①-
前回の内容はこちらから。 d01tsumath.hatenablog.com
今回はAfterということで、レビューで修正していただいたところを復習兼ねて投下していきます。
長いので、Before->Afterだけみたいよーって方は以下GitHubをご覧ください。
まずは、HomeController.cs
ファイルから修正していきます。
Before
public IActionResult Index() { string url = @"http://d01tsumath.hatenablog.com/rss"; try { // RSS読み込み XElement element = XElement.Load(url); // channelの取得 XElement channelElement = element.Element("channel"); //itemの取得 IEnumerable<XElement> elementItems = channelElement.Elements("item"); var titleList = new List<Title>(5); for (int i = 0; i < 5; i++) { XElement item = elementItems.ElementAt(i); // 先頭の<link></link>を取り出す var linkText = Regex.Replace(item.Element("link").ToString(), "<[^>]*?>", ""); var title = new Title { Name = item.Element("title").Value, URL = linkText }; titleList.Add(title); } ViewData["titles"] = titleList; } catch (Exception e) { Console.WriteLine(e.Message); } return View(); }
After
まず、RSSフィードの読み込みです。
const string rssFeed = "http://d01tsumath.hatenablog.com/rss"; var element = XElement.Load(rssFeed); var articles = element .Descendants("item") .Select(x => { var title = x.Element("title").Value; var url = x.Element("link").Value; return new Article(title, url); }) .Take(5) .ToArray();
①const string rssFeed = "http://d01tsumath.hatenablog.com/rss";
まず、先頭のurl
は、単純にurl
だと何のURLなのかわからないので、意図がわかる変数名にします。
rssFeed
の値は以後変更されないので定数としてconst
を使うのが無難ですね。
②var articles = element.Descendants("item")
Beforeでは、item
まで2段階経ていますが、ここまでスッキリしました。
Element
は子ノードを取得するのに対し、Descendants
は子孫ノードを取得します。(以下ページ参照)
③
.Select(x => { var title = x.Element("title").Value; var url = x.Element("link").Value; return new Article(title, url); })
Descendants()
の戻り値はIEnumerable<T>
です。
IEnumerable<T>
ということはLinqが使えます。積極的に使っていきたい…!(切実)
Select
でデータを成型します。
new Article()
のArticle
クラスは後ほど作るとして、今必要なのはitem
の中にある 記事タイトル
と 記事のURL
だけなのでitem
からtitle
とurl
のみ取得します。
④.Take(5).ToArray();
課題としてはRSSフィードから5件だけ取得したいので、Take()
で先頭から5つ取ってきて配列にします。
上から〇つなどの条件がある場合は、For文で回して取得するよりTake()
を使えば良い!っていう思考に切り替えていきたいものです。
ここから、非同期処理をプラスしていきます。
ネットワーク通信や読み込み処理などは非同期処理を使うべし!
前職では非同期処理を使わなければならない場面って遭遇しなかったので、C#を書いてても「非同期処理って何w」という状態だったのが正直なところ。
現職に入社して間もなく、有難いことに非同期処理を教えていただいたわけですが、今回の課題にて非同期処理をどう活用すればよいのか学びました。
非同期処理の採用を検討する必要があるシーンには、例えば次のようなものが挙げられる。
・重たい処理をするとき
・ファイルの読み書きやネットワーク通信など、不定な待ち時間が発生する処理をするとき
引用:-第1回 .NET開発における非同期処理の基礎と歴史-
レビューのときにも、詳しく説明してもらったんですが、非同期処理を使うことによって
パフォーマンス(リソース消費)が良くなる
->より複数のリクエスト処理もできるようになる
->結果、アプリケーション全体に無駄がなくなる
ということ(らしい)です。
1つのリクエストをどう処理するかだけでなく、全体のパフォーマンスを上げることも考えていく必要があるんですね~。
では、非同期処理を使うとどう変わっていくのでしょうか…。
public async ValueTask<IActionResult> Index() { const string rssEndpoint = "http://d01tsumath.hatenablog.com/rss"; var client = new HttpClient(); var response = await client.GetAsync(rssEndpoint); var rssFeed = await response.Content.ReadAsStringAsync(); var articles = XElement.Parse(rssFeed) .Descendants("item") .Select(x => { var title = x.Element("title").Value; var url = x.Element("link").Value; return new Article(title, url); }) .Take(5) .ToArray(); return this.View(); }
⑤public async ValueTask<IActionResult> Index()
つい先日Task
/ Task<T>
を使い始めたばかりなのに、ValueTask<T>
出てきた~って思いました(笑)。
Task
/ Task<T>
だと戻り値の型に制約がありますが、ValueTask<T>
はTask型以外の戻り値もOK!
更に、Task
/ Task<T>
は参照型(ヒープ領域を使う!)なのに対して、ValueTask<T>
は値型(スタック領域を使う!)っていう違いもあります。
(ついでに変数名も変わってます…!)
2019.08.23 追記:Task
でも戻り値に制約はないようです…Oh...しかもValueTask
はヒープ領域を使うこともあるようなのでおいおい詳しく学んでいきたいと思います!
⑥
const string rssEndpoint = "http://d01tsumath.hatenablog.com/rss"; var client = new HttpClient(); var response = await client.GetAsync(rssEndpoint); var rssFeed = await response.Content.ReadAsStringAsync();
XElement.Load()
はURL指定してRSSフィードを読み込んでくれるものですが、処理が終わるまで待ち時間が発生してしまいます。
.Load()
の代わりに非同期処理を使ってあげることで、CPUの処理能力を持て余すことがなくなり、通信中他の処理を裁くこともできます。
ちなみに調べてみたところHttpClient
に用意されているメソッドは、全て非同期版だそうです。
次回は、ModelとViewの修正をしていきたいと思います!