使用 Genuilder.Extensibility 的强类型 AppSettings






4.71/5 (5投票s)
Genuilder.Extensibility 的实际用例:强类型 AppSettings。
目录
介绍
我上一篇关于 Genuilder.Extensibility 的文章 并不成功,我博客上的一个读者 告诉我,那是因为它没有展示任何实际用例。所以在这里!
目标是创建一个代码生成器,它允许您以类型安全的方式使用 AppSettings。我已经完成了关于此方面的文章,并将其集成到 Genuilder 中。问题在于,要理解我如何做到的,您必须理解 MSBuild 的工作原理。所以今天,我将向您展示如何使用 Genuilder.Extensibility 自己实现此功能。
安装
我将不再解释如何安装 Genuilder,因为它已在 CodePlex 和 我的上一篇文章 中进行了充分描述。
创建插件
因此,让我们创建两个项目:第一个是一个包含配置文件和一些 appSettings 的控制台应用程序。第二个是我们的功能项目,一个类库。
不要忘记,功能项目的结尾必须是 .Gen。
让我们在功能项目中创建插件 StronglyTypedAppSettingsPlugin。
在此代码片段中,我订阅了 CodeRepository
的 CodeItemCreated
事件。此事件针对项目中的每个源代码文件 + 配置文件触发。
然后,我在我的配置文件和名为 StronglyTypedSettings.cs 的目标文件之间创建一个依赖关系。
public class StronglyTypedAppSettingsPlugin : IPlugin
{
#region IPlugin Members
public void Initialize(ICodeRepository repository)
{
repository.CodeItemCreated +=
new CodeItemCreatedHandler(repository_CodeItemCreated);
}
void repository_CodeItemCreated(ICodeRepository sender, CodeItem item)
{
if(item.Name.EndsWith(".config"))
{
var dependency = item.SourceOf("StronglyTypedSettings.cs");
dependency.ShouldUpdateTarget +=
new CodeDependencyHandler(dependency_ShouldUpdateTarget);
}
}
dependency_ShouldUpdateTarget
基于配置文件生成 StronglyTypedSettings.cs 中的代码。
void dependency_ShouldUpdateTarget(CodeDependency sender, CodeItem target)
{
var configuration =
ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap()
{
ExeConfigFilename = ((FileCodeItem)sender.Source).File.FullName
}, ConfigurationUserLevel.None);
string generatedClass = "public static class AppConfigSettings{";
foreach(KeyValueConfigurationElement setting in configuration.AppSettings.Settings)
{
string getter = "public static System.String " + setting.Key +
" { get{ return System.Configuration.ConfigurationManager.AppSettings[\"" +
setting.Key + "\"]; } }";
generatedClass += getter;
}
generatedClass += "}";
target.Content = generatedClass;
为了展示如何将警告和错误通知发送到构建,让我们在每次更新 StronglyTypedSettings.cs 时发送一个警告。
target.Logger.Send("Settings generated !!",
Genuilder.Extensibility.Utilities.LogType.Warning);
}
#endregion
}
这是控制台应用程序中的配置文件
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="SomeKey" value="SomeValue"/>
</appSettings>
</configuration>
构建 ConsoleApplication1 并享受这个过程。
您甚至可以看到警告消息。
正如您所看到的,当您重新构建时,警告不会出现,因为源文件(App.config)没有更改。如果修改您的功能项目,则必须在构建之前清理项目。
此插件仅在 C# 中有效,如何让它在 VB.NET 中也有效?
我们只需修改 dependency_ShouldUpdateTarget
以使用 NRefactory 扩展。但在那之前,让我们在我们的项目中引用 NRefactory 集成程序集。
这是使用 CompilationUnitExtension
(NRefactory 扩展)的 dependency_ShouldUpdateTarget
的代码... 稍微复杂一些,但可以在 C# 和 VB.NET 中使用!!
void dependency_ShouldUpdateTarget(CodeDependency sender, CodeItem target)
{
var configuration =
ConfigurationManager.OpenMappedExeConfiguration(
new ExeConfigurationFileMap()
{
ExeConfigFilename = ((FileCodeItem)sender.Source).File.FullName
}, ConfigurationUserLevel.None);
var targetNRefactoryExtension =
target.GetExtension<Genuilder.Extensibility.NRefactory.CompilationUnitExtension>();
targetNRefactoryExtension.CompilationUnit.Children.Clear();
var typeDeclaration = new TypeDeclaration(Modifiers.Public | Modifiers.Static, null)
{
Name = "AppConfigSettings"
};
targetNRefactoryExtension.CompilationUnit.Children.Add(typeDeclaration);
foreach(KeyValueConfigurationElement setting in configuration.AppSettings.Settings)
{
var propertyDeclaration = new PropertyDeclaration(
Modifiers.Public | Modifiers.Static, null, setting.Key, null)
{
TypeReference = new TypeReference(typeof(String).FullName)
};
var indexer = new IndexerExpression(
new MemberReferenceExpression(
new TypeReferenceExpression(
new TypeReference(typeof(ConfigurationManager).FullName)), "AppSettings")
, new List<Expression>()
{
new ICSharpCode.NRefactory.Ast.PrimitiveExpression(setting.Key)
});
propertyDeclaration.GetRegion = new PropertyGetRegion(new BlockStatement(), null);
propertyDeclaration.GetRegion.Block.Children.Add(new ReturnStatement(indexer));
typeDeclaration.Children.Add(propertyDeclaration);
}
targetNRefactoryExtension.Save();
target.Logger.Send("Settings generated !!",
Genuilder.Extensibility.Utilities.LogType.Warning);
}
结论
好吧,就这样。我很自豪我的文章简短且快速完成,这表明它们并不复杂!!
我非常有兴趣听取您关于新插件的想法。如果我受到激励,我很乐意实现它们!;)