Quantcast
Channel: miso_soup3 Blog
Viewing all 96 articles
Browse latest View live

Umbraco as a Service を試した

$
0
0

Umbraco とは、ASP.NET で作られた OSS な CMS ですが、それの SaaS 版があったので試してみました。

機能については、http://umbraco.com/cloudこちらにビデオや説明があります。

適当に挙げてみると、以下のような感じです。

  • Umbraco CMS のホスト
  • 14 日間無料で試せる。Standard プランは €89/month~
  • Umbraco CMS の自動バージョンアップ
  • ストレージ、帯域幅の制限なし
  • Dev 環境、Production 環境(+ Staging 環境)が用意され、それぞれに Git Repository が付く。
    • Dev 環境では Basic 認証が基本でつく。
    • ローカル環境で試すことも可能。Visual Studio 使うのもできる。ローカルで編集して Git でコミットとかもできる。
  • ドメイン、SSL、IP アドレス制限。
  • たぶん Azure 上で動いてる。Azure SQL Dabase を使うこともできる。

f:id:miso_soup3:20151207212444p:plain
https://our.umbraco.org/documentation/Umbraco-as-a-Service/より)

簡単に試してみて、1ページ分サイトを作ってみます。

目次

リンク

サインアップ

http://umbraco.com/cloudここにメールアドレスを入力するところがあるので、入力します。
受け取ったメールから、パスワードを登録し、アカウントを作成します。メールアドレスとパスワードは、この後の手順で必要になるので覚えておきます。

プロジェクトの作成

https://www.s1.umbraco.io/projects管理画面にアクセスし、プロジェクトを 1 つ作成します。
画像のように「Development」と「Live」の 2 つの環境が用意されます。

f:id:miso_soup3:20151207212646p:plain

「Live」は Production 環境のようなものです。まずは、Dev 環境で Umbraco の管理画面からサイトを構成し、それを Live 環境へ反映させ、サイトを確認してみます。

Development の Umbraco 管理画面へ

各環境には、Git Repository が用意されているので「Get clone url」からクローンできます。必須ではありませんが、ここで、Development の Git Repository を clone しておきます(サイズが大きく時間がかかるので注意)。

f:id:miso_soup3:20151207212646p:plain

次に Development の「Go to backoffice」から、Umbraco の管理画面へアクセスします。
基本認証の後、Umbraco の管理画面のログイン画面が表示されますので、先ほど登録したアカウントの情報を 2 回入力することになります。

f:id:miso_soup3:20151207213547p:plain

f:id:miso_soup3:20151207213557p:plain

f:id:miso_soup3:20151207213723p:plain
Umbraco の管理画面。

1 ページ作成してみます。例として"プロフィール"ページを作成し、そこに名前・誕生日・コメント欄の項目を用意し、管理画面で入力した値がページに表示されるようにしてみます。

手順は、1:ページにどんな項目を用意するかを定義する "Document Type"を作成し、そこに名前・誕生日・コメントの項目(=Property)を設定。2:ページをどのような Html にするか "Template"を作成。3:定義した項目に値を入力し、実際にページを用意(= "Content"を作成)、といった流れになります。

出来上がりのサイトはこんな感じ。

f:id:miso_soup3:20151207225029p:plain

1:Document Type を作成

Document Type を作成し、ページがどのような Property を持っているか等を定義します。

Dev 環境 の Umbraco 管理画面から、「Settings」->「Document Types」->「Create」で Document Type を作成します。

f:id:miso_soup3:20151207214323p:plain

下の画像のように Name 欄に Profile と入力し、Create をクリック。「Create matching template」にはチェックを入れてください。これは、同じ名前で Template も作成する、という意味です。

f:id:miso_soup3:20151207214452p:plain

作成した Document Type の編集画面が表示されます。「Generic properties」のタブをクリックし、「Click here to add new property」をクリックします。

f:id:miso_soup3:20151207214711p:plain

下の画像のように入力し、Name 項目を定義します。

f:id:miso_soup3:20151207215008p:plain

Name は人が識別するための表示名、Alias は Template などでプログラミング上で使う識別名、Type は項目の種類(Dropdown とか Checkbox とかあります)。Tab は管理画面のどのタブのページに表示させるか、Mandary は必須項目かどうか、Validation は値の検証文字列、Description は管理画面上に表示させる項目の説明文を入力します。

ここでは、Name と Alias と Type だけ指定し、他はデフォルトのままとします。

入力した後は、右上の「Save」をクリックし、1 つの項目(Property)の登録を完了します。

f:id:miso_soup3:20151207215434p:plain

同じような手順を繰り返し、次のように項目(Property)を作成します。

  • 誕生日
    • Name : Birthday
    • Alias : birthday
    • Type : Date Picker
  • ブログ URL
    • Name : BlogUrl
    • Alias : blogurl
    • Type : Textstring
  • コメント
    • Name : FreeComment
    • Alias : freecomment
    • Type : Rithtext editor

作成後、以下のように表示されているはずです。

f:id:miso_soup3:20151207215736p:plain

次に、「Structure」タブで、「Allow at root」にチェックを入れます。

f:id:miso_soup3:20151207215931p:plain

これは、サイトの Root にこの Document Type で構成されたコンテンツを配置するかどうか、という意味です。
今はプロフィールページを 1 つだけ置くので、ここにチェックを入れないとプロフィールページを用意できません。一般的にここには、「Home」や「Index」といった名前でサイトのトップページの Document Type を指定することになります。

2:Template を作成

Template を作成し、HTML を用意します。また、ここでは CSS ファイルを使うので CSS ファイルを登録します。CSS ファイルは bootstrap のものを使うことにします。

bootstrapのサイトからダウンロードし、「bootstrap.css」を準備します。

Umbraco 管理画面にて、↓下の画像のように「Settings」->「Stylesheets」->「Create」をクリックします。

f:id:miso_soup3:20151207220453p:plain

Name に 「bootstrap.css」を入力し、「Create」。

f:id:miso_soup3:20151207220748p:plain

先ほど bootstrap から取得してきた 「bootstrap.css」の中身をコピペし、右上の「Save」ボタンをクリックします。これで CSS ファイルの用意ができました。

次に、Template を作成します。だいたいのサイトは、マスターページを使うことが多いと思いますので、ここでもマスターページである「_Layout」とプロフィールページの「Profile」と 2 つの Template を作成します。

Document Type を作成した時に、Profile という Template が作成されたかと思いますが、もし作成されていない場合は次のように追加します。

「Settings」->「Templates」->「Create」をクリックします。

f:id:miso_soup3:20151207221041p:plain

Name は、「Profile」とします。

「Profile」の中身は、下のコードをコピーし、右上の「Save」ボタンをクリックします。

Profile:

@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
    Layout = "_Layout.cshtml";
}

<divclass="container"><divclass="page-header"><h1>@Umbraco.Field("name")</h1></div><p>birthday : @Umbraco.Field("birthday", formatAsDate: true)</p><p>blogurl : @Umbraco.Field("blogurl")</p><divclass="lead">
		@Umbraco.Field("freecomment")
	</div></div>

f:id:miso_soup3:20151207221408p:plain

同じ方法で、「_Layout」という名前の template を作成します。

_Layout:

@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
    Layout = null;
}

<!DOCTYPE html><htmllang="ja"><head><metacharset="utf-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width, initial-scale=1"><!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --><title>Bootstrap 101 Template</title><!-- Bootstrap --><linkhref="css/bootstrap.css"rel="stylesheet"><!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --><!-- WARNING: Respond.js doesn't work if you view the page via file:// --><!--[if lt IE 9]><script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script><script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script><![endif]--></head><body>
		@RenderBody()
  </body></html>

右上の「Save」をクリックし保存します。

(ここで Template に書いたコードは、ASP.NET MVC の Razor と同じ記法になります。マスターページである _Layout の参照も同じです。 )

3:Content を作成

ここまで作成した Template と Document Type を使い、実際にページを用意します(=Content を作成)。

Umbraco 管理画面から「Content」->「Content の横の…」->「Profile」をクリックします。

f:id:miso_soup3:20151207222257p:plain

Content の編集ページが開きます。一番上にある入力欄に「Profile」と入力し、後は画像の様に適当な値を入れて、「Save and publish」をクリックします。

f:id:miso_soup3:20151207222653p:plain

作成した Content のページを確認するには、Content の編集ページにある「Link to document」をクリックします。

f:id:miso_soup3:20151207222857p:plain

ブラウザから確認すると以下のように表示されます。

f:id:miso_soup3:20151207223103p:plain

Live(Production) 環境への反映

Dev 環境にてサイトが出来上がったところで、Live 環境へ反映してみます。

Umbraco as a Service の管理画面へ戻り、「Deploy * COMMITS TO LIVE」ボタンをクリックします。

f:id:miso_soup3:20151207223319p:plain

"Completed"と表示された後、Live 環境の「View Page」からサイトを確認してもプロフィールのページは用意されておりません。Live 環境に push されたのは、Document Type や Template 等のみであって、Content は作成されていないからです。

同じく Live 環境の「Go To backoffice」をクリックし、先ほどの「3:Content を作成」と同じように、Content を作成します。Dev 環境と区別するために、違う値で入力してみます。

Live 環境でも Dev 環境と同じように内容を確認することができます。

f:id:miso_soup3:20151207223956p:plain

Dev 環境の Git Repository を Clone した方は、ここで pull してみてください。作業の内容が Git commit されていることが確認できます。

f:id:miso_soup3:20151207224129p:plain
(一つ一つの操作が Git commit されていて OK かどうかは置いておいて)

Repository にあるファイルは、↓のように Umbraco CMS の構成ファイルと同じものです。

f:id:miso_soup3:20151207225849p:plain

Views ファイルに、Umbraco 管理画面で作成した Template が追加されています。

f:id:miso_soup3:20151207225937p:plain

例えば、ローカルで Visual Studio でこのプロジェクトを開いて、.cshtml を編集したり、CSS を登録したりし、commit -> Live 環境へ push、といったこともできるわけです。
ちなみにデータベースは、デフォルトでは SQL Server Compact(.sdf ファイル)になっています。

まとめ

Umbraco as a Service の 試用版を使って 1 つページを作ってみました。
Umbraco CMS を作成した際は必要になるであろう、Umbraco CMS のバージョンアップグレード、Git 管理、複数環境の用意、Dev は Basic 認証で Private に公開に~といったことが、これ 1 つでできました。


Visual Studio Code で C# script を書く

$
0
0

これは dots girl Advent Calendar 2015に投稿した記事です。

Visual Studio Code にて C# を script として 書いて実行できる拡張機能を紹介します。
この拡張機能は、scriptcs を Visual Studio Code で実行できるようにしたものです。

f:id:miso_soup3:20151215004643p:plain

環境は Mac OS X でやってみます。

  • Mac OS X
  • Visual Studio Code Beta 0.10.3
  • scriptcs 0.15.3
Visual Studio Code のインストール

https://code.visualstudio.com/こちらから Visual Studio Code をインストールします。Visual Studio Code とは、Windows, Linux, Mac で動作するエディターです。

scriptcs

scriptcs のインストールが必要です。以下のサイト等を参考し、まずはコマンドラインで scriptcs を実行できるようにします。

scriptcs
Console.WriteLine("hello, scriptcs");

f:id:miso_soup3:20151215005036p:plain

Visual Studio Code で、拡張機能をインストール

Visual Studio Code で、「scriptcsRunner」拡張機能をインストールします。

Visual Studio Code にて、F1 キーを押し、「install ex」とタイプ。install extension を選択します。
f:id:miso_soup3:20151215005525p:plain
次に、「scriptcs」とタイプし、scriptRunner を選択。
f:id:miso_soup3:20151215005603p:plain

これでインストール操作は終了です。
(Sublime Text や Atom と他のエディタでも scriptcs を実行できる拡張機能があります。)

C# script を書いて実行

Visual Studio Code にて、「File -> Open...」から適当なフォルダを選択(または作成して選択)します。
次の2つのファイルを作成し、下のようにコードを書きます。
・book.csx
・script.csx

f:id:miso_soup3:20151215010002p:plain

book.csx :

publicclass Book
{
	publicstring Title { get; set; }
}

script.csx :

#load book.csx

Console.WriteLine("Hello,world");

privatestring GetMessage(string userName)
{
	return"Hi, " + userName + ".";
}

var userName = "Hana";
Console.WriteLine(GetMessage(userName));

var book = new Book() { Title = "book-title" };
Console.WriteLine(book.Title);

script.csx を開き、cmd + shift + R(または F1 おして、「execute with scriptcs」をタイプ&選択)で、スクリプトファイル全体を実行します。
output が開き、次のように出力されるはずです。

f:id:miso_soup3:20151215010312p:plain

最後に

scriptcs とこの拡張機能はコミュニティにより開発されています。
現在 scriptcs で参照している Roslyn は古いものですが、Roadmapに今後の予定がドラフトとして書かれています。

tips サイドバーに tumblr を表示

$
0
0

このはてなブログのサイドバーに tumblr を表示してみました。

http://miso-soup3.tumblr.com/

コード

参考サイト:
簡単!RSS(XML)を取得&表示させる方法 – jQuery + Google Feed APIを使用してFeedを表示させる方法 | Stronghold
Google Feed API Developer's Guide  |  Google Feed API  |  Google Developers

コードは、はてなの設定>詳細設定から head 内に以下のコードを。

<scriptsrc="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.4.min.js"></script><scripttype="text/javascript"src="https://www.google.com/jsapi"></script><scripttype="text/javascript">var todayDate = newDate().getDate();    google.load("feeds", "1");function initialize(){var feedurl = "http://miso-soup3.tumblr.com/rss/?t=" + todayDate;var feed = new google.feeds.Feed(feedurl);	    feed.setNumEntries(15);	    feed.load(function(result){if(!result.error){for(var i = 0; i < result.feed.entries.length; i++){var entry = result.feed.entries[i];var conte = '<li>' + entry.content + '</li>';var categories = entry.categories;var category = '';if(categories.length != 0){				        category = categories[0];}if(category.toLowerCase() == "note"){continue;}var Dates = newDate(entry.publishedDate);var Dday = Dates.getDate();var Dmonth = Dates.getMonth() + 1;var Dyear = Dates.getFullYear();var Ddates = '<li class="tdate">' + Dyear + '-' + Dmonth + '-' + Dday + '</li>';				    $('#tumblr-feed').append('<li class="post"><ul>' + Ddates + conte + '</ul></li>');}}});}    google.setOnLoadCallback(initialize);</script>

ノートのようなものは長文になるので表示したくなく、category の値を見て除外。

次に、はてなのデザイン設定から、HTML を挿入するサイドバーを作成し、以下の要素を貼り付け。

<ulid="tumblr-feed"></ul>

ASP.NET Web API OData で enum はどのように表現されるか

$
0
0

ASP.NET Web API OData で、enum の値や定義はどのように表現されるか確認しました。
結果は、出力の方はもちろんどちらも可能で、enum の定義(とある enum はどのような列挙子をもつか)は、v4 では対応しているようでした。

Getting started with ASP.NET Web API 2.2 for OData v4.0この記事に v4 から enum サポートしたよーと書いてあります。

Support for enums

We already had support for enums in Web API OData v3.0 by serializing them as strings, but the new version of the protocol has added full support for them, so we have upgraded our enum support accordingly. In order to use enums you just need to define a property with an enum type and we’ll represent it as an enum in the $metadata and the clients will able to use enum query operators in $filter clauses. There are
also specific overloads on the model builder in case we want to configure the enumeration explicitly.

以下は試したときの手順です。

OData エンドポイントを用意して試してみる

まずは、以下のようなクラスと enum を用意します。Product の ColorType プロパティを enum で定義しました。

namespace ODataenumSample.Models
{
    publicenum ColorType
    {
        Red = 0,
        Blue = 1,
        Green = 2,
    }

    publicclass Product
    {
        publicint Id { get; set; }
        publicstring Name { get; set; }
        publicdecimal Price { get; set; }
        publicstring Category { get; set; }

        public ColorType ColorType { get; set; }
    }
}

このモデルを使い、v3 と v4 の両方で OData のエンドポイントを ASP.NET Web API Odata を使って用意します。
手順は以下のサイトのチュートリアルを参照しました。サンプルデータを Code First で用意します。

v4 : Create an OData v4 Endpoint Using ASP.NET Web API 2.2
v3 : Creating an OData v3 Endpoint with Web API 2
Code First を使った初期データの用意:Use Code First Migrations to Seed the Database

v3 と v4 で微妙にコードが違うので注意が必要です。

補足情報:

・ASP.NET Web API は 2.2 から、OData v4 に対応しました。
・Visual Studio 2015 Update 1 では、v4 OData スキャフォールディングが用意されておりません。なので、拡張機能 OData v4 Web API Scaffoldingを使いました。
・もしエラーが起きた場合はこちらの記事が参考になるかもしれません。

v4 の方では、下のように WebApiConfig.cs を記述します。v3 の方もメソッド名等が違うだけでほとんど変わりません。

ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");

config.MapODataServiceRoute(
  routeName:"ODataRoute",
  routePrefix:"odata",
  model: builder.GetEdmModel());
$metadata

用意した OData の $metadata を確認したものが下の画像です。上が v4 で下が v3。v4 の方には enum ColorType の列挙子があることがわかります。

f:id:miso_soup3:20160106193125p:plain

v3 で enum の定義を $metadata に含めることはできるのか?

Tutorial & Sample Use enumeration types in OData

こちらの記事を見るとできそうだったのですが、EdmModel を自分で作り上げる必要があり面倒?そうだったので、確認はしておりません。

クライアントでは

v4 の方に enum の定義があることを確認できたので、クライアントコードを自動生成したら enum も作ってくれるのではーと思い試してみました。

OData v4 のクライアントコード生成は、こちらの記事を参照します。
WEB API ODATA V4 USING AN ODATA T4 GENERATED CLIENT PART 8

記事にある通り、「OData v4 Client Code Generator」の拡張機能をインストールし、「OData Client」の .tt ファイルを追加します。次に、nuget で「Micorosft.OData.Client」をインストール。
先ほど用意した OData v4 エンドポイントのプロジェクトの方を立ち上げておき、MetadataDocumentUri に URL を入力し、.tt ファイルを実行しコードを生成します。

自動生成されたコードをのぞいてみると…enum がありました。

f:id:miso_soup3:20160106194209p:plain

↓のようにクライアント側のコードを書いて、OData でデータを取得できます。

class Program
{
    staticvoid Main(string[] args)
    {
        var context = new Container(new Uri("http://localhost:16334/odata/"));
            
        foreach(var product in context.Products)
        {
            if (product.ColorType == ODataenumSample.Models.ColorType.Red)
            {
                Console.WriteLine("Redです");
            }
            Console.WriteLine($"{product.Name} {product.Category} {product.ColorType}");
        }

    }
}

f:id:miso_soup3:20160106194259p:plain

Visual Studio 拡張機能、Web Extension Pack リスト

$
0
0

Mads Kristensen 氏が、Web 開発のための Visual Studio 拡張機能をまとめた Web Extension Packを公開しています。
どのような拡張機能が含まれているのか、調べてみました。

~~~~
※Web Extension Packは VS 起動の際、新しい拡張機能があれば自動でインストールされます。
そのため、含まれる拡張機能の内容が随時変わる可能性があります。下記のリストは古い可能性があるため、最新については上記ページを参照します。
この機能を入れてほしい、といったものがあれば、https://github.com/madskristensen/WebExtensionPack/issuesに投げればいい模様。
~~~~
※2016/03/29 Mads Kristensesn 氏による Channel 9 の動画が公開されています。
Web Extension Pack | Visual Studio Toolbox | Channel 9 https://channel9.msdn.com/Shows/Visual-Studio-Toolbox/Web-Extension-Pack
~~~~

それぞれについて一言:

(2015/1/14 追加)

それぞれのページに一目でわかる画像や説明がありますので、ここではさらりと紹介します。

Bootstrap Snippet Pack

https://visualstudiogallery.msdn.microsoft.com/e82e7862-f731-4183-a27a-3a44b261bfe5

HTML, CSS, JS のフレームワークである Bootstrapの HTML のスニペット。

例えば、HTMLファイルにて「bs-accordion」とタイプし Tab を押せば、アコーディオンのテンプレートが展開されます。

f:id:miso_soup3:20160108171220p:plain

スニペット一覧は、
https://github.com/elebetsamer/bootstrap-snippets-visual-studio/blob/master/snippet-listing.md
ここから確認できます。

ちなみに Visual Studio 2015 に登録されているスニペットを確認するには、ツール>コード スニペット マネージャ を開きます。

Bowser sync

https://visualstudiogallery.msdn.microsoft.com/5741a548-5179-4a77-ad96-fca71535774d

ASP.NET のプロジェクトのデバッグ時に、フォームの入力・スクロール・ページ遷移が全ブラウザで同期されるというもの。
上記サイトのgifを見れば一目瞭然です。例えば、複数のブラウザを立ち上げ、IEにて「登録」ページに遷移し、Ctrl + Alt + Enter を押すと、すべてのブラウザが同じページに遷移します。

機能
・すべてのブラウザとエミュレーターに対応
・フォームへの入力がすべてのブラウザで同期される
・hotkey(Ctrl + Alt + Enter) ですべてのブラウザが同じ URL に遷移
・hotkey でスクロールポジションを同期
・有効/無効の切り替え


この機能は Brower Link 上で働きます。Browser Link は Visual Studio 2013 からあるものです。
詳しくはこちらをどうぞ。クロスブラウザのテストに Visual Studio 2013 のブラウザー リンクをどうぞ

Glyphfriend

https://visualstudiogallery.msdn.microsoft.com/5fd24afb-b3b2-4cec-9b03-1cfcec6123aa

グリフが多いWebフォント(Font Awesome等のようなWebフォントでアイコンを表示するもの)のインテリセンスと、アイコンのプレビューを提供します。
対応しているのは以下のものです。

例えば、Visual Studio 2015 の ASP.NET MVC のプロジェクトテンプレートには、Bootstrap Glyphicons のライブラリが含まれています。
HTML ファイル等でタイプすると、以下のようにインテリセンスとアイコンのプレビューが表示されます。

f:id:miso_soup3:20160108171229p:plain

このインテリセンスを使用するには、あらかじめプロジェクトに使用するフォントのライブラリが含まれている必要があります。
例えば、Font Awesome のインテリセンスを使用したい場合はプロジェクトにFont Awesomeのライブラリを追加することで、下の画像のように表示されます。

f:id:miso_soup3:20160108171234p:plain

Image Optimizer

https://visualstudiogallery.msdn.microsoft.com/a56eddd3-d79b-48ac-8c8f-2db06ade77c3

右クリックから画像 JPEG, PNG, Gif を圧縮する拡張機能。

ソリューションエクスプローラーから、画像を右クリック→ Optimize image をクリックすると画像が圧縮されます。
圧縮してみると、出力ウィンドウにこのように出力されました。

2016/01/07 18:00:39: Optimized a0002_012117.jpg
Before: 56108 bytes
After: 51542 bytes
Saving: 4566 bytes / 8.1%

NPM Scripts Task Runner

https://visualstudiogallery.msdn.microsoft.com/8f2f2cbc-4da5-43ba-9de2-c9d08ade4941

package.json にある script セクション内にあるタスクを Task Runner Explorer に追加する拡張機能。

package.json を右クリックし、「タスクランナーエクスプローラー」を選択すると、下のようにウィンドウにて表示され、タスクの実行を管理できます。

f:id:miso_soup3:20160108172039p:plain

注意:
現在、Visual Studio 2015 で ASP.NET 5 のプロジェクトを開くと、ソリューションエクスプローラーにて bower.json, package.json が表示されません。
実際のフォルダには存在しており、「すべてのファイルを表示」から表示させることができます。

また、2016-1-6 に公開された記事Task runners in Visual Studio 2015
を見ると、いろいろ Task Runner Explorer に集約されそうです。

Open command Line

https://visualstudiogallery.msdn.microsoft.com/4e84e2cf-2d6b-472a-b1e2-b84932511379

Visual Studio からプロジェクトファイルの場所をコマンドラインで簡単に開くツール。PowerShell やカスタムツールも設定できます。

2015年1月に、Scott Hanselman 氏のブログでも取り上げられました。Quake Mode Console for Visual Studio - Open a Command Prompt with a hotkey

Package Installer

https://visualstudiogallery.msdn.microsoft.com/753b9720-1638-4f9a-ad8d-2c45a410fd74

Bower, npm, JSPM, TSD (DefinatelyTyped), NuGet のパッケージをお手軽にインストールできる拡張機能。

ソリューションエクスプローラーにてプロジェクトを右クリックし、「Quick Install Package」を選択すると下のようなウィンドウが表示されます。

f:id:miso_soup3:20160108171244p:plain

が、私の環境では VS が即落ちしました。何か必要なのでしょうか。

Web Analyzer

https://visualstudiogallery.msdn.microsoft.com/6edc26d4-47d8-4987-82ee-7c820d79be1d

Visual Studio にて、JavaSciprt、TypeScript、JSX、CSS 等の静的チェックをする拡張機能。他、CoffeScript、CSSLint、ESLint、CoffeLint、TSLint にも対応している模様。

Web Compiler

https://visualstudiogallery.msdn.microsoft.com/3b329021-cd7a-4a01-86fc-714c2d05bb6c

LESS, Sass, JSX, ES6, CoffeeScript をコンパイルする拡張機能。

以前書いた VS2015 拡張機能による JS/CSS/LESS 等の Bundle, Minify, Compile についてに試したときの様子があります。

Web Essentials 2015.1

https://visualstudiogallery.msdn.microsoft.com/ee6e6d8c-c837-41fb-886a-6b50ae2d06a2

数年前からある Visual Studio で Web 開発をするなら絶対いれておくべきな Web Essentials。フロントを中心に多くの機能があります。詳細は公式サイトから確認できます。

最後に

以上、さらりと Web Extension Pack が含む拡張機能を調べてみました。個人的にはBundler & Minifierも含まれてほしいですがキリが無いですし、別途インストすればOKかなと。
ほとんどの作成者が Mads Kristensen 氏でした。Visual Studio で Web 関連の拡張ツールを探すときは、作成者=Mads Kristensen氏 でフィルタリングして探すのが良さそうです。

また、Task runners in Visual Studio 2015より、Task Runner の拡張機能も気になるところです。

Azure WebJobs エラー MSB4062: "ReadWebJobConfigFile"

$
0
0

Azure WebJobs デプロイ時にエラーが発生したのでメモ。

数か月前に作成した Web Job をデプロイしようとしたところ、以下のようなエラーが発生しデプロイできませんでした。

C:\Users\hogehoge\SharedPackages\Microsoft.Web.WebJobs.Publish.1.0.5\tools\webjobs.console.targets(100,5): エラー MSB4062: "ReadWebJobConfigFile" タスクをアセンブリ C:\Users\hogehoge\Microsoft.Web.WebJobs.Publish.1.0.5\tools\Microsoft.Web.WebJobs.Publish.Tasks.dll から読み込めませんでした。ファイルまたはアセンブリ 'Microsoft.Web.WebJobs.Publish.Tasks, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'、またはその依存関係の 1 つが読み込めませんでした。厳密な名前の検証に失敗しました。 (HRESULT からの例外:0x8013141A) <UsingTask> 宣言が正しいこと、アセンブリとその依存関係が使用可能であること、および Microsoft.Build.Framework.ITask を実装するパブリック クラスがタスクに含まれていることを確認してください。

https://azure.microsoft.com/en-us/documentation/articles/websites-dotnet-deploy-webjobs/
ここのコメント欄より、Nuget Package「Microsoft.Web.WebJobs.Publish」を最新にアップデートしましたが、直らず。
参照設定を確認したり、Visual Studio を再起動していたりするといつの間にか直りました。

アップデートする前:<package id="Microsoft.Web.WebJobs.Publish" version="1.0.5" targetFramework="net452" />
アップデート後:<package id="Microsoft.Web.WebJobs.Publish" version="1.0.9" targetFramework="net452" />
環境:Visual Studio 2015.1, Azure SDK 1.8, .NET 4.5.2

パッケージが古いとか、settings.jobの有無でいろいろ試してみましたが再現はできず。

Chrome で Push API を試す

$
0
0

2015年4月にリリースされた Chrome 42 で可能になったという、”ブラウザを閉じていても届くプッシュ通知”というものを試してみました。

「Google Chrome 42」安定版リリース プッシュ通知機能追加と45件の脆弱性対処

※正式版ではないので以下の内容は間違っている可能性があります。

実装方法はググるとたくさんの記事がでてきます。この記事では試したときのメモを。

使用するものは、

  • Google Cloud Messaging (Android、iOS、Chrome の複数のプラットフォームにメッセージを送信)
  • Push API

Push API とは W3C が定める仕様で、Web Worker の中の一つ。Web Worker ではいくつか分類されていて、

Web Workers API

  • Shared Worker
  • Service Worker
  • Chrome Worker
  • Audio Worker
  • ...

この Service Worker 内で Push API を使います。
参考:
Service Worker の紹介
Push API

トライ

ChromeでW3C Push APIを使ってみた
http://qiita.com/tomoyukilabs/items/8fffb4280c1914b6aa3d

Your first push notifications web app
https://developers.google.com/web/fundamentals/getting-started/push-notifications/

この2つのサイトを交互しながら試してみました。後者のチュートリアルに従いつつ、前者を見ながら、という感じです。

以下、引っかかったところのメモです。

  • manifest.json の gcm_sender_id に指定するのは、Project ID ではなく、Project Number。
  • 「Google Cloud Messaging for Chrome」がなく、「Google Cloud Messaging for Android」で「ブラウザキー」を登録。Authorize ヘッダーにはこのキーを指定。
  • https://android.googleapis.com/gcm/sendへ送信したときのエラーについて
    • 「error : MismatchSenderId 」→ Manifest.json が認証されていない可能性。localhost上ではなく、一度 Public な場所で公開する必要がある?
    • 401 → 「Authorization: key=******」が正しいかを怪しむ。
    • 400 → Body の中身が正しい形式かどうか怪しむ。JSONであればJSON書式として正しいか。
    • 「error : InvalidRegistration」→ registration_ids の中身である Registration ID を怪しむ。
  • https://android.googleapis.com/gcm/send/cAimx0m8Cys:******」セミコロンの後に Registration ID がある。
動的なメッセージの送信について

サーバー側から動的なメッセージを通知するには、
Web Pushでブラウザにプッシュ通知を送ってみる
HTTP/2 の Web Push を使用する必要があるみたいです。こちらは試していません。

以上、Google Cloud Messaging と Chrome で軽く試してみましたが、ブラウザ/Google Cloud Messaging/アプリケーションサーバー の関係性が良く分からず。
と、いろいろ見ていましたら、

Service WorkerとHTTP/2が切り開く新しいWeb Pushの世界
http://d.hatena.ne.jp/jovi0608/20141204/1417697480

2014/12の記事ですがこちらで詳しく説明されていました。

Visual Studio Code, TypeScript で Electron 触ってみた

$
0
0

無性に Electron をやってみたかったので触ってみました。環境は Windows 10 です。

触りたくなった理由

Visual Studio Code、Slack、Azure Storage Explorer (Cross-Platform)といった Electron 製を触っていて何かいいなーと思い、Electron 公式サイトに訪れてみたら、↓のようにアイコンが並んでいるのが素敵だな~と思って。

f:id:miso_soup3:20160205172802p:plain

Visual Studio Code と Microsoft Storage Explorer でよく見るアラートが一緒で、何となく気になったり(デザインは自家製だろうけど)。

f:id:miso_soup3:20160205173001p:plain

参考サイト

TypeScript+Electronでデスクトップアプリを作ってみる - SourceChord
ここで手順通りにしつつ、

tsd query github-electron-main -rosa install じゃなくて、
tsd query github-electron -rosa install こっちかな?


JavaScript (Electron) を使ってアプリの見栄えを整える - Qiita
これで遊んで、

Browser Window
Electronでデスクトップウィジェットを作るまで - Qiita
これも試してみたり、という感じ。

f:id:miso_soup3:20160205173205p:plain

f:id:miso_soup3:20160205173228p:plain
起動中のアプリで、Ctrl + Shift + i。

f:id:miso_soup3:20160205173416p:plain

f:id:miso_soup3:20160205174828p:plain

好感触。


ASP.NET MVC の UpdateModel と ValidateModel に思いを馳せる

$
0
0

ASP.NET MVC の Contoller クラスには、UpdateModel(...) と ValidateModel(...) のヘルパーメソッドが定義されています。
このメソッドを使うことで、モデルのバインド先の選択、検証対象の選択を行うことができます。

これらの関連メソッドは、Controller クラスにて以下のように定義されています(一部を掲載)

protectedinternalvoid UpdateModel<TModel>(TModel model) where TModel : class;
protectedinternalvoid ValidateModel(object model);
protectedinternalbool TryUpdateModel<TModel>(TModel model) where TModel : class;
protectedinternalbool TryValidateModel(object model);

この2つについて、調べてみました。

UpdateModel とは

UpdateModel は、入力値でモデルを更新し、検証し、ModelState に情報を追加します。

試しに、以下のように Student.cs と、ビュー、コントローラーを用意します。

Student.cs :
FirstName, LastName どちらにも[Required]属性を付与します。

using System.ComponentModel.DataAnnotations;

publicclass Student
{
    [Required]
    publicstring FirstName { get; set; }
    [Required]
    publicstring LastName { get; set; }
}

Create.cshtml : (ただの入力フォーム)

@using (Html.BeginForm())
{
    <divclass="form-horizontal"><h4>Student</h4><hr />
        @Html.ValidationSummary(
            excludePropertyErrors: false,
            message: "",
            htmlAttributes: new { @class = "text-danger" })

        FisrstName : @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" } })
        LastName : @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })
        <inputtype="submit"value="Create"class="btn btn-default" /></div>
}

StudentController.cs :

[HttpPost]
[ActionName("Create")]
public ActionResult CreatePost()
{
    //Body:"FirstName=Sato&LastName="でPOSTした場合

    var student = new Student() { FirstName = "DefaultFirst", LastName = "DefaultLast" };
    TryUpdateModel(student);

    Debug.WriteLine(student.FirstName); //sato
    Debug.WriteLine(student.LastName);//空
    OutputModelErrors();//LastName フィールドが必要です。return View();
}

void OutputModelErrors()
{
    foreach(var modelState in ModelState)
    {
        foreach (var error in modelState.Value.Errors)
        {
            Debug.WriteLine(error.ErrorMessage);
        }
    }
}

StudentController.cs では、Student クラスの各プロパティに適当な値をいれた変数を用意し、
TryUpdateModel メソッドを呼び出しています。

f:id:miso_soup3:20160328222128p:plain

画像のように入力しPOSTした場合(Body:"FirstName=Sato&LastName="でPOSTした場合)、StudentController.cs では、student変数に入力値がバインドされます。LastName は[Required]属性が付与されてますが、入力値は空で送信されているので、
「LastName フィールドが必要です。」という検証エラーの情報が ModelState に追加されます。
student.LastName に空の値がバインドされることに注意です。

Try の有無の違い

TryUpdateModel と UpdateModel の違いは、検証エラーがある場合に、例外を投げるかどうかの違いです。
例えば先ほどの StudentController.cs の TryUpdateModel() を UpdateModel() に変更して、同じように POST してみると下のように例外が発生します。

f:id:miso_soup3:20160328222146p:plain

UpdateModel() は、下の記事でも登場するように、使用頻度が高いメソッドです。

この他、プロパティのホワイトリスト/ブラックリスト、IValudProvider、値のKeyのPrefix を指定することができます。

protectedinternalvoid UpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IValueProvider valueProvider) where TModel : class;

推測ですが特に理由がない限り、UpdateModel() を使うのではなく、Controller のメソッドの引数にモデルを定義する方法が一般的に使われてるかなと思います。
(特にDBから取得してきたような監視のあるEntityに対してUpdateModel() を使う際は、ホワイトリストの使用が必須になるなど、動作を把握し注意が必要です。)

(また補足として、「入力値で値をバインドする」と言いましたが、この入力値は ValueProvider から提供されている値なので、手を加えれば Cookie や Session の値を対象とすることもできます)

ValidateModel とは

入力値をバインドする UpdateModel() とは違い、ValidateModel() はバインドを行いません。
インスタンスの値に対して検証を行い、ModelState に情報を追加します。

先ほどとやや同じ条件で試してみます。
今度は、FirstName, LastName どちらも値を入力して送信します。

f:id:miso_soup3:20160328222154p:plain

StudentController.cs にて、TryValidateModel() を呼び出します。

[HttpPost]
[ActionName("Create")]
public ActionResult CreatePost()
{
    //Body:"FirstName=Taro&LastName=Sato"でPOSTした場合

    var student = new Student() { FirstName = "DefaultFirst", LastName = "" };
    TryValidateModel(student);

    Debug.WriteLine(student.FirstName); //DefaultFirst
    Debug.WriteLine(student.LastName);//空
    OutputModelErrors();//LastName フィールドが必要です。return View();
}

このとき、student 変数には入力値がバインドされず、初期化時のプロパティの値(DefaultFirstと"")のまま格納されています。
また、フォームにてFirstName, LastName がどちらも入力されて送信されていますが、バインドは行われていないので、student.LastName には空文字ということで、
ModelState には「LastName フィールドが必要です。」というエラー情報が格納されます。

TryValidateModel と ValidateModel の違いは、UpdateModel のときと同様で、検証エラーがある場合に、例外を投げるかどうかの違いです。

ValidateModel の注意

後者で説明した ValidateModel では気を付ける点があります。それは、子プロパティのモデルに対して検証が走らないということです。

ここでは、次のように Cource クラスのリストをプロパティとして定義し、Title プロパティに [Required] を付与して試してみました。

publicclass Student
{
    [Required]
    publicstring FirstName { get; set; }
    [Required]
    publicstring LastName { get; set; }

    public IList<Cource> CourceList { get; set; }
}

publicclass Cource
{
    [Required]
    publicstring Title { get; set; }
}

StudentController.cs にて、Title を空にした student を用意しました。
ValidateModel() では、下のように各 Cource のインスタンスに対して ValidateModel() を呼び出さないと、検証が走りません。

[HttpPost]
[ActionName("Create")]
public ActionResult CreatePost()
{
    var student = new Student() { FirstName = "DefaultFirst", LastName = "DefaultLast" };
    student.CourceList = new List<Cource>()
    {
        new Cource() { Title = "" },
        new Cource() { Title = "" }
    };

    TryValidateModel(student);
    foreach(Cource cource in student.CourceList)
    {
        TryValidateModel(cource);
    }

    Debug.WriteLine(student.FirstName); //DefaultFirst
    Debug.WriteLine(student.LastName);//DefaultLast
    OutputModelErrors();//Title フィールドが必要です。return View();
}

ちなみにこの場合、Cource は2つ持っていますが、ModelState には、"Title"というキーで「Title フィールドが必要です。」というエラーが1つのみ格納されます。
もし、このエラーを1つ1つ識別する場合(2つのエラーとしたい場合)は、TryValidateModel メソッドで prefix を指定します。

TryValidateModel(student);
int courceIndex = 0;
foreach(Cource cource in student.CourceList)
{
    TryValidateModel(cource, prefix: (++courceIndex).ToString());
}

そうすると、下のように異なるキーで ModelState にエラー情報を追加することができます。

f:id:miso_soup3:20160328222211p:plain

この prefix の指定は UpdateModel() の方でもできるのですが用途が違います。
UpdateModel() の方は入力値を検索するときに、指定された prefix がついている入力値を検索します。
ValidateModel() の方は、ModelState にエラー情報を格納するときに、キーに指定した prefix を付けて追加します。
この違いがややこしい感じ。

UpdateModel() を使う例、条件によって検証を変える

UpdateModel()やValidateModel()は、動作を把握しておけばいざというときに役に立つヘルパーかもしれません。

私の場合、条件分岐によって検証ロジックを変えたいときに UpdateModel() を使いました。
Aパターンのときには、FirstName プロパティを必須にしたいけど、Bパターンのときは、FirstName は文字数だけ検証したい、けど、そのロジックは検証属性で表現したい、といったことです。

パターン毎にモデルを定義します。Student_A は必須&文字数検証、Student_B は文字数検証のみ。

publicclass Student_A
{
    [Required]
    [MaxLength(10)]
    publicstring FirstName { get; set; }
    [Required]
    [MaxLength(10)]
    publicstring LastName { get; set; }
}

publicclass Student_B
{
    [MaxLength(10)]
    publicstring FirstName { get; set; }
    [MaxLength(10)]
    publicstring LastName { get; set; }
}

StudentController.cs にて、条件分岐はここでは簡単に bool 変数で定義しました。
flag が true の時は、Student_A の属性の検証が行われ、
flag が false の時は、Student_B の属性の検証が行われます。

[HttpPost]
[ActionName("Create")]
public ActionResult CreatePost()
{
    bool flag = true;
    Type userModelType = userModelDic[flag];
    dynamic model = Activator.CreateInstance(userModelType);
    TryUpdateModel(model);
    
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    return View();
}

IDictionary<bool, Type> userModelDic = new Dictionary<bool, Type>()
{
    { true, typeof(Student_A) },
    { false, typeof(Student_B) }
};

UpdateModel() と ValidateModel() のコードです↓
https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/Controller.cs#L648

ASP.NET Web API の ApiController.cs にはありませんでした。

ASP.NET Core 1.0 では同様のメソッドが用意される予定です。
https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.Core/ControllerBase.cs#L1113

まとめ

★UpdateModel と ValidateModel の違い:

  • UpdateModel()
    • 入力値の値でモデルを更新し、検証し、ModelState に情報を追加する。
  • ValidateModel()
    • インスタンスの値を検証し、ModelState に情報を登録する。

★Try の有無の違い:

Try がない場合は検証エラーとなった場合は例外が発生します。Try がつく場合は、例外は発生せず検証エラーの有無を返します(ModelState.IsValidを返します)。

★prefix の扱い:

UpdateModel() の方は入力値を検索するときに、指定された prefix がついている入力値を検索します。
ValidateModel() の方は、ModelState にエラー情報を格納するときに、キーに指定した prefix を付けて追加します。

★注意:
ValidateModel は階層化のモデルに対して検証を行わない。


UpdateModel() と ValidateModel() は、ASP.NET MVC 2 ?のころからあるみたいです。
成熟前から用意されていて、次期の ASP.NET MVC Core 1.0 にも用意されていて…
Controller クラスにあるヘルパーメソッドの中でもちょっと用途が異なっていて…
というか UpdateModel と ValidateModel 処理的に全然違う…
サンプルでは使用されるけど、実際には、工夫のある使い方で使用されたりして…
でも ASP.NET MVC のモデルバインドの本質を考えると、引数にバインドするだけじゃなくて、Controller にてバインドヘルパーが用意されているのは納得…

と、いろいろ思ったのでした。

ASP.NET で例外診断のために Bugsnag を触ってみた

$
0
0

Bugsnag という例外診断サービスを ASP.NET で触ってみましたので、簡単にスクリーンショットを貼ります。

bugsnag.com

料金プランはこちら:Pricing and Plans - Bugsnag
14日間の試用期間がある模様。

導入

Bugsnag のサイトにアクセスし、サインアップを行います。

・プラットフォームに .NET を選択。ここで選択したものにあわせて、次の画面でドキュメントが表示されるもよう。
f:id:miso_soup3:20160329232934p:plain

・Visual Studio 2015 を開き、適当な ASP.NET MVC プロジェクトを作成します。

・NuGet で Bugsnagをインストール。

・Web.config にて、以下のように設定します。

<configuration><configSections><section name="bugsnagConfig"type="Bugsnag.ConfigurationStorage.ConfigSection, Bugsnag" /></configSections><bugsnagConfig apiKey="**** api key ****" /></configuration>

・FilterConfig.cs にて、以下のように属性を追加。

using Bugsnag.Clients;
using System.Web;
using System.Web.Mvc;

namespace ReportTry
{
    publicclass FilterConfig
    {
        publicstaticvoid RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(WebMVCClient.ErrorHandler());
            filters.Add(new HandleErrorAttribute());
        }
    }
}

・HomeController.cs に、例外を発生させるコードを追加。

using Bugsnag.Clients;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace ReportTry.Controllers
{
    publicclass HomeController : Controller
    {
        public ActionResult Index()
        {
            WebMVCClient.Notify(new ArgumentException("試しの例外です"));

            return View();
        }

        public ActionResult Error()
        {
            thrownew Exception("試しの例外発生です", new Exception("InnerExceptionです"));
        }


・デバッグで起動し、~/Home/Index と、~/Home/Error に何度かアクセスしてみます。

すると、Bugsnag のダッシュボードサイトにて、以下のように表示。

f:id:miso_soup3:20160329233347p:plain

検索も対応。

f:id:miso_soup3:20160329233358p:plain

エラーに対してアクション等。スヌーズ、アサイン、Fix 等が可能。

f:id:miso_soup3:20160329233425p:plain

デフォルトでメール送信になっているようで、以下のようなメールが送信されてきました。

f:id:miso_soup3:20160329233450p:plain

メールは嫌だったので OFF にし、Slack に連携してみました。

f:id:miso_soup3:20160329233514p:plain

f:id:miso_soup3:20160329233520p:plain

f:id:miso_soup3:20160329233524p:plain

ドキュメントはこちら。Documentation - Bugsnag

ちょっとしばらく使ってみようかなと思いました。

ちょっと使ってみて

ASP.NET MVC プロジェクトにて導入してみましたが、いろいろ引っかかる点がありました。できれば対応を進めようと思います。

Global.asax.cs の Application_Error() 内でエラーを送信しようとしましたが、やりたいことができなかったり。(Request情報やInnerExceptionの情報を送信できなかったり。)
既存のライブラリは2つ見つけまして、
・公式の bugsnag/bugsnag-dotnet .NET notifier for Bugsnag
・非公式の danesparza/net-bugsnag .NET Bugsnag notifier library

通知の API の仕様は https://bugsnag.com/docs/notifier-apiにあるので、これらを見ながら自分で作った方がよいのかなと思ったり。

また、StackTrace が空だとエラーとして追加してくれない?
Metadata として任意の情報も送信できるのですが、検索には対応していない?

いろいろ確認中です。

Azure Mobile Apps / Cordova / Xamarin のハンズオン開催

$
0
0

場所は、日本マイクロソフト関西支店。久しぶりに大阪行きました。

Azure Mobile Apps と Xamarin は、Microsoft エバンジェリスト 鈴木 章太郎さんが、
Cordova は私が担当しました。

f:id:miso_soup3:20160426131848j:plain

それぞれ30分のセッションの後、ハンズオンを行いました。
資料は以下の場所にあります。

事前準備:https://docs.com/cloudcamp/3916
資料:https://aka.ms/20160426HOLDOC
Cordova資料:https://github.com/hhyyg/MisoCordovaHol/tree/master/HandsOn

Cordova について

Cordova のセッションでは触れませんでしたが、個人的に面白い点が2つあります。

1. ASP.NET Core のプロジェクト構成と似ていること
2. Visual Studio 2015 で最近の Web 開発を試せる

ASP.NET Core はまだ RC なので、Cordova でいろいろ発散できます。
下にスクショを載せます。左が Cordova で、右が ASP.NET Core のプロジェクトです。

f:id:miso_soup3:20160427010453p:plain

npm, Bower の依存関係のところや、静的コンテンツ用のフォルダ等の構成・表示が一緒です。
これはあまり Cordova の本質とは関係ないのですが。

TypeScript での開発や、Gulp を使ったタスクランナーなど、Web で試したかったことが Cordova でもできます。
個人的に興味があるのはそこです。

f:id:miso_soup3:20160427010709p:plain

実際にモバイル開発をする際は、Xamarin や Swift 等のネイティブでやってみたいなと思いつつ、
最近の Web を遊べる Cordova + Visual Studio 2015 の組み合わせも面白いなと思います。

ちなみに、Onsen UI については 拡張機能によりプロジェクトテンプレートが用意されています。Onsen UI Templates for Visual Studio 2015 拡張機能

次の東京開催5/11では、WebViewやレンダリング改善のところを、少し掘り下げて説明したいと思いました。

Google Compute Engine に対して ASP.NET をデプロイ

$
0
0

Google Cloud Platform Blog: How to get your ASP.NET app up on Google Cloud the easy way

という記事があったので、ASP.NET をデプロイしてみました。Windows の仮想マシン自体は前からありましたよね? 特記事項はなく単にスクショを貼ります。

ドキュメントには2つのチュートリアルがあるので、最初の1つめを試しました。

1つめ Google Cloud Computing, Hosting Services & Cloud Support - .NET — Google Cloud Platform

The Hello World tutorial shows you how to deploy an ASP.NET application to Compute Engine.

2つめ Google Cloud Computing, Hosting Services & Cloud Support - .NET — Google Cloud Platform

The Bookshelf tutorial shows you how to build an ASP.NET MVC application that uses a variety Cloud Platform services to make your application reliable, scaleable and easy to maintain.

f:id:miso_soup3:20160512123634p:plain

f:id:miso_soup3:20160512123639p:plain

f:id:miso_soup3:20160512123648p:plain

f:id:miso_soup3:20160512123657p:plain

f:id:miso_soup3:20160512123703p:plain

チュートリアル通り DL したものは、単にメッセージを返すだけの ASP.NET Web API のプロジェクト。 f:id:miso_soup3:20160512123709p:plain

Visual Studio のプロジェクトを右クリック>発行

f:id:miso_soup3:20160512123716p:plain

f:id:miso_soup3:20160512123723p:plain

f:id:miso_soup3:20160512123729p:plain

Azure Search、SQL Server Database のコレクション項目を検索対象とする

$
0
0

Azure Search にてデータソースを Azure SQL Database にした場合の、コレクションの項目を検索可能/ファセット可能にする方法です。

例として、次のように SQL Database でテーブルが定義されている場合、Category.Name で Product を検索できるようにします。

Product

Id Name
1 商品名1

Category

Id Name
1 カテゴリ名1

ProductCategory

Id ProductId CategoryId
1 101 17
1 101 18

方法は適当に言うと、SQL の View で ["hoge", "hoge2"] と Json 形式で出力し、カスタムインデクサーで jsonArrayToStringCollection として定義します。

参考サイト
目次

前提

Azure Search と Azure SQL Database

Azure Search では、”この中から検索してください”と「データソース(またはストア)」を指定します。 現在、Azure Search では、主に以下のデータに対応しています。

  • Azure SQL Database
  • Azure DocumentDB
  • Azure Blob Storage
  • または Azure VM でホストされている SQL Server

この他、API からデータを追加したり、PDF、HTML、CSV、.txt 等のドキュメントにも対応しています(現在プレビュー)。 この記事で対象にしているのは、この中の Azure SQL Database(or Azure VM の SQL Server)です。

ちなみにAzure のポータルサイト上では、"この Azure SQL Databse で検索してください"とフローから設定することができます。

f:id:miso_soup3:20160628153826p:plain

Table, View

そして、Azure SQL Database を指定すると、Azure のポータルでは”どの Table を対象にするか”を設定することができます。 この選択には、Table だけではなく View も指定することができます。 この記事では View を対象とします。理由は、コレクションの項目を検索対象に含めたいからです。

f:id:miso_soup3:20160628153924p:plain

コレクションの項目

「コレクションの項目を検索対象にしたい」というのは、SQL Database でいえば、いわゆる「Children」も検索対象にしたい、ということです。 例えば、 Product テーブルの子である Category の Name でも検索したい、といった用途です。 (Child 単体ではなく、Children 複数です。 ちなみに単体も可能で、この記事のような複雑な設定はいりません。)

ですが、SQL Database のような RDB の場合は、別テーブルで設計されているのがほとんどです。 なので、Table の指定では Category の Name をデータに含められないため、Category も含めて select するような View を定義し、 Azure Search に”この View を検索対象としてください”と指定します。 (他の手段として、Azure SQL Database から他のデータソース― CSV や DocumentDB に変換する、もあると思います。)

前提の説明は以上で、このコレクションの項目を検索可能にする手順を記載します。

SQL Database 側の用意

まず、SQL Database に View を定義し、そのあと Azure Search 側で インデックス、インデクサーを定義します。

View

SQL Database にて View を作成します。とりあえず、Product を取得したいので次のような T-SQL が思い浮かびます。

select * from Product

これに 複数の Category の情報を追加します。複数の項目を出力するには、以下のように JSON 形式で string の配列で出力します。

["カテゴリ名1", "カテゴリ名2", "カテゴリ名3"]

※ [{ id: 1, name: "カテゴリ名1"}, { id: 2, name: "カテゴリ名2"}, ...] ではだめです。

View で上記の文字列を出力するために、例えば ProductId を引数として 1 つの Product から Cateogory.Name を取得する関数を作成します。 例えばこんなスカラー値関数になります。

CREATEFUNCTION [dbo].[GetCategoryNameListText]
(
 @productId int
)
RETURNS nvarchar(max)
ASBEGIN

delare @result NVARCHAR(3000)
set @result=''select @result = CASE @result
             WHEN ''THEN'"' + Category.Name + '" 'ELSE @result + ', ' + '"' + Category.Name + '" 'ENDfrom ProductCategory
    left outer join Category on
        ProductCategory.CategoryId = Category.Id
Where
    ProductCategory.ProductId = @productId
return'[ ' +  @result + ']'END

スカラー値関数を定義したので、View で参照します。 例えばこんな View になります。

CREATEVIEW [dbo].[ProductView] ASselect 
    [dbo].[GetCategoryNameListText](Product.Id) as'CategoryNameCollection',
    Product.*
from Product

そうすると1行の中に Product と複数の Category の情報が格納されます。

Id Name CategoryNameCollection
1 商品名1 ["カテゴリ名1", "カテゴリ名2", "カテゴリ名3"]

Azure Search 側の設定

次に Azure Search 側の設定です。

流れ:

  • インデックスの作成
    • SQL Database の View の列名でインデックスを作成します。「CategoryNameCollection」の型は Collection(Edm.String) で定義します。
  • インデクサーの作成
    • 作成したインデックスの対象のフィールドを「jsonArrayToStringCollection」として変換するように定義したインデクサーを作成します。
  • インデクサーの実行
  • 検索方法

単語:

Azure Search の構成要素として、次のような単語が登場します。()内は、今回の場合の具体例です。

  • ドキュメント (インデクサーによって作成された、SQL Database のデータ行。1ドキュメント=1行)
  • データソース、ストア (Azure SQL Database)
  • インデックス
  • インデクサー

インデックスとは、スキーマのようなもので、どういうフィールド名があって、このフィールドは”検索可能”、”並べ替え可能”、”取得可能”といったようなことを定義することです。このフィールド名は、データソース上で参照するときに使われます。 インデクサーはインデックスの定義に基づきデータソースをクロールします。

インデックスの作成

インデックスの作成時に、コレクションの型を「Collection(Edm.String)」とします。 例えば、REST API でインデックスを作成した場合、次のようになります。

POST /indexes?api-version=2015-02-28-PreviewContent-Type: application/jsonapi-key: [adminkey]Body: 
{"name": "productindexlucene",
    "fields": [{"name": "Id",
            "type": "Edm.String",
            "key": true,
            "retrievable": true},
        {"name": "Name",
            "type": "Edm.String",
            "searchable": true,
            "filterable": true,
            "sortable": false,
            "facetable": false,
            "key": false,
            "retrievable": true,
            "analyzer": "ja.lucene"
        },
        {"name": "CategoryNameCollection",
            "type": "Collection(Edm.String)",
            "searchable": true,
            "filterable": true,
            "sortable": false,
            "facetable": true,
            "key": false,
            "retrievable": true,
            "analyzer": "ja.lucene"
        },

        //...
    ],
    "suggesters": [{"name": "suggester",
            "searchMode": "analyzingInfixMatching",
            "sourceFields": ["Name", "NameKana" ]}]
}

CategoryNameCollection が Collection(Edm.String) で定義されています。(CategoryNameCollection は、先ほど作成した View の列名と一致します) クエリ文字列「?api-version=2015-02-28-Preview」が必須かどうかは未確認です。(プレビューバージョンのAPIじゃないとダメだったような、そうじゃないような)

インデックスの作成方法ですが、Azure のポータル上や SDK、他ツール等の方法があります。

インデクサーの作成

インデクサーに、このフィールドは「jsonArrayToStringCollection」として解釈してくれ、と定義します。

インデクサーも同様に REST API で作成します。API の仕様は、Create Indexer (Azure Search Service REST API)  から確認できます。 例えば次のようになります。

POST /indexers?&api-version=2015-02-28-PreviewContent-Type: application/jsonapi-key: [adminkey]Body:

{"name" : "productindexer",
    "description" : "",
    "dataSourceName" : "データソース名。Azure Portal から確認できます。",
    "targetIndexName" : "productindexlucene(先ほど作成したインデックス名)",
    "fieldMappings" : [{"sourceFieldName" : "CategoryNameCollection", "mappingFunction" : {"name" : "jsonArrayToStringCollection" }}]}

「fieldMappings」の設定が大事なとこです。クエリ文字列「?&api-version=2015-02-28-Preview」もおそらく必須。

参照:

インデクサーの実行

あとは、インデクサーを実行します。が、たぶん先の API でインデクサーを作成した時に、自動的に実行されていると思います(スケジュールの設定によるかも?)。(インデクサーの実行は REST API でも Azure のポータル上から可能です。)

進捗状況は、Azure のポータルから確認します。インデクサーが失敗した場合は、エラーの詳細を確認します。 私の場合はこのようなエラーが発生しました。

"The data field 'CategoryNameCollection' has an invalid value '[  'hoge' ]'. The expected type was 'Collection(Edm.String)'."
"The data field 'CategoryNAmeCollection' has an invalid value. The expected type was 'Collection(Edm.String)'."

原因は、ダブルクォートではなくシングルクォートにしてしまったり、Collection(Edm.String)で設定し忘れていたり、です。

インデクサーの実行が成功すれば、Category の Name で検索できたり、ファセットナビゲーションの項目として Category の Name を参照したりできます。また、検索結果の Json にもコレクションとして格納されています。

検索

検索のときは、例えば、”カテゴリ名1”という Category をもつ Product を検索したい場合は、次のようなクエリ文字列で URL を構築します。

?filter=CategoryNameCollection/any(t: t eq 'カテゴリ名1')

これは OData の構文と同様です。

参照: Azure の検索の OData 式の構文

REST API をたたく時に使用したコードを gist で貼っておきます。

Azure Search を触ってみて

$
0
0

Azure Search をいろいろ触ってみてのノートです。最新のアップデート内容とは違う可能性があります。

最初に

Azure Search を知らない場合、参考になる資料です

やってみる

  • Azure App Service を使ってみる
    • アカウント無しで、Azure Search を試すことができます。ただし時間制限があり。
    • [Web App] -> [ASP.NET with Azure Search Site] をクリックで立ち上がります。
      • このとき、「Web App コンテンツのダウンロード」から、ASP.NET Web Pages での実装のサンプルをダウンロードできます。

開発について

  • Azure ポータルからの操作以外に次のツールが用意されているが、自分で REST API を叩いた方が良い。雰囲気をつかむまでは Azure ポータル上で、そのあとは REST API 中心がいい。
ツール
REST API たたき中心がよい理由は、
  • SaaS という特性から。
  • 現在、Azure Search は REST API を先行して実装されており、Azure ポータルは二の次の実装、という印象を受ける。Azure のポータル上の変な日本語翻訳に惑わされやすい。
  • 試行錯誤等で REST API を何度も叩く可能性あり。
  • インデックスは作成した後、一部だけ更新というのができない。
  • ツールがプレビュー機能に対応しておらず、プレビュー機能の API を試すことができない。
面白そうな機能
  • スコアプロファイリング
  • ドキュメント クラッキング (現時点プレビュー)

PDF Microsoft Office 形式: DOCX/DOC、XLSX/XLS、PPTX/PPT、MSG (Outlook 電子メール) HTML XML ZIP EML プレーン テキスト ファイル (.txt) JSON

Azure Search で CSV 検索

$
0
0

azure.microsoft.com

Azure Search にて、Azure Storage Blob においてある CSV ファイルの行検索が可能になりました(version 2015-02-28-Preview にて可能、プレビューでの提供です)。 今までは行・列単位ではなくファイル単位での検索しかできませんでした。

主な機能
  • Azure Storage の Blob にある CSV ファイルを対象にできる。
    • コンテナー、フォルダーの指定が可能です。
  • コンテナーまたはフォルダー内にある CSV はすべて対象となります。(複数ファイルごそっと配置できます)
  • UTF-8、カンマ(,)区切りのみ対応。
  • CSVは、ヘッダー行有り・無し、の両方対応しています。
注意
  • Shift-JIS で保存すると日本語が文字化けします
  • 指定したコンテナー、またはフォルダ内には、CSVファイル以外のファイルを混在できません。
  • プレビューなので、URL に ?api-version=2015-02-28-Preview を付けることを忘れない。
  • CR, LF のみの改行コードだとダブルクォーテーションで囲ったとしてもエラーになります。
主な流れ
  • データソースの作成(CSV ファイルのある Azure Blog Storage、コンテナー、フォルダー名の指定)
  • インデックスの作成(CSV ファイルの列名をフィールドとして設定します)
  • インデクサーの作成(CSV ファイルとインデックスをつなげるインデクサーを作成します)
  • 検索実行

実際にやってみたので手順を記載します。

サンプルCSVの用意

サンプルとして下の場所から郵便番号のCSVファイルを用意しました。

vallog: 無料CSVデータ住所データCSV【住所.jp】

このCSVファイルは、ヘッダー行が日本語になっています。Azure Search では対応していないので、英数のヘッダーに置き換えました。 この英数のヘッダー名は後の手順で参照することになります。

f:id:miso_soup3:20160708182535p:plainf:id:miso_soup3:20160708182538p:plain

CSV ファイルは、Azure Storage の Blog に配置します。 ここでは、コンテナー名「yago-test」の「zipcode」フォルダ内に配置しました。

f:id:miso_soup3:20160708182708p:plain

データソースの作成

Azure Search をプロビジョニングした後、データソースを作成します。 API は次のようになります。 Azure Search の API については、Azure Search Service REST API バージョン 2015-02-28-Preview) | Microsoft Azure | Azure Search Preview API こちらを参照します。

POST https://[サービス名].search.windows.net/datasources?api-version=2015-02-28-Preview
Content-Type: application/json
api-key: キー

{
    "name" : "my-blob-zipcode(データソースの名前。なんでもよいですがあとで参照します。)"",
    "type" : "azureblob",
    "credentials" : { "connectionString" : "Azure Storage の接続文字列" },
    "container" : { "name" : "yago-test(コンテナ名)", "query" : "zipcode(フォルダ名(ある場合))" }
}

作成後、Azure ポータルではこのように表示されます。

f:id:miso_soup3:20160708182551p:plain

インデックスの作成

つぎにインデックスを作成します。 ここで、CSV ファイルの各列について記述することになります。CSV ファイルの全ての列を定義する必要はありません。 取得可能や検索可能といった仕様に応じて定義します。

また、CSV ファイルにヘッダー行がある場合は、このヘッダー名とここで定義するフィールド名は同じにしなければいけません。

例として、次のようにインデックスを作成しました。

POST https://[サービス名].search.windows.net/indexes?api-version=2015-02-28-Preview
Content-Type: application/json
api-key: キー

{ "name": "zipcode-index", "fields": 
 [  {"name": "AddressCode", "type": "Edm.String", "key": true },
    { "name": "Prefecture", "type": "Edm.String" },
    { "name": "ZipCode", "type": "Edm.String" },
    { "name": "PrefectureKana", "type": "Edm.String" },
    { "name": "City", "type": "Edm.String" },
    { "name": "CityKana", "type": "Edm.String" },
    { "name": "Area", "type": "Edm.String" },
    { "name": "AreaKana", "type": "Edm.String" }
  ]
}

f:id:miso_soup3:20160708182600p:plain

インデクサーの作成

次にインデクサーの作成です。ヘッダー行がある場合・無い場合で Body の Json が変わります。

ヘッダー行がある場合
POST https://[service name].search.windows.net/indexers?api-version=2015-02-28-Preview
Content-Type: application/json
api-key: [admin key]

{
  "name" : "my-zipcode-indexer",
  "dataSourceName" : "my-blob-zipcode",
  "targetIndexName" : "zipcode-index",
  "parameters" : { "configuration" : { "parsingMode" : "delimitedText", "firstLineContainsHeaders" : true } }
}

"firstLineContainsHeaders" : true が、ヘッダー行があることを意味します。

ヘッダー行がない場合
POST https://[service name].search.windows.net/indexers?api-version=2015-02-28-Preview
Content-Type: application/json
api-key: [admin key]

{
  "name" : "my-zipcode-indexer",
  "dataSourceName" : "my-blob-zipcode",
  "targetIndexName" : "zipcode-index",
  "parameters" : { "configuration" : { "parsingMode" : "delimitedText", "delimitedTextHeaders" : "AddressCode,PrefectureCode,CityCode,Address1Code,ZipCode,Flag1,Flag2,Prefecture,PrefectureKana,City,CityKana,Area,AreaKana,AreaNote,Torina,Cho,ChoKana,Note,Office,OfficeKana,OfficeAddress,NewAddressCode" } }
}

delimitedTextHeaders には、CSV ファイルの全ての列名を定義する必要があります。 この列名とインデックスのフィールド名が照会し検索が動作します。

インデクサーの実行

インデクサーが作成されると、データのインデックスが行われます。 Azure ポータルから結果を確認できます。エラーがある場合はエラーの内容を確認します。

f:id:miso_soup3:20160708182610p:plain

検索

これで検索の準備ができました。 「富山市」で検索すると、結果が返ってきました。

GET https://yagosear2.search.windows.net/indexes/zipcode-index/docs?api-version=2015-02-28&search=フチュウ
Content-Type: application/json
api-key: キー

f:id:miso_soup3:20160708183507p:plain

検索は Azure ポータルからも試すことができます。(日本語での検索は結果を確認できなかったので API で確認しました。)

f:id:miso_soup3:20160708182646p:plain

(日本語での検索は、アナライザーを日本語用のアナライザーにすることを忘れないようにします。)

カンマ以外の対応が欲しい場合、ほか要望は https://feedback.azure.com/forums/263029-azure-search こちらでフィードバックします。


Web ページに MathJax を使って MathML を表示する

$
0
0

 Reference

使い方 MathML

ここでは、MathJax を使った MathML を記述する方法について書きます。LaTex, Tex 等の情報はありません。

load

head内に、下記のように script を記述します。 ?configのクエリ文字列については?config の設定についてを参照してください。

<script 
    type="text/javascript"
    src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
inline & block
  • インライン表示:<math display="inline">
  • ブロック表示:<math display="block">
  • デフォルトはインライン表示
    • <math>はインライン表示
tag
namespace

必須ではないが、<math xmlns="http://www.w3.org/1998/Math/MathML">といったように名前空間をつけることが望ましいです。

参照:MathML input

self-closing tag

自己終了タグ(例:<mspace width="5pt" />)は使用しないで下さい。

参照:MathML input

設定オプション Core

参照:The Core Configuration Options

mml2jax

MathJax の ページ内に記述された MathML を認識するコンポーネントはmml2jaxと呼ばれます。mml2jaxはいくつかの設定オプションがあります。

詳細についてはmml2jax configuration optionsを参照してください。MathJax の MathML のサポートの詳細についてはMathMLのページを参照してください。

ここでは、mml2jaxの設定オプションについて記述します。

◇init

mml2jax の設定オプションを追加するには、以下のようにMathJax.Hub.config()mml2jaxセクションを追加します。

MathJax.Hub.Config({
    mml2jax: {
        preview: "mathml"
    }
});

以下は、MathJax の設定を含めた script の記述例です。

<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
        mml2jax: {
            preview: "mathml"
        }
    });
</script>
<script type="text/javascript"
        src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

◇preview: "mathml"

preview: "mathml"という設定により MathJax が MathML のレンダリング完了までに Html ページに挿入するものを指定できます。

"mathml","alttext","altimg","none"デフォルト値はmathmlです。

  • "mathml"
    • レンダリング中にmathタグをそのまま保持します。
  • "alttext"
    • レンダリング中に<math>要素のalttext属性の値が表示されます。例:<math alttext="表示中"> 表示中というテキストが表示されるます。
  • "altimg"
    • レンダリング中に<math>要素のaltimg*属性の値で指定された URL の画像が表示されます。例:<math alttext="../image/hoge.jpg">
  • "none"
    • プレビューが挿入されるのを防ぎます。

この他、 HTML スニペットを使用することもできます。詳細は description of HTML snippetsを参照してください。

Examples:

preview: ["[math]"]

レンダリング完了まで "[math]"というテキストが表示されます。

preview: [["img",{src: "/images/mypic.jpg"}]], 

レンダリング完了まで指定した URL の画像が表示されます。

Word からコピペする場合

Word から数式をコピーして貼り付ける場合、html タグを以下の様にする。

<html lang="ja" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">

Word から数式をコピーした場合、以下の様な MathML がコピーできる

<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"><mml:mfrac><mml:mrow><mml:mo>-</mml:mo><mml:mi mathvariant="normal">b</mml:mi><mml:mo>±</mml:mo><mml:msqrt><mml:msup><mml:mrow><mml:mi mathvariant="normal">b</mml:mi></mml:mrow><mml:mrow><mml:mn>2</mml:mn></mml:mrow></mml:msup><mml:mo>-</mml:mo><mml:mn>4</mml:mn><mml:mi mathvariant="normal">a</mml:mi><mml:mi mathvariant="normal">c</mml:mi></mml:msqrt></mml:mrow><mml:mrow><mml:mn>2</mml:mn><mml:mi mathvariant="normal">a</mml:mi></mml:mrow></mml:mfrac></mml:math>

Umbraco で Macro を使う

$
0
0

概要

Macro は Razor, XSLT, usercontrol で書くことができる。(Umbraco 7 では、usercontrol はあまり使われないと思われる。)

Parameter も設定可能。

Macro の入力用ヘルパーあり(Rich Text Editor にも付属)。

用途

ユーザーが任意の場所に、動的な要素を埋め込みたい時に使用する。

例えば、本文中にとある手順について書くとする。この手順は、あちこちの記事で表示する可能性があり、機能がリリースされるたびに更新が必要となる。

例:Azure Websites と ASP.NET を使用するの "このチュートリアルを完了するには、Azure アカウントが必要です。" の部分。

Macro を使用しない場合は、リリースの度に複数の記事を修正しなければいけない。Razor で @Html.Partial("hoge")と書きたいところだが、ユーザーが管理画面の入力欄で任意の場所に配置できるようにしたい。そこで Macro を使う。

手順

  • Partial View Macro Files を作成する。
    • Back Office > Developer > Partial View Macro Files

このとき、 .cshtml は @inherits Umbraco.Web.Macros.PartialViewMacroPage と、継承する。

  • Macro を作成する。
    • Back Office > Deceloper > Macros
  • Macro を配置する。方法は 2 つ。

◇方法1

ユーザーが Macro を配置したい場所にて以下のコードを書く。パラメータがある場合は、属性とその値も追加する。

<div><?UMBRACO_MACRO macroAlias="{ Macro の 名前}}" /></div>

開発者は、.cshtml 側で以下のコードを記述し、Macro をレンダリングさせる。

string afterRender = umbraco.library.RenderMacroContent(string Text, int PageId(Model.Content.Id)等);

◇方法2

入力フィールドがリッチテキストの場合は、ユーザーが 入力用ヘルパーから配置する。

Bug

  • Partial View Macro Files が文字化けする場合がある。
    • 改行文字の混合が原因?
    • Visual Studio から、ファイル>名前を付けて ... を保存>エンコード付きで保存>改行文字 でファイルを保存し直すと直る。
    • Back Office から編集して保存すると文字化けする可能性大。

Umbraco 7 Note 1

$
0
0

Umbraco についてです。メモとして描いていたので内容は部分的です。

Umbraco で登場する用語

  • Dashboards
    • http://hoge/umbracoでアクセスできる管理画面
  • Umbraco API
    • Version 6 から登場した Umbarco のデータを操作できる API
  • Back Office
    • Umbraco の構成要素

Back Office

C# で例えると、Document Type : クラス、Content : クラスから作成したインスタンス、Properies : クラスがもつ Property、Data Type : Property の型、Property Editors : Property の型の構造(string, int, Custom Class の中身の実装)。Umbraco でサイトを作成するには、Document Type を定義し、Properties を定義し、Content を作成してページを作る。

  • Document Type
    • ページの構造。
    • 例: Blog という Document Type は、 Title, BodyText, PublishDate, という Properties を持つ。
  • Content
    • ページ。
    • 例: Document Type の "Blog"から 2011/11/10 の記事 を作成する。(= Content を 1 つ作成した)
    • 例: Document Type の "Blog"から 2011/11/30 の記事 を作成する。(= Content を 1 つ作成した)
  • Properties
  • Data Type
  • Property Editors
  • Media Type
  • Media
  • Member Type
  • Member
  • Node
  • User
  • Macros
  • Macro Parameter Editor
  • Templates/Layouts/Masterpages
  • Packages

参照

未分類

Document Type

Document Type は継承することができる。この Document Type の継承は、"Property"や "Tab"を継承したい(同じ構造を持たせたい) 、という目的の時に使用する。とあるページがとあるページの下に配置されるからといって、Document Type を継承しなければいけない、ということではない。 (http://hoge/blogの下に http://hoge/blog/entryというページを配置する場合、必ずしも entry の Document Type は blog の Document Type を継承しなければいけない、ということではない。)

Document Type Compositions

Umbraco 7.2 から追加された機能。Document Type を複数継承することができるようになった。

今までは、継承する Document Type は一つしか選択できず、また継承元を変更することもできなかった。Document Type Compositions により複数の Document Type を継承元として選択できるようになり、変更も可能になった。

例えば、複数の Document Type に "Meta Keyword"という Property を持たせたい場合は、"SEO"という Document Type を作成して "Meta Keyword"という Property を持たせる。そして、例えばページという Document Type にて Document Type Compositions で "SEO"にチェックを入れる。そうすると、ページの Document Type に "Meta Keyword" という Property を持たせることができる。そして、ページは、他の Document Type も継承することができるので、気軽に Document Type を小さくまとめて定義できる。

なお、Dashboards の Document Type では、今まで通りのツリー構造で表示される。

Umbraco 7.2 Compositions

Alt Template

実際に選択している Template とは別のテンプレートを適用して表示することができる機能。URL に ?alttemplate=hoge ( hoge に Template の Alias) を付けて表示することができる。

注意として、意図しないページを表示させたり、余計なエラーを発生することになる。

この機能を禁止する場合は、 config/umbracoSettings.config の disableAlternativeTemplates に false を設定する。

<web.routing
    trySkipIisCustomErrors="false"
    internalRedirectPreservesTemplate="false" disableAlternativeTemplates="true">
</web.routing>
Custom Error Page

Custom Error ページの Content を用意する config/umbracoSettings.config にて、Content Id を設定

<errors>
  <error404>1732</error404>
</errors>

Web.config の system.webserver に

<httpErrors existingResponse="PassThrough"/>

ASP.NET の通常のエラー設定も必要に応じて。

<customErrors mode="RemoteOnly" defaultRedirect="~/Error.aspx"/>

Umbraco 7 公開日の設定

$
0
0

Umbraco の Document Type には、作成日・編集日 は予め用意されているが、公開日は用意されていない。

そこで、公開日を設定したい場合は、Document Event を拡張し、コンテンツが公開された時のイベントを拡張し、 ”あるドキュメントが公開されたらその時の日付を Property にセットする”という実装をかく。

以下はその例のコード。 (このコードには、MarkdownでかかれたテキストをHtmlに変換する処理も混ざっている。)

プロジェクト配下に「Umbraco.Core.ApplicationEventHandler」を継承したクラスを配置する。

参照:

application-startup - Events - Reference - Documentation - our.umbraco.org

Document Events https://our.umbraco.org/documentation/reference/events/Document-Events(ちょっと古い)

using HogeProject.Umbraco.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Publishing;
using Umbraco.Core.Services;

namespace HogeProject.Umbraco.Extensions
{
    /// <summary>/// Umbraco の アプリケーション イベントをカスタマイズします/// </summary>/// <remarks>/// https://our.umbraco.org/documentation/Reference/Events/application-startup/// /// Document Events https://our.umbraco.org/documentation/reference/events/Document-Events (ちょっと古い)/// </remarks>publicclass HogeProjectApplicationEventHandler : ApplicationEventHandler
    {
        protectedoverridevoid ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
        {
            ContentService.Publishing += ContentService_Publishing;
            ContentService.Saving += ContentService_Saving;
        }

        /// <summary>/// Content Saving/// </summary>/// <paramname="sender"></param>/// <paramname="e"></param>void ContentService_Saving(IContentService sender, SaveEventArgs<IContent> e)
        {
            foreach(IContent node in e.SavedEntities)
            {
                if (node.ContentType.Alias == "Article" || node.ContentType.Alias == "BlogEntry")
                {
                    //markdown で書かれた文章を変換しプロパティに格納します。
                    SetMarkdownParsed(node);
                }
            }
        }

        /// <summary>/// Content が Publish されようとするときに呼び出されます。/// </summary>/// <paramname="sender"></param>/// <paramname="args"></param>void ContentService_Publishing(IPublishingStrategy sender, PublishEventArgs<IContent> e)
        {
            foreach (IContent node in e.PublishedEntities)
            {
                if (node.ContentType.Alias == "Article" || node.ContentType.Alias == "Subject")
                {
                    // 最初の公開日をプロパティに設定します。
                    SetFirstPublishedDate(node, "sinceSet");
                }
                elseif (node.ContentType.Alias == "BlogEntry")
                {
                    // 最初の公開日をプロパティに設定します。
                    SetFirstPublishedDate(node, "firstPublishedDate");
                }
            }
        }

        /// <summary>/// プロパティに最初の公開日を設定します/// </summary>/// <paramname="content"></param>privatevoid SetFirstPublishedDate(IContent content, string propertyAlias)
        {
            //指定した値が null の場合のみ設定しますif (content.HasProperty(propertyAlias) == false)
                return;

            //既に設定してある場合は設定しないif (content.GetValue(propertyAlias) != null)
                return;

            //初期データの場合は設定しないif (content.HasProperty("isInitialData") && content.GetValue<bool>("isInitialData"))
                return;

            content.SetValue(propertyAlias, DateTime.Now);
        }

        /// <summary>/// Markdown でかかれた本文を Html に変換し、プロパティに設定します。/// </summary>/// <paramname="content"></param>privatevoid SetMarkdownParsed(IContent content)
        {
            if (!content.HasProperty("bodyText") || !content.HasProperty("bodyTextParsed"))
                return;

            string bodyTextMarkdown = content.GetValue<string>("bodyText");
            string bodyTextHtml = MarkdownHelper.Transform(bodyTextMarkdown);

            content.SetValue("bodyTextParsed", bodyTextHtml);
        }
    }
}

Application Insights で Azure Web Apps のパフォーマンスカウンターを監視したいが…

$
0
0

こちらの記事にて、Azure Web Apps でパフォーマンスカウンターの値を Application Insights に送信できるとありましたので、ASP.NETで試してみました。もろもろを記録しておきます。

azure.microsoft.com

現状の確認

まず、上記の方法を試す前に、現状、パフォーマンスカウンター関連の項目をどのように確認できるか、見てみます。
Standard 1のApp Service Plan上に、Web Appsを立ち上げます。

Web Appsでは、インスタンスあたりのメトリックスや、CPU Time、Average memory working set等の項目を見られます。

f:id:miso_soup3:20160819193235p:plain
↑インスタンスあたりのメトリックス
f:id:miso_soup3:20160819185435p:plain
↑グラフで選択できる項目

App Service Planだと、「CPU Percentage」「Memory Percentage」「Disk Queue Length」等が見られます。

f:id:miso_soup3:20160819193548p:plain
↑グラフで選択できる項目

グラフで選択できる項目は、アラートにも設定できます。「インスタンスあたりのメトリックス」で確認できるインスタンス毎の値については、アラートには設定できません。

Application Insights

Application Insights を入れた場合のパフォーマンスカウンター関連の項目はどうでしょうか?
Web Apps と Application Insights を作成した後、Visual Studio から ASP.NET プロジェクト作成、NuGet で Application Insights 2.1.0 を追加しデプロイしました。

このとき、Application Insights のグラフの項目には、パフォーマンスカウンターの欄がありますが、Web Apps の場合は実際に「Process CPU」や「ASP.NET request execution time」が取得できるわけではありません。

f:id:miso_soup3:20160819193909p:plain

このことは、実行中の IIS Web サイトのパフォーマンスの問題の診断 Microsoft Azureのドキュメントにも書いてあります。

システム パフォーマンス カウンター IIS または Azure Cloud Services (Azure Web アプリは除く)

それでは、冒頭のサイトで説明された機能を試し、Application Insights 上で Web Apps のパフォーマンスカウンターの値が取れるか確認してみます。

Application Insights Performance Counters

試した方法は以下の通りです。

・Azure 上に Application Insights と Web Apps を作成する。
・Visual Studio で適当な ASP.NET プロジェクトを作成する。
ApplicationInsights-SDK-Labsこちらにある手順を参照し、Application Insights SDK Labs の Package をインストールできるよう設定する。
・NuGetで「Microsoft.ApplicationInsights」(version 2.2.0-beta1)をインストールする。
・プロジェクトの中のApplicationInsights.configに、InstrumentationKey(Application Insightsのキー)を設定する。
・Azure Web Apps にデプロイする。
・Azure Web Apps の Kudu から拡張機能「Application Insights」を設定する。

f:id:miso_soup3:20160819195434p:plain
https://****.scm.azurewebsites.netにアクセスし、Site extensions から Application Insights をインストールします。)

そうすると、Application Insights メトリックスエクスプローラーにて、以下の項目の追加を確認できました。

f:id:miso_soup3:20160819195742p:plain

\.NET CLR Exceptions(??APP_CLR_PROC??)\# of Exceps Thrown / sec
\ASP.NET Applications(??APP_W3SVC_PROC??)\Request Execution Time 
\ASP.NET Applications(??APP_W3SVC_PROC??)\Requests In Application Queue 
\ASP.NET Applications(??APP_W3SVC_PROC??)\Requests/Sec 
\Process(??APP_WIN32_PROC??)\% Processor Time 
\Process(??APP_WIN32_PROC??)\IO Data Bytes/sec 
\Process(??APP_WIN32_PROC??)\Private Bytes 


f:id:miso_soup3:20160819195922p:plain

サイトの画像のように、Performance counters欄にある「Processor time」の項目名として取得できるのかと思いましたが、上記の項目名として取得しているようでした。

これらの項目はアラートとしても設定できますが、すべて単位が「カウント」となっており、また設定してもアラートが飛んでこないので若干怪しいです。
f:id:miso_soup3:20160819200112p:plain

Custom

Application Insights Aggregate Metrics SDK TelemetryModuleこちらを参考にし、
applicationinsights.configにカスタムカウンターを定義してみました。

<Counters> 
      <Add PerformanceCounter="\Process(??APP_WIN32_PROC??)\Handle Count" ReportAs="Process handle count" /> 
      <Add PerformanceCounter="\Process(??APP_WIN32_PROC??)\Thread Count" ReportAs="Process thread count" /> 
    </Counters> 

が、ポータル上からはこれらの項目を確認できず…。何か設定が間違っているのかもしれません。


以上、いろいろ試してみましたが、理解不足もあり中々難しいです。まだBetaですし、今後に期待です。

Viewing all 96 articles
Browse latest View live