2009-10-18 23 views
5

ここで最初の質問です:自動生成する、厳密に型指定されたのAppSettingsクラス

が可能これですか?私はJoe Wrobel's work(忘れたCodeplex projectの還元)から私のインスピレーションを受けています。ここでは、プロバイダー用のプロファイルを作成する作業を行い、強力な型定義を作成して、Profileクラスのファサードを効果的に作成します。

今やバックストーリー!

私は本当に好きではないmagic strings。彼らはかなり悪いですし、あなたのアプリケーションを更新することにいくつかの重大な問題を引き起こす可能性があります。 PHPやColdFusionのような言語で作業していたので、あなたのアプリケーションに入れて、変更するまで忘れてしまうのは簡単です。そして、あなたはそれぞれの変化を狩り、それに応じて変えなければなりません。

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

ここにはfacadesが入ります。ファサードは、マジックストリングから1つの場所に強く型付けされたオブジェクトを作成し、アプリケーションの残りの部分から参照するように開発者を呼び出す方法を提供します。

今、私のappsettingsを格納するためにweb.configを使用する代わりに、それらをすべて保持するためにデータベースを使用します。アプリケーションの開始時に、名前/値のコンボが取得され、にSetを介して順番に追加されます。いいえ、私は以前持っていたproblemから離れています。

この「アプリケーションファサード」は、データレイヤー、サービスレイヤー、プレゼンテーションレイヤーからアクセス可能で、アプリケーションモードのようなものを保持しています。サービスエンドポイントは、yada yada yadaを使用し、多くのマジックストリング、 2つの魔法の弦に至るまで - ファサードの名前(名前)と創造のポイントの名前と値(これは私にとってはデータベース)です。

このファサードクラスは最終的にかなり大きくなり、最終的には両方を更新することに疲れてしまいます。

私がしたいのは、ビルドが完了するたびに自動的に生成されるApplicationFacadeクラスです。そして今、始めに戻って...これは可能ですか?

答えて

7

この目的でCodeSmithテンプレートを使用することもできます。利点は

(ビルドアクション=「Complile」を設定)を使用すると、各ビルドに再生成するテンプレートファイルのプロパティで設定することができるということです編集 私はまた、このような解決策を探しました。グーグルの後、私はそのようなクラスを生成するためのベースT4テンプレートを見つけました。 私はそれを再設計しました。あなたはそれを下に見つけることができます。

テンプレートがあなたのWeb.configからのAppSettingセクションのラッパークラスを生成している/ App.configファイルは

はあなたが以下を取得するテンプレートを処理した後、configファイル

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

の設定の行を次したとファイル* .ttファイルへのクラス次のコードを保存

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; 

    } 
} 

とヨーヨーに含まあなたが生成されたファイルを置く場所である。各上のクラスを再生成する はsee my answer here テンプレートを構築

<#@ 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}""]);", [email protected], GetConverter([email protected])) 
      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 = [email protected] 
      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([email protected]), 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 

#> 
+0

これは興味深い考えですが、正直言ってCodeSmithの大ファンではありません。最終的には、自分のアプリケーションのタイプを推論するアプリケーションがないため、どのような場合でも必要なクラスを作成しました。 –

+1

私のポストに少しのコードを追加しました。それがあなたを助けることができると願っています – Cheburek

+0

それは本当に面白い解決策です!それが問題を抱えていると思われるもの(これはVBのIsNumericです)は、VBが数値であると考える「0,5,0」ですが、どういうことかわかりません。 –

1

これは、ビルド前の手順で実行できます。これはかなり簡単です - クラスを再生成するプログラムやスクリプトやテンプレートを書くだけでビルド前のイベントで呼び出すことができますが、クラスが取得されるまで、新しいメンバーには赤い揺れやインテリセンスはありません再生された。

少し手作業だが、おそらくもっと便利な方法は、T4 templateを作成してプロジェクトに組み込むことです。ただし、新しい設定を追加するたびにテンプレートを再変換する必要があります。これはあまりにも面倒だろうか?

+0

値から文字列、日時、int型やブール型を認識し、あなたの応答をありがとう!現実的には、私が何をするにしても、ファサードクラスを埋める全プロセスは自動であり、開発者は何も必要としません。これを行うことができることをあなたが知っている既存のリソースがありますか? –

+0

ええと、あなたはASP.NETにいるので、System.Web.Compilation名前空間を使ってこれを行うことができます。これは、ASP.NET Webサイトプロジェクトがプロファイルクラスを作成するために使用するものです。残念ながら、これは私の知識の範囲外です。Webアプリケーション(.csprojベース)プロジェクトで動作するかどうかはわかりません。ごめんなさい。あなたの別のオプションは、VSカスタムツール(IVsSingleFileGenerator)を見ることですが、異なるシナリオ用に設計されており、設定定義が独自の特別なファイルに保存されている場合にのみ機能します。 – itowlson

+0

これは - http://blog.jqweb.ca/?p=44 - 私が使用できるもののように見えるが、web.configではなくdbから引き出すために適応する必要がある...私は、もし私が解決策を見つけたら、更新するでしょう。 –

関連する問題