Kobarin's Development Blog

C#やASP.NETなどについての記録です。

Azureでwkhtmltopdfがサポートされた話

Webサイト上からHTML(URLで指定)をPDFに変換する処理にwkhtmltopdfを使う場合、従来Azureでは動作しなかったらしい。
調べてみると、以下の投稿が見つかった。
social.msdn.microsoft.com
ただし、

Azure now supports WKHTMLTOPDF. Please make sure you're using Basic, Standard, or Premium App Service Plan.

とあるように、Freeでは非対応らしい。
試したところ、たしかにFreeでは動作せずBasicでは出来た。

Visual Studio 2019からAzureにDeployできない問題

Visual Studio 2019からAzureにDeployする際、以下ののエラーとなる。

Web deployment task failed. (The type initializer for 'Microsoft.Web.Deployment.DeploymentManager' threw an exception.

状況をまとめると以下の通り。

  • ASP.NET Coreのプロジェクトをテンプレのまま何も編集していないため、コードや設定に問題があるわけではない
  • Buildは正常にできるものの、PublishでAzureにDeployする際に上記エラーとなる
  • Azureポータルで確認すると、インスタンスは出来ている(従って、https://XXXXXX.azurewebsites.net/ のサイトは存在するが、サイトは動作しない)

冒頭のエラーについて調べてみると、以下の投稿が見つかった。
stackoverflow.com
この中の以下のReplyが気になった。

I had the same problem but installing SQL 2012 and changing the registry didn't fix it. After reinstalling Web Deploy 3.5 on my development machine things got straightened out.

気になった理由は、ここ以外にも「Web Deploy」が問題になるという内容の情報が見つかったからだ。
そこで「プログラムの追加と削除」を確認してみると、以下の2つが見つかった。

  • Web Deploy 4.0
  • Web Deploy 2.0

古い2.0を削除し、再びVSのDeployを行った結果、無事に成功。う~ん、エラーメッセージもっと具体的に出してほしい。

【解決済み】SQL Server 2014の再インストール時「sql server データベース エンジンの復旧ハンドルの待機に失敗しました」エラー

概要

久々にSQLServerを動かそうとしたところ接続できず、管理ツールのサービス「SQL Server」も停止したまま起動できなかったため、SqlServer2014を再インストールしようとした。

症状

インストーラーからインストールを実行したところ、以下のエラーが発生した。

sql server データベース エンジンの復旧ハンドルの待機に失敗しました」

インストール結果としては、データベースエンジンだけがインストールに失敗している。

対策1:全て削除してから再インストール(解決できず)

「プログラムと機能」より「SQL」と名の付くアプリケーションを全て削除して再度インストールを試みたが改善せず。

対策2:「SQL Server データベースエンジン」のアカウント変更(解決!)

以下を参考に実行したところ、無事にインストール成功した。

www.sk-access.com

SQL Server 2016 SP1 Express」のインストールの途中で、「サーバーの構成」が表示されます。
サービスの
「SQL Server データベースエンジン」のアカウント名が
「NT Service\MSSQL$SQLEXPRESS」になっています。
この「SQL Server データベースエンジン」のアカウント名を
「NT AUTHORITY\NETWORK SERVICE」に変更します。

信頼レベル「Medium」(Medium-Trust)のサイトでは、ASP.NET MVCが実行できない可能性

私が個人的に契約しているWindowsホスティング会社に、MVCサイトを発行し実行したところ、セキュリティエラーが発生しました(System.Security.Policy.PolicyException)。
Visual Studioの開発環境で試してもエラーが出ないため、ホスティング会社に確認したところ「信頼レベルは”Medium”」だとの事なので、その辺りを疑ってみました。
VS上で同じ環境を作って試すため、web.config内に以下の行を付け加えてみました。

<system.web>
  <trust level="Medium" />
</system.web>

その結果、VSの開発環境でも同様のエラーが発生しました。



冒頭で発行したとするMVCのサイトは、VSで自動生成されたMVCサイトのままでほとんどに手を付けていない状態。
信頼レベルの制約で疑わしい点があるとするなら、

  1. OAuth
  2. 外部APIXML)へのアクセス
  3. SqlServerへのアクセス

程度ですが、2及び3については、既に発行済のASP.NET WebFormsで実行済みなので除外しました。
とすると、残るはOAuthのみ(他にあるかもしれないけど、それがダメならMedium-Trustって何も出来ないと同義ですよね)。


そこで、「こういう事例って他に結構あるのか?」と思い探してみると、こんな書込みが。
どうやら「ASP.NETの開発チームの公式見解としては、Medium-Trustは時代遅れ」という事です。
stackoverflow.com
理由としては、

  1. 「修正不可」とされていたMedium-Trustにまつわるバグを全て解決済み(デバッグではなく、Full-Trustにより解決したと思われる)
  2. ホスティング会社に対して、Medium-Trustから移行し、代わりにOSレベルの適切な分離をするようにガイダンスを提供済み
  3. これまで開発してきたフレームワークMVCやWebAPI等)からMedium-Trustのサポートを中止済み。今後これらのフレームワークにより作られたアプリケーションにはFull-Trustが求められる。

としている。つまりMedium-Trustは使うべきではないアクセス制限機能ということになります。
なお、ここでの「Medium-Trust」というのは「信頼レベル=Medium」というだけでなく、「Full」より下の「High」「Medium」「Low」「Minimum」の4つを全て含む総称としている点に注意です。


実際、このような書込みもあります。
stackoverflow.com
この中のリプライに

But, most of hosting provider offer full trust hosting now

とあるように、Full-Trustが米国(?)では一般的なようです。
ASP.NET MVCサイトのホスティング先をお探しの方は、あらかじめ運営会社に「信頼レベル」を確認していただく事をオススメします。

ASP.NET MVCでGoogleのOAuth 2.0 の認証をする

Visual StudioASP.NET MVCサイトのテンプレートには最初からOAuthの認証機能が付いているが、幾つか引っかかったのでメモしておきます。
基本的な流れは以下のサイトによくまとめられているため、割愛します(これ以上わかりやすく書けません)。
fnya.cocolog-nifty.com

ただ、上記の記事作成時点ではベータ版だったらしく、その後仕様が変わったのか、この通りに設定・操作を進めてもログインできません。
何故か、ログインページの「Google」ボタンを押しても、何も表示されないまま元のログインページに戻ってきてしまいます。

解決方法として見つかったのは、以下のスレッドです。
stackoverflow.com
これによると、Google Developer Consoleで「Google+ API」を有効にする必要があるようです。
Google Developer Consoleの左ペイン「APIとサービス」から「ライブラリ」を押し、「Google+ API」を有効にしてから再度実行するとOAuthログインできます。

Umbraco : 1つのデータベース内に複数サイト

Umbracoの開設は、下記サイトのようなチュートリアル通りに進めればほぼ難なく出来る事がわかりました。
www.buildinsider.net

ただ、複数サイトを作成しようとすると、幾つか問題があります。
Umbracoサイト毎にデータベースを用意するのであれば問題になりませんが、自社で使う簡易的なサイトや同じ顧客のためにサイトを複数作る時など、できれば同じデータベース内で管理したいと思います。
そうした場合、上記チュートリアルの通りに進めても上手くインストール出来ません。
Webサイト側はVisualStudiodで新たに作れば良いだけですが、データベース側(SQL server)ではTABLE(cmsContent等)が重複するため、インストール途中で失敗します。

そこで、以下の流れに沿って進める事で複数サイト開設ができたのでメモしておきます(例として2サイトを作成)。

  1. Umbracoサイトを2つ作成
  2. Umbraco用のデータベースを1つ作成
  3. SqlServerログインを2つ作成
  4. データベースロールを2つ作成
  5. 各DBロールに、スキーマレベルのCREATE TABLE権限を付与
  6. Umbracoインストー

設定例

なお、各サイトのログイン設定は以下の通りとします。

項目 サイト1 サイト2
データベース UmbracoDemoDb UmbracoDemoDb
ログイン umbuser1 umbuser2
スキーマ umb1 umb2
データベースロール umb_role1 umb_role2

それでは進めてみましょう。

手順

1.Umbracoサイトを2つ作成

Visual StudioでUmbracoのプロジェクトを2つ作成しましょう。この部分は説明の必要はないと思うので割愛します。

2.Umbraco用のデータベースを作成

SSMSでデータベースをUmbraco用に1つ作成します。ここでは「UmbracoDemoDb」というDBにします。

3.SqlServerログインを作成
  1. SqlServerManagementStudioを開く
  2. [セキュリティ]→[ログイン] で右クリックし、「新しいログイン」
  3. [ログイン名] に「umbuser1」を入力
  4. [SQL Server認証]を選択し、パスワードを登録
  5. [既定のデータベース]に「UmbracoDemoDb」を選択
  6. [ユーザーマッピング]で「UmbracoDemoDb」を選択し、[ユーザー]に「umbuser1」、[スキーマ]に「umb1」を入力

一般的な説明では「データベース ロール メンバーシップ」の「db_owner」にチェックを入れますが、ここはオフで。チェックを入れるとインストールに失敗します。

4.データベースロールを作成
  1. SSMSで [UmbracoDemoDb]→[セキュリティ]→[ロール]→[データベースロール] を右クリックし、「新しいデータベースロール作成」
  2. [ロール名]に「umb_role1」を入力
  3. [所有者]に「dbo」
  4. [このロールが所有するスキーマ]に「umb1」
  5. [このロールのメンバー]に「umbuser1」を選択
5.DBロールに、スキーマレベルのCREATE TABLE権限を付与

最後に、SSMSで以下のクエリーを実行します。

USE UmbracoDemoDb
GRANT ALTER ON Schema :: umb1 TO umb_role1
GRANT CREATE TABLE TO umb_role1
GO

このコードは以下の書込みを参考にしました。
serverfault.com
なお、実行すると以下のメッセージが表示されますが、正常に完了しているので大丈夫です。

sa、dbo、エンティティ所有者、information_schema、sys、または自分自身に対する権限を許可、拒否、または取り消すことはできません。

6.Umbracoインストー

以上で1サイト用のログインは完成です。
Umbracoのインストールで、ここで設定したログインを入力すれば、スキーマ付きでTABLEが登録されます。

2つ目以降のサイトも同様に、ログイン名・データベースロール名・スキーマ名を変えて設定し、Umbracoのインストール画面でログインすれば、指定したスキーマでTABLEが作成されます。
あと、Umbracoのよくある解説サイトでは、ログインを作成する際に「db_owner」を選択しますが、これをしてしまうとインストール時に失敗します(当方の場合は「umbracoMigrationが無効」と出ました)。
どうもアクセスできてしまうだけでエラーになってしまうので、ここではdb_ownerを外す事で指定スキーマにしかアクセス出来ないようにしています。

Umbraco+ASP.NET MVCによるサイト作成

UmbracoとMVCの併存サイトを作ったのでメモします。
まずは当方の環境から。

はじめに

まず参考にさせていただいたのは以下の記事です。
www.buildinsider.net
この記事ではUmbracoのバージョンは6.1.1、MVCはver.4なので、やや古い印象はありますが概ね内容通り進めれば問題ないと思いますが、幾つか追加事項があるのでそれも含めて説明していきます。

A. 新規Webサイトの作成

  1. Visual Studio 2017(以降、VSと略)で新規プロジェクトを作成し、「ASP.NET Web Application (.NET Framework)」を選択
  2. テンプレートから「MVC」を選択
  3. これで空のMVCサイトが出来上がりましたが、この後Umbracoインストール時に上書きされる、ルート直下のweb.configを何処かにバックアップしておきましょう

B. Umbracoのインストー

  1. メニューの[Tools] → [Nuget Package Manager] → [Manage Nuget Packages for Solution]
  2. 「UmbracoCMS」を検索し、プロジェクトに[Install]
  3. ここまでが参考記事2までに沿った流れです

C. web.configの編集

  1. Umbracoによるweb.configとMVCのweb.config(A-3でバックアップしたファイル)をマージする(参考記事3の箇所)。1つ1つタグを追っていき、互いに存在しない行を付け足していきます。

D. 初期設定

  1. プロジェクトをBuildし、[Debug] → [Start Without Debugging]でサイトを起動
  2. この時、web.config周りでエラーが出たら、いったんコメントアウトして再度試してみましょう(私の場合も、忘れましたが幾つか削除しました)
  3. ブラウザが開き、ログインアカウントの設定画面が出ます。そのまま[Install]するとSQL Server Compact EditionとしてApp_Dataフォルダの下の.sdfファイルをデータベースとして使うことになります。SQL serverを使う場合は、[Customize]を押すとサーバー設定が出来ます。後々SQLserverで動作させる予定があるならこの場で設定しておきましょう。なお、後からweb.configのConnetionStringを変更しても上手く動作しませんでした(初期画面の女性が多く写った写真を背景にインジケーターがずっと点滅した場が続きました)。おそらくCEからSQLへのデータ移行を行う必要があるのかもしれません。

E. ルーティング設定

ASP.NET MVCアプリケーションの場合、既定では例えば http://example.jp/Product/Details/123 というアドレスを指定すると、Controller=Product、のAction=Details、id=123 としてルーティングされます。
しかしUmbracoをインストールしたことによりこのルーティング設定は無効化され、あらゆるアクセスがUmbracoで処理されることになります(RouteConrigが削除されたり書き換えられるわけではありません)。
本稿はMVCとの併存サイトを構築することが狙いなので、MVCアプリケーションにもアクセスできるようカスタムルーティングを設定する必要があります。
Umbracoを扱う以上は、基本は全てUmbracoで処理する事になると思われます。その中で、例えば「オンラインショップ部分のみMVCで動かしたい」と考えた場合、http://example.jp/onlineshop/で始まるをMVCアプリケーションとしてルーティング設定することになります。
参考記事5の通り、どこでも良いのでクラスファイルを作り、以下のように作成(参考記事ではGlobal.asax内だが、当方はApp_Code内に記載した)。
Global.asaxのApplication_Start内の文をOnApplicationStarted内に記述。

public class AppStart : IApplicationEventHandler
{
  public void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication,
  ApplicationContext applicationContext)
  { }

  public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication,
     ApplicationContext applicationContext)
  {
  }

  public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
  {
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
  }
}

次に、App_Start/RouteConfig.csを開き、以下のように書き直す。

public static void RegisterRoutes(RouteCollection routes)
{
  routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
  routes.LowercaseUrls = true;  //小文字の有効化

  routes.MapRoute(
    name: "OnlineShop",
    url: "OnlineShop/{action}/{id}",
    defaults: new { controller = "OnlineShop", action = "Index", id = UrlParameter.Optional },
    namespaces: new[] { "(アプリケーション名).Controllers" }
  );
}

これにより、/onlineshop/で始まるアドレスのみMVCアプリケーションとして動作する事になります。
ちなみにnamespace部分は必ずしも必要ではなく、参考記事にも書かれていません。
ただ、当方の場合プロジェクト名を途中で変更したせいか旧プロジェクトのControlerが残ってしまったらしく、以下のような例外が発生してしまってました。

Multiple types were found that match the controller named 'OnlineShop'. This can happen if the route that services this request ('OnlineShop/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.

特に必要なければそのままでよいですが、もし上のようなエラーが現れる場合は、MapRouteでnamespaceを付け加えてみて下さい。
これについては、自分なりに探して以下に情報を参考にしました。
stackoverflow.com

F. UmbracoReservedPathsの設定

最後に、参考記事にもあるようにweb.configのappSettings内のUmbracoReservedPathsに以下のように追記して終了です。

<add key="umbracoReservedPaths" value="~/umbraco,~/install/,~/Content,~/Bundles"  />

以上で動作すると思われます。