5

最初の質問は次のとおりです。

これは可能ですか?Joe Wrobel の作品(忘れられたCodeplex プロジェクトのリダックス)からインスピレーションを得ています。ここでは、プロバイダーのプロファイルを作成する作業を行います。これにより、プロバイダーの厳密な型指定を作成する作業が行われ、Profile クラスのファサードが効果的に作成されます。

そしていよいよ裏話!

私は魔法の糸が本当に好きではありません。それらは非常に悪いものであり、アプリケーションの更新に関して深刻な問題を引き起こす可能性があります。PHP や ColdFusion などの言語で働いてきた経験から、それらをアプリケーションに組み込むと、変更が必要になるまで忘れてしまいがちであることを私は知っています。そして、それらのすべてのバリエーションを探し出し、それに応じて変更する必要があります。

.NET は、「すぐに使える」アプリケーション テンプレートに従っている場合、それほど優れているとは言えません。多くの例では、web.config の appsettings を使用してさまざまな設定を保存しています。これは実際に保存するのに最適な場所であり、ほとんどのアプリケーションに最適です。ただし、これらを直接呼び出し始めると、問題が発生し始めます。たとえば、ConfigurationManager.AppSettings["MyAppSetting"]. その後、魔法の文字列を使用するようになるため、PHP ユーザーよりもはるかに優れているとは言えません。

ここでファサードの出番です。ファサードは、マジック ストリングから厳密に型指定されたオブジェクトを 1 か所で作成し、開発者がそれをアプリケーションの残りの部分から参照できるようにする方法を提供します。

今では、web.config を使用して appsettings を含める代わりに、データベースを使用してそれらすべてを保持しています。アプリケーションの開始時に、名前と値の組み合わせが取得され、順番にConfigurationManager.AppSettingsviaに追加されSetます。大したことはありません(私が以前に抱えていた問題は別として!)。

この「アプリケーション ファサード」は、データ レイヤー、サービス レイヤー、およびプレゼンテーション レイヤーからアクセスでき、アプリケーション モードなどを保持します。どのサービス エンドポイントが yada yada yada を使用するか、多くのマジック ストリングを探す必要性を 2 つのマジックに制限します文字列 - 1 つ (名前) はファサードにあり、もう 1 つ (名前と値) は作成時点 (私にとってはデータベース) にあります。

このファサード クラスは最終的にかなり大きくなり、最終的には両方を更新しなければならないことにうんざりするでしょう。

だから私がやりたいのは、ビルドが完了するたびに自動生成される ApplicationFacade クラスを持つことです。そして今、最初に戻ります...これは可能ですか?

4

3 に答える 3

8

この目的で CodeSmith テンプレートを使用することもできます。利点は、ビルドごとに再生成されるようにテンプレート ファイルのプロパティを設定できることです (BuildAction = "Complile" を設定します)。

編集 私もそのような解決策を探しました。グーグルで調べた後、そのようなクラスを生成するベース T4 テンプレートを見つけました。私はそれを再設計しました、そしてあなたはそれを以下で見つけることができます。

テンプレートは、Web.config/App.config ファイルから appSetting セクションのラッパー クラスを生成しています

設定ファイルに次の設定行があるとします

  <appSettings>
    <add key="PageSize" value="20" />
    <add key="CurrentTheme" value="MyFavouriteTheme" />
    <add key="IsShowSomething" value="True" />
  </appSettings>

テンプレートを処理した後、次のクラスを取得します

namespace MyProject.Core
{
    /// <remarks>
    /// You can create partial class with the same name in another file to add custom properties
    /// </remarks>
    public static partial class SiteSettings 
    {
        /// <summary>
        /// Static constructor to initialize properties
        /// </summary>
        static SiteSettings()
        {
            var settings = System.Configuration.ConfigurationManager.AppSettings;
            PageSize = Convert.ToInt32( settings["PageSize"] );
            CurrentTheme = ( settings["CurrentTheme"] );
            IsShowSomething = Convert.ToBoolean( settings["IsShowSomething"] );
        }

        /// <summary>
        /// PageSize configuration value
        /// </summary>
        public static readonly int PageSize;

        /// <summary>
        /// CurrentTheme configuration value
        /// </summary>
        public static readonly string CurrentTheme;

        /// <summary>
        /// IsShowSomething configuration value
        /// </summary>
        public static readonly bool IsShowSomething;

    }
}

次のコードを *.tt ファイルに保存し、生成されたファイルを配置するプロジェクトにインクルードします。ビルドごとにクラスを再生成するには、ここで私の回答を参照してください テンプレートは、値から文字列、日時、int、およびブール型を認識します

<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="Microsoft.VisualBasic" #>
<#@ template language="VB" debug="True" hostspecific="True"  #>
<#@ output extension=".Generated.cs" #>
<#
    Dim projectNamespace as String = "MyProject.Core"
    Dim className as String = "SiteSettings"
    Dim fileName as String = "..\..\MyProject.Web\web.config"

    Init(fileName)  

#>
//------------------------------------------------------------------------------
// FileName = <#= path #>
// Generated at <#= Now.ToLocaltime() #>
//
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
//     
//    NOTE: Please use the Add a Reference to System.Configuration assembly if 
//          you get compile errors with ConfigurationManager
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Configuration;

namespace <#= projectNamespace #>
{
    /// <remarks>
    /// You can create partial class with the same name in another file to add custom properties
    /// </remarks>
    public static partial class <#= className #> 
    {
        /// <summary>
        /// Static constructor to initialize properties
        /// </summary>
        static <#= className #>()
        {
            var settings = System.Configuration.ConfigurationManager.AppSettings;
<#= AddToCostructor(path) #>        }

<#= RenderApplicationSettings(path) #>  }
}

<#+ 
    Dim path as String = ""
    Dim doc as XDocument = Nothing

    Public Sub Init(fileName as String)
        Try
            path = Host.ResolvePath(fileName)
            If File.Exists(path) Then
                doc = XDocument.Load(path)
            End If
        Catch
            path = "<< App.config or Web.config not found within the project >>"
        End Try     
    End Sub

    Public Function AddToCostructor(ByVal path as String) as String                 
        If doc Is Nothing Then Return ""

        Dim sb as New StringBuilder()

        For Each result as XElement in doc...<appSettings>.<add>            
            sb.Append(vbTab).Append(vbTab).Append(vbTab)
            sb.AppendFormat("{0} = {1}( settings[""{0}""] );", result.@key, GetConverter(result.@value))
            sb.AppendLine()
        Next

        Return sb.ToString()

    End Function

    Public Function RenderApplicationSettings(ByVal path as String) as String
        If doc Is Nothing Then Return ""

        Dim sb as New StringBuilder()       

        For Each result as XElement in doc...<appSettings>.<add>    
            dim key = result.@key
            sb.Append(vbTab).Append(vbTab)
            sb.Append("/// <summary>").AppendLine()
            sb.Append(vbTab).Append(vbTab)
            sb.AppendFormat("/// {0} configuration value", key).AppendLine()            
            sb.Append(vbTab).Append(vbTab)
            sb.Append("/// </summary>").AppendLine()
            sb.Append(vbTab).Append(vbTab)
            sb.AppendFormat("public static readonly {0} {1}; ", GetPropertyType(result.@value), key)    
            sb.AppendLine().AppendLine()
        Next

        Return sb.ToString()

    End Function

    Public Shared Function GetConverter(ByVal prop as String) as String     
        If IsNumeric(prop) Then Return "Convert.ToInt32"
        If IsDate(prop) Then Return "Convert.ToDateTime"
        dim b as Boolean
        If Boolean.TryParse(prop, b) Then Return "Convert.ToBoolean"        
        Return ""
    End Function

    Public Shared Function GetPropertyType(ByVal prop as String) as String
        If IsNumeric(prop) Then Return "int"
        If IsDate(prop) Then Return "DateTime"
        dim b as Boolean
        If Boolean.TryParse(prop, b) Then Return "bool"
        Return "string"
    End Function

#>
于 2010-07-31T20:41:07.370 に答える
1

ビルド前のステップでこれを行うことができます。これを行うのはかなり簡単です。クラスを再生成するプログラム、スクリプト、またはテンプレートを作成し、ビルド前のイベントでそれを呼び出すだけです。再生した。

T4 テンプレートを作成し、それをプロジェクトに含める方法は、もう少し手動ですが、おそらくより便利な方法です。ただし、新しい設定を追加するたびにテンプレートを再変換することを忘れないでください。これは負担が大きすぎるでしょうか?

于 2009-10-18T01:04:11.207 に答える