自动生成强类型的AppSettings类 [英] Auto-generate a strongly-typed AppSettings class

查看:121
本文介绍了自动生成强类型的AppSettings类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先是问题:

这可能吗?我的灵感来自 Joe Wrobel的著作(被遗忘的

Is this possible? I'm taking my inspiration from Joe Wrobel's work (a redux of the forgotten Codeplex project). Here, you do your work on creating your profile for the provider, and it does the legwork of creating the strong typing for it, effectively creating a facade for the Profile class.

现在是背景故事!

我真的不喜欢魔术字符串.它们非常糟糕,在更新应用程序时可能会导致一些严重的问题.在使用PHP和ColdFusion等语言进行工作之后,我知道将它们轻松放入您的应用程序中,而不必更改它们,直到您需要更改它们时,就很容易了.然后,您必须逐一寻找它们的每个变体,并进行相应的更改.

I really don't like magic strings. They're pretty bad and can cause some serious issues when it comes to updating your application. Having worked in languages like PHP and ColdFusion, I know that it's easy to put them into your application and forget about them until you need to change one. And then you have to hunt each and every variation of them down and alter them accordingly.

.NET确实并没有那么好.那里有很多示例使用web.config中的appsettings来存储各种设置.这确实是一个很好的存储位置,并且对于大多数应用程序来说都是完美的选择.但是,当您开始直接调用它们时,就会开始出现问题-例如 ConfigurationManager.AppSettings ["MyAppSetting"] .然后,当您返回使用魔术字符串时,您实际上并没有比PHP用户更好的地方.

.NET really isn't that much better if you follow the 'out of the box' application templates. Lots of examples out there use the appsettings in the web.config to store various settings. This is indeed a fine place to store, and is perfect for most applications. Problems start to arise however, when you start calling these directly - for example ConfigurationManager.AppSettings["MyAppSetting"]. Then you're not really any better off than a PHP user as you're back to using magic strings.

这是外观出现的地方.一种从一个地方的魔术字符串创建强类型对象的方法,让开发人员从应用程序的其余部分引用该对象.

This is where facades come in. Facades offer a way of creating a strongly-typed object from a magic string in one place, and having the developer reference that from the rest of the application.

现在,我不是使用web.config来包含我的应用程序设置,而是使用数据库来保存所有设置.在应用程序启动时,将检索名称/值组合,然后通过 Set 将它们顺序添加到 ConfigurationManager.AppSettings 中.没什么大不了的(除了问题我早一点!).

Now, instead of using a web.config to contain my appsettings, I use a database to hold them all. On application start, the name/value combos are retrieved, and are then sequentially added to the ConfigurationManager.AppSettings via Set. No biggie (apart from the problem I had earlier!).

此应用程序外观"可通过我的数据层,服务层和表示层访问,并包含诸如应用程序模式之类的内容,该服务端点使用yada yada yada并限制了必须寻找许多魔术字符串的需求,到两个魔术字符串-一个(在外观中)(名称),另一个(在名称上)(在我看来是db)(在我看来是db).

This 'application facade' is accessible by my data layer, service layer and presentation layer and holds things like the application mode, which service endpoint to use yada yada yada and limits the need for having to hunt for many magic strings, down to two magic strings - one (the name) in the facade, and the other (the name and value) in the point of creation (which, for me is the db).

这个外观类最终将变得非常庞大,而我最终将不得不对它们进行更新而感到厌烦.

This facade class will eventually get pretty big and I'll eventually get tired of having to update both of them.

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

So what I'd like to do is have an ApplicationFacade class which auto-generates every time a build is done. And now back to the beginning... Is this possible?

推荐答案

您也可以为此使用CodeSmith模板.优点是您可以在模板文件属性中设置要在每次构建时重新生成(设置BuildAction ="Complile")

You could also use CodeSmith templates for this purpose. Advantage is that you can set in template file properties to be regenerated on each build (set BuildAction = "Complile")

已编辑我也正在寻找这样的解决方案.谷歌搜索后,我发现了基本的T4模板来生成这样的类.我已经对其进行了重新设计,您可以在下面找到它.

Edited I also looked for such solution. After googling I found base T4 template to generate such a class. I have redesigned it and you can find it below.

模板正在从Web.config/App.config文件为appSetting部分生成包装器类

Template is generating wrapper class for appSetting section from your Web.config/App.config file

假设您在配置文件中有以下几行设置

Suppose you have following lines of settings in config file

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

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

After processing template you will get following class

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文件,并将其包含在要放置生成文件的项目中.要在每个版本上重新生成类,请在这里查看我的答案模板从值中识别字符串,日期时间,整数和布尔类型

Save following code to *.tt file and include to your project where you want to put generated file. To regenerate class on each build see my answer here Template recognize string, datetime, int and bool types from values

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

#>

这篇关于自动生成强类型的AppSettings类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆