私の以前の投稿は、WCFでMagentoのAPIを使用する方法を扱いました。 Magentoのもう1つの側面は、テーマに対する非常に柔軟なサポートです。
デフォルトのテーマとは根本的に異なるように見える新しいテーマを設計できます。カスケードスタイルのシートの画像と色を変更できるだけでなく、ページを構成する領域(ヘッダー、コンテンツ、フッターなど)を再定義することもできます。地域ごとに、どのHTMLが注入されるかを指定できます。これにより、サイトをテーマにするための最大のカスタマイズパワーが得られます。
ASP.NETでのテーマは、すぐにサポートされています。 App_Themesフォルダーを使用すると、サイトのルックアンドフィールをカスタマイズできますが、このシステムは面倒です。
Magentoは、ASP.NET MVCフレームワークと同様に、MVCパターンを使用して構築されています。そして、それがこの記事の焦点です。 ASP.NET MVCでテーマを実装するにはどうすればよいですか?
始めましょう...
コーディングを開始する前に、達成したい目標を要約しましょう。中国、ベトナム、サウスコレアなどで作られた家具を輸入する会社を所有していると仮定しましょう。エンドユーザーに直接販売するのではなく、再販業者に販売しています。
すべての再販業者がeコマースサイトとして使用できるASP.NET MVC搭載Webアプリケーションを設計したいと考えています。各再販業者には独自のドメイン名があり、オンラインで商品を販売したいと考えています。これらの各ドメインは、単一のWebアプリケーションにリンクされています。
Webアプリケーションで提供される機能は、各リセラーで同じですが、各リセラーはカスタムテーマを適用してオンラインショップをカスタマイズしたいと考えています。次の状況をサポートします。
そのため、スタイルシート(CSS)、マスターページ、ビュー、および部分的なビューを動的に置き換える方法を把握する必要があります。
開始する前に、基礎を築く必要があります。シンプルなデモアプリケーションの基本を構築することから始めましょう。
注:このセクションでは、テーマ機能を実証できるように、デモアプリケーションのセットアップの簡単な概要を説明します。これは、迅速かつ簡単なアプローチです。この記事の焦点は、ドメインモデルの設計方法、ビジネスロジックレイヤーの設計方法などにありません。だから私はこれを可能な限り短くしています。自由に改善してください。
データベース
SQL Server Express(2005または2008)を使用して新しいデータベースを作成します。 Northwindデータベースに触発されて、データベース[WindDirection]という名前を付けました。
このデータベースには、[Reseller]と呼ばれる1つのテーブルが正確に含まれています。次の図に示すようにテーブルを設計します。
図1- [再販業者]テーブル
![リセラーテーブル [Reseller] Table Design](https://images.downcodes.com/uploads/20250616/img_68500176a3ae030.png)
ご覧のとおり、ID列が主キーであり、ID仕様(= autoincrement)を使用します。また、各再販業者には独自のドメインがあるため、ドメイン列に一意の制約を追加します。
注:この記事に付随するソースコードには、手作業で設計したくない場合にこのテーブルをすばやく生成できるスクリプト(DDL.SQL)が含まれています。
データベースの設定の最後の部分は、[再販業者]テーブルのダミーレコードを入力することです。次の記録を入力してください。
図2-再販業者

4つの再販業者がいます。最初のリセラーにはカスタムテーマがなく、デフォルトのテーマに戻ります。他のすべては、独自のカスタムテーマを定義しています。
Visual Studio 2008を開始し、「MVCApplication」というタイトルの新しい空白のソリューションを作成します。新しいコードライブラリを追加し、「cgeers.winddirection.database」と呼びます。自動生成されたClass1.CSSファイルを削除します。
次に、SQLクラスのアイテムに新しいLINQを追加し、「Dataclasses」と名付けます。新しいDataContextを「WindDirectionDatacontext」に変更します。 [再販業者]テーブルをサーバーエクスプローラータブからLINQにドラッグし、SQLデザイナーサーフェスにドラッグします。
図3-再販業者エンティティ

DataContextの接続プロパティを「none」に設定し、接続文字列アプリケーション設定とアプリケーション構成ファイル(app.config)を削除します。 Visual Studioが接続文字列を注入するという事実は好きではありません。私は自分でやりたいです。
そのため、このアセンブリに次の部分クラスを追加して、接続文字列を使用してDataContextの初期化を処理しました。私たちが同意しなければならない唯一の部分は、接続文字列に「Winddirection」という名前が付けられていることです。
リスト1 -WindDirectionDatacontextクラス
public partial class WindDirectionDataContext
{
private static readonly string ConnectionString ;
static WindDirectionDataContext ( )
{
ConnectionStringSettings settings = ConfigurationManager . ConnectionStrings [ "WindDirection" ] ;
ConnectionString = settings != null ? settings . ConnectionString : String . Empty ;
}
public WindDirectionDataContext ( ) : base ( ConnectionString ) { }
}system.configurationアセンブリへの参照を追加することを忘れないでください。このアセンブリを参照するアプリケーションに「Winddirection」という接続文字列を含める限り、それは正常に機能します。
私たちはほとんどそこにいます。ちょうど続けて、私たちはそれを通り抜けます。次に、「cgeers.winddirection.managers」と呼ばれるソリューションに新しいコードライブラリを追加します。自動化されたClass1.CSファイルを削除し、System.Data.Linqアセンブリへの参照を追加します。
マネージャーという新しいクラスを追加し、次のコードを追加します。
リスト2-要約マネージャー
public abstract class Manager
{
protected Manager ( )
{
Context = new WindDirectionDataContext ( ) ;
}
public WindDirectionDataContext Context { get ; set ; }
}この非常にシンプルなクラスは、後でLINQクエリを解き放つことができる新しいDataContextを作成します。
次に、プロジェクトに「ResellerManager」というクラスを追加し、リスト3に示すコードを追加します。
リスト3 ResellerManager
public class ResellerManager : Manager
{
public string GetThemeForDomain ( string domain )
{
var q = from r in Context . Resellers
where r . Domain == domain
select r . Theme ;
string theme = q . SingleOrDefault ( ) ;
return ! String . IsNullOrEmpty ( theme ) ? theme : "Default" ;
}
}このマネージャークラスは、抽象マネージャークラスから降りて、getTheMefordomain(...)と呼ばれる1つの方法を追加します。この方法は、特定のドメイン名に基づいて再販業者のテーマを調べます。各ドメインは1つの再販業者と一意に結び付けられているため、これは問題ありません。
Voila、それがデモアプリケーションに必要なすべてのデータアクセスです。着信要求のドメインに基づいて再販業者のテーマを把握する必要があり、それを適用する必要があります。
注:ASP.NET電源アプリケーションでLINQをSQLコンテキストに使用することに注意してください。この記事では示されていませんが、私たちの主な努力からあまり気を散らしてしまうので、要求ごとに1つのコンテキストのみを作成することをお勧めします。リクエストのhttpcontextにコンテキストを保存して、リクエスト中にいつでもアクセスできるようにします。
しばらく前に、これについて特に記事を書きました。EntityFrameworkObjectContextの記事をご覧ください。 LINQからSQLの代わりにエンティティフレームワークを扱っていますが、まだ適用されます。
基本的なデモアプリケーションを完了する最終ステップは、ソリューションに新しいWebサイトプロジェクトを追加することです。 ASP.NET MVC Webアプリケーションプロジェクトテンプレートに基づいてソリューションに新しいプロジェクトを追加し、「MVCApplication」と名付けます。このアプリケーションのユニットテストプロジェクトも作成するかどうかを尋ねられます。この記事には必要ないので、これをスキップするには「いいえ」を選択してください。
Visual Studioは、「Hello、World!」-Type ASP.NET MVCアプリケーションを生成します。接続文字列をweb.configファイルに追加し、cgeers.winddirection.databaseおよびcgeers.winddirection.managersアセンブリに参照を追加します。
注:web.configには、ASP.NETメンバーシップ、プロファイル、役割...プロバイダーを参照するいくつかの構成設定が含まれています。必要でないため、先に進んで削除できます。
ソリューションエクスプローラーは図4に似ているはずです。
図4-ソリューションエクスプローラー

注:この記事を書いている時点で、ASP.NET MVCバージョン1.0を使用しています。ただし、バージョン2.0は近い将来にリリースされます。
Webアプリケーションを実行するとき、最初に把握する必要があるのは、適用する必要があるテーマです。これは、すべてのリクエストに対して行う必要があります。そのため、リクエストパイプラインのカスタムHTTPモジュールを接続することは適切と思われます。
MVCApplicationプロジェクトに新しいクラスを追加し、themehttpmoduleと呼びます。クラスにihttpmoduleインターフェイスを実装してもらいます。このクラスのコード全体をリスト4に示します。
この記事は、HTTPモジュールの作成に関する入門書ではないため、詳細情報が必要な場合は、「ウォークスルー:カスタムHTTPモジュールの作成と登録」記事をMSDNの記事をご覧ください。
リスト4 -themehttpmodule
public class ThemeHttpModule : IHttpModule
{
public void Init ( HttpApplication application )
{
application . BeginRequest += application_BeginRequest ;
}
private void application_BeginRequest ( object sender , EventArgs e )
{
HttpApplication application = ( HttpApplication ) sender ;
HttpContext context = application . Context ;
if ( context . Cache == null )
{
return ;
}
string domain = context . Request . Url . GetDomain ( ) ;
string cacheKey = String . Format ( CultureInfo . InvariantCulture , "theme_for_{0}" , domain ) ;
if ( context . Cache [ cacheKey ] == null )
{
ResellerManager manager = new ResellerManager ( ) ;
string theme = manager . GetThemeForDomain ( domain ) ;
context . Cache [ cacheKey ] = theme ;
}
}
public void Dispose ( ) { }
}このHTTPモジュールは、BeginRrequestイベントのイベントハンドラーを追加します。このイベントは、ASP.NETがリクエストに応答したときに、HTTPパイプラインの実行チェーンでの最初のイベントとして発生します。
ここでは、着信要求からドメイン名を抽出します。次に、ResellermanagerのGetTheMefordomain(...)メソッドを使用して、このドメインのテーマを取得します。結果はキャッシュされます。次回、このドメインのリクエストがトリガーされると、テーマはキャッシュから取得され、データベースクエリは起動されません。
GetDomain()メソッドは、URIクラスの拡張メソッドです。この記事のソースコードをチェックして、それがどのように機能するかを確認してください。同様に、リクエストからサブドメイン(www、admin ...など)を抽出することを選択できます。その後、テーマエンジンを拡張して、ドメインの各サブドメインに異なるテーマを適用できます。
最後になりましたが、web.configファイルにエントリを作成して、themehttpmoduleを登録します。これは、httpモジュールをリクエストパイプライン通知にサブスクライブするために必要です。
リスト5- themehttpmoduleを登録します
< httpModules >
< add name = " ThemeHttpModule " type = " MvcApplication.ThemeHttpModule " />
<!-- ... -->
</ httpModules >Webアプリケーションを開始すると、図5に表示されているデフォルトのルック&フィールが表示されます。ビジュアルスタジオは、マスターページやスタイルシートを含むデフォルトページ(ホーム、アバウンド、ログオンなど)を生成します。これらのファイルを使用して、デフォルトのテーマを構成します。
図5 -ASP.NET MVCアプリケーションデフォルトテーマ

デフォルトでは、すべてのファイルがコンテンツフォルダーとビューフォルダーに保存されます。テーマを論理的にグループ化できるように、独自のディレクトリ構造を実装する必要があります。したがって、テーマと呼ばれる新しいフォルダーを作成します。テーマディレクトリのサブフォルダーを作成し、デフォルトと呼びます。このデフォルトのディレクトリの下にあるコンテンツとビューディレクトリを移動します。
コンテンツとビューのフォルダーを移動した後、各ビューのページディレクティブのMasterPageFileプロパティを調整する必要があります!古い値は、もはや存在しない場所を参照しています。 MasterPageFile = "〜/views/shared/site.master" to masterpagefile = "〜/themes/default/views/shared/site.master" !
図6-デフォルトのテーマ

私たちのデフォルトのテーマがセットアップされました。新しいテーマを作成する場合は、新しいフォルダーを作成してテーマフォルダーの下に配置するだけです。前のスクリーンショットでわかるように、後で他のテーマ(緑、オレンジ、赤)を作成します。
マスターページ、スタイルシート、ビューなどを移動しました。別のディレクトリに。今すぐWebアプリケーションを開始した場合、次の例外を受け取ります。
図7 -InvalidoperationException

「インデックス」またはそのマスターのビューは見つかりませんでした。次の場所が検索されました。
MVCは、デフォルトの開始ページのビューを見つけようとしていますが、検索するデフォルトの場所でそれを見つけることができないため、例外を受け取ります。これらのファイルをデフォルトのテーマフォルダーに移動し、すぐに他のテーマを作成します。 MVCに、そのビュー、マスターページ、部分的なビューなどを検索する場所をMVCに通知する方法が必要です。これらの場所は、再販業者のテーマに依存します。
したがって、基本的に、ASP.NET MVCでテーマをサポートするために必要なことは、次のとおりです。
これを行うには、独自のビューエンジンを作成する必要があります。 MVCは、ビューエンジンを使用して、応答のページをレンダリングします。このビューエンジンは、マスターページ、ビュー、および部分的なビューを見つける責任があります。デフォルトでは、WebFormViewEngineが使用されます。
このデフォルトビューエンジンを独自に置き換える必要があります。これを行うには、MVCApplicationプロジェクトにThemedViewEngineと呼ばれる新しいクラスを追加し、WebFormViewEngineクラスから下降します。
リスト6 -ThemedViewEngine
public class ThemedViewEngine : WebFormViewEngine
{
#region Constructor(s)
// Replace the default search paths by our own.
public ThemedViewEngine ( )
{
// Search paths for the master pages
base . MasterLocationFormats = new [ ]
{
"~/Themes/{2}/Views/{1}/{0}.master" ,
"~/Themes/{2}/Views/Shared/{0}.master"
} ;
// Search paths for the views
base . ViewLocationFormats = new [ ]
{
"~/Themes/{2}/Views/{1}/{0}.aspx" ,
"~/Themes/{2}/Views/{1}/{0}.ascx" ,
"~/Themes/{2}/Views/Shared/{0}.aspx" ,
"~/Themes/{2}/Views/Shared/{0}.ascx" ,
} ;
// Search parts for the partial views
// The search parts for the partial views are the same as the regular views
base . PartialViewLocationFormats = base . ViewLocationFormats ;
}
#endregion
}この新しいビューエンジンのコンストラクターでは、MasterLocationFormats、ViewLocationFormats、およびPartialViewLocationFormatsを新しい場所に設定します。
各パスには、動的に決定された3つの部分が含まれています。
新しいビューエンジンを使用するには、登録する必要があります。これを行い、Global.asax.csファイルにあるApplication_startイベントハンドラーに次のコードを追加します。
リスト7- ThemedViewEngineを登録します
protected void Application_Start ( )
{
ViewEngines . Engines . Clear ( ) ;
ViewEngines . Engines . Add ( new ThemedViewEngine ( ) ) ;
RegisterRoutes ( RouteTable . Routes ) ;
}ここでは、以前にロードされた可能性のあるビューエンジンをクリアし、独自のビューを注入します。残っているのは、リクエストされたファイルを正しく見つけるように、新しい検索パスをフォーマットする方法をエンジンに指示することです。これを行うには、次の2つの方法をオーバーライドする必要があります。
リスト8 -FindPartialView(...)&FindView(...)メソッド
public override ViewEngineResult FindPartialView ( ControllerContext controllerContext , string partialViewName , bool useCache )
public override ViewEngineResult FindView ( ControllerContext controllerContext , string viewName , string masterName , bool useCache )ここには、これら2つの機能のコードをここに含めるつもりはありません。なぜなら、それは非常に長く、プライベートヘルパー方法へのいくつかの参照があるからです。基本的に、これらの2つの方法は同じパターンに従います。
したがって、新しいビューエンジンは基本的にテーマフォルダーを検索し、要求されたマスターページを見つけることができない場合は、デフォルトテーマのビューまたは部分的なビューを使用します。もちろん、デフォルトのテーマは完全である必要があり、不足しているファイルを持つことはできません。
これにより、マスターページのみを含むテーマを作成することができます。このテーマは、異なるスタイルを整えたいセクションのみのビューや部分的なビューを含む異なるスタイルシートまたはテーマを参照することができます。
このパターンに従うことにより、特定のビューをオーバーライドするだけで、カスタムビューが提供されていない場合はデフォルトテーマのビューに頼るテーマを作成できます。
私は、ASP.NET MVCでのテーマに関するChris Pietschmannの優れた記事の作業に基づいて自分のビューエンジンに基づいています。ビューエンジンが内部的にどのように機能するかについての詳細情報が含まれているため、彼の記事をチェックアウトすることをお勧めします。
新しいView Engineを設置すると、マスターページ、ビュー、および部分的なビューのリクエストを解決できるため、例外なくWebアプリケーションを再度実行できます。
注:ビューエンジンが特定のマスターページのリクエストを解決できない場合、ビュー、または部分的なビューがデフォルトのテーマで見つかったものに戻るように、コードを少し変更しました。この記事のソースコードも必ずチェックしてください。
すぐに新しいテーマを作成しましょう。 Themes Folderの下に「Red」という新しいフォルダーを追加します。次の図に示すように、デフォルトのテーマからsite.master and site.cssをコピーします。
図8-赤いテーマ

赤いテーマのスタイルシートを開き、ボディ要素の背景色プロパティを変更します。それを赤に設定します。 [再販業者]テーブルを開き、ドメインがLocalHostに設定されている再販業者のテーマフィールドを「赤」に設定します。 Webアプリケーションを再起動すると、赤いテーマのマスターページとスタイルシートを使用する必要があります。
図9-動作中の赤いテーマ

同様に、マスターページだけでなく、ホームページの別のビューも含むオレンジ色のテーマを作成できます。
図10-オレンジ色のテーマ

オレンジ色のテーマは、デフォルトのビューではなく、ホームページの新しいビューをレンダリングします。部分的なビューを交換したい場合は、同じ方法でそうすることができます。デフォルトの部分的なビューを新しいテーマフォルダーの下の同じ場所にコピーして、必要に応じて調整してください。
各テーマについて、さまざまなマスターページ、ビュー、部分的なビューを提供できるようになりました。私がサポートしたい残りのシナリオが1つあります。デフォルトのビューに満足しているが、ロゴ、いくつかの色などのみを調整したい再販業者。デフォルトのテーマに別のスタイルシートを適用することで、簡単に満足できます。
テーマディレクトリの下に新しいテーマフォルダーを追加し、グリーンと呼びます。次の図に示すように、デフォルトテーマのスタイルシートをグリーンテーマにコピーします。
図11-緑のテーマ

緑のテーマのスタイルシートを開き、ボディ要素の背景色のプロパティを緑に調整します。ドメインLocalHostにグリーンにリセラーのテーマを設定し、アプリケーションを開始すると、デフォルトテーマのスタイルシートを使用していることがわかります。
これは、緑のテーマに独自のマスターページがないという事実が原因です。デフォルトのテーマのマスターページを使用し、このマスターページは独自のスタイルシートを参照しています。
デフォルトのテーマのマスターページを開き、行を置き換えます。
< link href =" ../../Content/Site.css " rel =" stylesheet " type =" text/css " />と
< link href =" <% " ="Html.GetThemedStyleSheet()" % /> rel="stylesheet"
type="text/css" / >GetThemedStylesheet()メソッドは、HTMLユーティリティクラスの拡張メソッドです。 htmlhelperextensionsという新しいクラスをプロジェクトに追加し、次のコードを追加します。
リスト9 -htmlhelperextensions
public static class HtmlHelperExtensions
{
public static string GetThemedStyleSheet ( this HtmlHelper html )
{
HttpContext context = HttpContext . Current ;
if ( context == null )
{
throw new InvalidOperationException ( "Http Context cannot be null." ) ;
}
string defaultStyleSheet = context . Server . MapPath ( "~/Themes/Default/Content/Site.css" ) ;
string domain = context . Request . Url . GetDomain ( ) ;
string cacheKey = String . Format ( CultureInfo . InvariantCulture , "theme_for_{0}" , domain ) ;
string theme = ( string ) context . Cache [ cacheKey ] ;
if ( String . IsNullOrEmpty ( theme ) || theme == "Default" )
{
return defaultStyleSheet ;
}
string styleSheet = context . Server . MapPath ( String . Format ( CultureInfo . InvariantCulture ,
"~/Themes/{0}/Content/Site.css" , theme ) ) ;
if ( ! File . Exists ( styleSheet ) )
{
styleSheet = defaultStyleSheet ;
}
return String . Format ( CultureInfo . InvariantCulture , "'{0}'" , styleSheet ) ;
}
}GetThemedStylesheet()メソッドは、httpapplicationのキャッシュからテーマをロードし、このテーマに独自のスタイルシートがあるかどうかをチェックします。そうでない場合は、デフォルトのテーマのスタイルシートに戻ります。コードにはいくつかのハードコーディングされた文字列が含まれていますが、最適ではありませんが、トリックを行います。この方法を自由に改善してください。
今すぐWebアプリケーションを開始すると、素敵な緑の背景が得られます。
この記事では、ASP.NET MVCでテーマを有効にする方法を示します。そのためには、2つのことだけを実装する必要があります。
実装したテーマシステムは、デフォルトのテーマを使用し、このデフォルトテーマの一部をカスタムテーマの部分に置き換える必要があるかどうかをチェックします。次のシナリオのいずれかを簡単にサポートするか、それらを組み合わせることができます。