自动生成强类型的AppSettings类 [英] Auto-generate a strongly-typed AppSettings class
问题描述
首先是问题:
这可能吗?我的灵感来自 Joe Wrobel的著作(被遗忘的 Codeplex项目).在这里,您将为提供者创建个人资料,并为它创建强类型,有效地为Profile类创建外观,这是一项繁琐的工作.
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.
现在是背景故事!
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屋!