自动生成强类型的AppSettings类

Dan*_*son 5 c# asp.net t4 facade appsettings

这是第一个问题:

这可能吗?我从Joe Wrobel的工作中获取灵感(减少了被遗忘的Codeplex项目).在这里,您完成了为提供程序创建配置文件的工作,并为其创建强类型的工作,有效地为Profile类创建了一个Facade.

现在是背景故事!

我真的不喜欢魔法弦.它们非常糟糕,在更新应用程序时可能会导致严重的问题.在PHP和ColdFusion等语言中工作之后,我知道很容易将它们放入应用程序并忘记它们,直到您需要更改它们.然后你必须追捕它们的每一个变化并相应地改变它们.

如果您遵循"开箱即用"的应用程序模板,.NET实际上并没有那么好.很多例子都使用web.config中的appsetting来存储各种设置.这确实是一个存储的好地方,非常适合大多数应用程序.然而,当您开始直接调用这些问题时,问题就开始出现了 - 例如ConfigurationManager.AppSettings["MyAppSetting"].然后,当你回到使用魔术字符串时,你并没有比PHP用户更好.

这就是外墙进来的地方.外墙提供了一种在一个地方从魔术字符串创建强类型对象的方法,并让开发人员从应用程序的其余部分引用它.

现在,我没有使用web.config来包含我的appsettings,而是使用数据库来保存它们.在应用程序启动时,将检索名称/值组合,然后将其顺序添加到ConfigurationManager.AppSettingsvia Set.没什么大不了的(除了我之前的问题!).

这个"应用程序外观"可以通过我的数据层,服务层和表示层访问,并保存应用程序模式,使用yada yada yada的服务端点,并限制必须寻找许多魔法字符串,最多两个魔法strings - facade中的一个(名称),以及创建点中的另一个(名称和值)(对我来说是db).

这个门面类最终会变得非常大,我最终会厌倦不得不更新它们.

所以我想要做的是拥有一个ApplicationFacade类,每次构建完成后都会自动生成.现在又回到了开始......这可能吗?

Che*_*rek 7

您也可以使用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>
Run Code Online (Sandbox Code Playgroud)

处理完模板后,您将获得以下课程

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;

    }
}
Run Code Online (Sandbox Code Playgroud)

将以下代码保存到*.tt文件并包含到要放置生成文件的项目中.要在每个构建上重新生成类,请在此处查看我的答案 模板从值中识别字符串,日期时间,整数和布尔类型

<#@ 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

#>
Run Code Online (Sandbox Code Playgroud)