WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

Razor クラスライブラリ

by WebSurfer 2024年3月20日 15:43

Razor Class Library (RCL) に ASP.NET Core MVC の Controller と View を実装し、それを ASP.NET Core MVC アプリから利用する例を書きます。

Razor クラスライブラリの利用

話の発端は Microsoft Q&A のスレッド「.NET MVCで参照登録したDLLのビューを使用する方法」でクラスライブラリ中のビューが見つからないという話です。それに対処する方法を検討した時の話を備忘録として残しておくことにしました。

ASP.NET Core MVC の cshtml ファイルは、Microsoft のドキュメント「ASP.NET Core での Razor ファイルのコンパイル」によるとデフォルトでビルド時及びデプロイ時に dll にコンパイルされるそうなので、.NET Framework 版の MVC のようなランタイムコンパイルだからダメということはなさそうです。

ただし、アクションがビューを返すときにビューの検出と呼ばれるプロセスが行われるそうで、Microsoft のドキュメント「ビューの検出ルール」に書いてあるように、既定のフォルダに当該ビューが存在しなければなりません。

Microsoft Q&A の話は、独立したクラスライブラリに MVC の Controller と View を実装した結果、MVC アプリがビューを見つけることができず、InvalidOperationException: The view 'Index' was not found いう例外がスローされたということです。

クラスライブラリではなくて、ASP.NET Core MVC 本体のプロジェクトに Controller, Model, View を実装すればそういう悩みは解消できますが、どうしても独立したライブラリを使わなければならない事情があるなら、Razor Class Library として作るのが良さそうです。

Razor Class Library は Razor Pages だけでなく MVC もサポートしており、設定によって Controller, View, Model を実装して、MVC アプリからそれらを呼び出すことができるそうです。

ということで、Microsoft のドキュメント「ASP.NET Core の Razor クラス ライブラリ プロジェクトを使用した再利用可能 UI の作成」とネットで見つけた記事「Working with Razor Class Libraries in ASP.NET Core」を参考にして作ってみました。

ソリューションの構成

上の画像の RazorClassLib が RCL プロジェクトで、RazorClassLibraryHost が MVC アプリのプロジェクトです。両方とも Visual Studio 2022 のテンプレートで作って、前者には Controllers, Models, Views フォルダを追加し、それらの中に Controller, Model, View クラスを実装しています。後者はテンプレートで作ったまま何も手を加えてません。

MVC アプリの実行結果がこの記事の一番上の画像で、MVC アプリから RCL の Controller / View を呼び出して結果を表示したものです。ビューが見つからないという問題は起こりません。

何も難しいことは無かったのですが、Visual Studio で RCL プロジェクトを作成する際に注意すべき点があって、それは[サポート ページとビュー]にチェックを入れることです。

[サポート ページとビュー]にチェック

上に紹介した Microsoft のドキュメントに "Select Support pages and views if you need to support views. By default, only Razor Pages are supported." と書いてありますが、デフォルト([サポート ページとビュー]にチェック無し)では Razor Pages も MVC もサポートされません。その下に書いてある "The Razor class library (RCL) template defaults to Razor component development by default. The Support pages and views option supports pages and views." が正しいです。

Microsoft のドキュメント「クラス ライブラリで ASP.NET Core API を使用する」の「MVC 拡張機能を含める」のセクションの説明によると以下の設定が必要とのことです。

  1. Microsoft.NET.Sdk.Razor SDK を使用する。
  2. true に設定された AddRazorSupportForMvc MSBuild プロパティ。
  3. 共有フレームワークの <FrameworkReference> 要素。

Visual Studio 2022 の RCL テンプレートで[サポート ページとビュー]にチェックを入れて作成したプロジェクトは上の要件を満たしていて、生成されるプロジェクトファイルの内容は以下のようになります。

<Project Sdk="Microsoft.NET.Sdk.Razor">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
  </PropertyGroup>

  <ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
  </ItemGroup>
  
</Project>

その他、気が付いた点を以下に書いておきます。

MVC アプリから RCL に参照設定がされていれば、RCL の Controller は、MVC アプリのプロジェクトの Program.cs に含まれる builder.Services.AddControllersWithViews(); で DI コンテナに登録されるようです。なので、参照設定以外は何もしなくても、要求に応じて RCL の Controller が呼び出され応答が返ってきます。

MVC アプリから RCL の Razor Pages を呼び出す場合は、Program.cs に builder.Services.AddRazorPages(); と app.MapRazorPages(); を追加する必要があります。追加しないと見つからないというエラーになります。

MVC アプリに実装されている _Layout.cshtml が自動的に使われます。なので、MVC アプリの wwwroot に実装されている Bootstrap などの CSS や jQuery などの JavaScript も有効になります。

Tags: , , , ,

CORE

ASP.NET MVC でトレース情報の表示

by WebSurfer 2015年4月6日 21:52

ブラウザからトレースビューア Trace.axd を要求したとき表示される[トレース情報]に、System.Diagnostics.Trace クラス(Page.Trace プロパティで取得できる TraceContext オブジェクトではない点に注意)を利用して書き込んだトレースメッセージを表示する方法を書きます。

トレースビューアの表示

この記事の例では、一つのソリューショ���の中に二つのプロジェクトがあって、一方が ASP.NET MVC4 の Web アプリケーション、他方がデータベースなどからデータなどを取得する中間ビジネス層のクラスライブラリを考えます。また、View に Razor 構文を使用することとします。

ASP.NET Web Forms アプリケーションの例は MSDN ライブラリの チュートリアル : ASP.NET トレースと System.Diagnostics トレースの統合 に詳しく書いてあります。(現時点の記事には、「Web フォームのトレース メッセージを書き込むには」のセクションのコード Trace.WriteLine が Trace.Write の間違い、WebPageTraceListener とコンパイラのバージョンが古いなどの問題があるので注意してください)

これと同様なことを MVC4 Razor 構文のアプリケーションで行ってみます。ちなみに、この記事の検証に使った環境は、Vista SP2, ASP.NET 4, VS2010 Professional, MVC4 インターネットアプリケーションテンプレートで作成、IIS7 統合パイプラインモード上で実行、ブラウザは IE9 です。

(1) クラスライブラリ(Model 相当)

チュートリアルにある AuthorClass ビジネスオブジェクトに相当するクラスライブラリは、以下のコードのとおり実装しました。

MVC アプリケーションの Model として利用しやすいように、Author クラスを定義し、List<Author> 型のオブジェクトを作成して渡すようにしています。チュートリアルとは違って、Authors.xml ファイルは使用していません。

トレースメッセージは、チュートリアルと同様に、AuthorClass オブジェクトの生成時点と AuthorClass.GetAuthors メソッドの呼び出し時点で Trace.Write メソッドを使って書き込みます。

加えて、非同期で呼び出したメソッドでトレースメッセージを書き込んだ場合にはどうなるかを検証するため、AsynchronousMethod を追加し、非同期で呼び出してみました。(結果は、上の画像の通りトレースビューアには表示されません)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AuthorClassLibrary
{
  public class Author
  {
    public string au_id { get; set; }
    public string au_lname { get; set; }
    public string au_fname { get; set; }
    public string au_phone { get; set; }
  }

  public delegate Author WriteTraceMessage();
    
  public class AuthorClass
  {        
    public AuthorClass()
    {
        // トレースメッセージ書込み
        System.Diagnostics.Trace.Write(
            "AuthorClass is created.", "AUTHORCLASS TRACE");
    }

    public List<Author> GetAuthors()
    {
      // トレースメッセージ書込み
      System.Diagnostics.Trace.Write(
          "GetAuthors called.", "AUTHORCLASS TRACE");
            
      List<Author> authors = new List<Author>() {
        new Author { au_id = "172-32-1176", au_lname = "White",
            au_fname = "Gerry", au_phone = "408 496-7223" },
        new Author { au_id = "172-32-1176", au_lname = "Green",
            au_fname = "Marjorie", au_phone = "415 986-7020" }
      };

      // AsynchronousMethod を非同期呼び出し
      WriteTraceMessage asyncCall = 
          new WriteTraceMessage(AsynchronousMethod);
      IAsyncResult ar = asyncCall.BeginInvoke(null, null);
      Author author = asyncCall.EndInvoke(ar);
      authors.Add(author);

      return authors;
    }

    // 非同期で呼び出すメソッド
    static Author AsynchronousMethod()
    {
      // トレースメッセージ書込み(Trace.axd では表示されない)
      System.Diagnostics.Trace.Write(
          "AsynchronousMethod called.", "AUTHORCLASS TRACE");

      Author author = new Author() {
          au_id = "123-45-6789", au_lname = "太郎",
          au_fname = "日本", au_phone = "000 111-2222" };

      return author;
    }
  }
}

(2) Controller

MVC4 インターネットアプリケーションテンプレートで自動生成される HomeController に、以下のように Authors アクションメソッドを追加します。

ブラウザから Home/Authors が呼び出されたときに Trace.Write メソッドを使ってトレースメッセージを書き込むようにしています。

また、このメソッドの中で、上のクラスライブラリの AuthorClass コンストラクタと AuthorClass.GetAuthors メソッドが呼び出され、トレースメッセージが書き込まれることに注意してください。

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

namespace Mvc4App.Controllers
{
  public class HomeController : Controller
  {

    // ・・・中略・・・

    public ActionResult Authors()
    {
      System.Diagnostics.Trace.Write(
        "Home/Authors method called.", "CONTROLLER TRACE");
            
      ViewBag.Message = "System.Diagnostics Trace の統合。";

      AuthorClassLibrary.AuthorClass authors = 
                new AuthorClassLibrary.AuthorClass();
      return View(authors.GetAuthors());
    }
  }
}

(3) View

View においても、以下のコードのように、Trace.Write メソッドを使ってトレースメッセージを書き込むことができます。

@model IEnumerable<AuthorClassLibrary.Author>

@{
    ViewBag.Title = "ASP.NET MVC Trace";
    Layout = "~/Views/Shared/_Layout.cshtml";
    
    System.Diagnostics.Trace.Write(
        "Home/Authors.cshtml called.", "VIEW TRACE");
}

<hgroup class="title">
    <h1>@ViewBag.Title.</h1>
    <h2>@ViewBag.Message</h2>
</hgroup>

<table>
@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.au_id)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.au_lname)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.au_fname)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.au_phone)
        </td>        
    </tr>
}
</table>

Trace.Write メソッドで書き込んだトレースメッセージが出力されるようにするには、Visual Studio で当該プロジェクトの Property を開き、その[ビルド]タブの[TRACE 定数の定義(T)]にチェックマークを入れる必要があります。

[トレース定数の定義]の設定

View については更なる設定が web.config に必要です(上の画像の[トレース定数の定義]の設定だけでは View の Trace.Write メソッドは無視されます)。

具体的には、C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\web.config の中の complier 要素を、アプリケーションルート直下の web.config にコピーして、それに compilerOptions="/define:TRACE" を追加します。

詳しくは、MSDN ブログの記事 Tracing in ASP.NET MVC Razor Views を見てください。チュートリアルの「トレースを有効にしてアプリケーションを自動コンパイルするには」のセクションにも同様なことが書かれていますが、こちらはバージョンが古いので注意してください。

今回の検証で使った環境では以下のようになります。

<system.codedom>
    <compilers>
        <compiler 
            language="c#;cs;csharp" 
            extension=".cs" 
            warningLevel="4" 
            compilerOptions="/define:TRACE" 
            type="Microsoft.CSharp.CSharpCodeProvider, 
                System, 
                Version=4.0.0.0, 
                Culture=neutral, 
                PublicKeyToken=b77a5c561934e089">
            <providerOption 
                name="CompilerVersion" 
                value="v4.0"/>
            <providerOption 
                name="WarnAsError" 
                value="false"/>
        </compiler>
    </compilers>
</system.codedom>

さらに、System.Diagnostics.Trace クラスを使用して書き込んだトレースメッセージをルーティングして、ASP.NET トレース ビューア(Trace.axd)に表示されるようにするには、web.config で trace 要素を有効にし、WebPageTraceListener を追加する必要があります。

WebPageTraceListener の設定はチュートリアルの「構成でアプリケーションの WebPageTraceListener を追加するには」のセクションに書かれていますが、バージョンが古いようです。

WebPageTraceListener は System.Web.dll に含まれていますので、参照設定を見てそれと同じバージョンにするのがよさそうです。具体的には、今回の検証で使った環境では、以下の通りです。

<system.web>
    <trace enabled="true" pageOutput="true" 
        requestLimit="40" localOnly="false"/>
</system.web>

<system.diagnostics>
    <trace>
        <listeners>
            <add 
                name="WebPageTraceListener"
                type="System.Web.WebPageTraceListener, 
                System.Web, 
                Version=4.0.0.0, 
                Culture=neutral, 
                PublicKeyToken=b03f5f7f11d50a3a"/>
        </listeners>
    </trace>
</system.diagnostics>

上記の通り設定してブラウザから Home/Authors を呼び出すと以下のように表示されるはずです。

Home/Authors の表示

その後、ブラウザからトレースビューア Trace.axd を呼び出し、ブラウザに表示された Home/Authors 行の[詳細の表示]をクリックして[トレース情報]を見ると一番上の画像のようになっているはずです。

非同期呼び出しした AsynchronousMethod メソッドで書き込んだトレースメッセージ以外はトレースビューアに表示されているのがわかるでしょうか?

Tags: ,

MVC

Razor 構文の Web ヘルパー/ページ

by WebSurfer 2012年3月20日 16:12

ASP.NET Web サイトプロジェクト(MVC でない)でも Razor 構文の Web ページ、Web ヘルパーが使用できるということを知ったので、備忘録として書いておきます。

Web サイトプロジェクトで[ヘルパー(Razor)] を追加

Web サイトプロジェクト(MVC でない)で、ソリューションエクスプローラーから[新しい項目の追加(W)]を選ぶと、上の画像のダイアログが表示され、Razor 構文の Web ページや Web ヘルパーが選択できるのが分かります。(ちなみに、Web アプリケーションプロジェクトでは Razor 関係のメニューは表示されません)

ここで、[ヘルパー(Razor)] をクリックすると、デフォルトで Helper.cshtml という名前のヘルパーが Add_Code フォルダに追加されます。その時同時に、web.config の appSettings 要素に以下の key が追加されます。(何故か、[Web ページ (Razor)]その他ではこの key は追加されません)

<appSettings>
  <add key="webpages:Enabled" value="true" />
</appSettings>

MSDN の ASP.NET のフォーラム LoginStatus コントロールで loginUrl が反映されない の原因を調べる過程で分かったことですが、< key="webpages:Enabled" value="true" /> が設定してあると、forms 要素の loginUrl に設定したリダイレクト先(ログインページ)が無視されて、/Account/Login になってしまうという問題があります。

これを回避するためには、以下のように loginUrl キーを appSettings に追加してやります。

<appSettings>
  <add key="webpages:Enabled" value="true" />
  <add key="loginUrl" value="~/login.aspx" />
</appSettings>

< key="webpages:Enabled" value="true" /> を削除すると、追加した Web ヘルパーのソースの @helper HelperName( ... ) の下に青の波線が出て、"拡張 '.cshtml' に対して登録されたビルド プロバイダーはありません。" というエラーメッセージが表示されます。

でも、自分が試した限りでは、最終的には < key="webpages:Enabled" value="true" /> を削除しても、Razor 構文の Web ページ、Web ヘルパーはビルドでき、問題なく動きました。また、ビルド後は青の波線とエラーメッセージは出なくなりました。

Razor 構文の Web ページ、Web ヘルパーの実行結果

左の画像が、自分が試した結果���す。その時に使ったコードを以下にアップしておきます。

ただし、< key="webpages:Enabled" value="true" /> を削除しても、相変わらずログインのリダイレクト先が /Account/Login になってしまいます。

このあたり、訳が分かりませんが、Razor 構文の Web ページを追加すると、< key="webpages:Enabled" value="true" /> がデフォルトで設定されるのではないかと推測しています。(Web ヘルパーだけではデフォルトでは webpages:Enabled の value は ture にならない?)

webpages:Enabled は、MVC 3 Project Upgrade Tool の記事によると、Razor の MVC3 で、"to prevent .cshtml or .vbhtml files in the Views folder from being directly accessible from a web browser" のため、View フォルダの web.config に value="false" として設定するものだそうです。それ以上の説明は見つけられませんでした。

Razor Web ヘルパー (App_Code/QR.cshtml)

@helper GetHtml(string url, int pixelSize=150){
  // Google のチャートAPIを使って QR コード ( 二次元バーコード ) 
  // を生成する
  string sizeUrl = string.Format("{0}x{0}", pixelSize);
  string requestUrl = 
    string.Format(
      "http://chart.apis.google.com/chart?chs={0}&cht=qr&chl={1}",
      sizeUrl, 
      HttpUtility.UrlEncode(url));
    
  <img src="@requestUrl" alt="QR コード" />
}

Razor Web ページ (WebPage.cshtml)

<!DOCTYPE html>
<html>
  <head>
    <title></title>
  </head>
  <body>
    <p>@QR.GetHtml("http://surferonwww.info/")</p>
  </body>
</html>

Tags: ,

ASP.NET

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar