Azure工作角色配置文件转换

10

我已经设置了一个新的工作角色,并通过SlowCheetah设置了一些新的配置转换。当我选择其中一个新配置进行项目构建时,实际上会在\bin文件夹下创建configs文件夹,就如您所期望的那样(例如:\bin\Production)。

当我使用其中一个新配置打包云服务以进行部署时,我的Web项目可以适当地进行配置转换,但我的工作角色库却没有,尽管我在\bin文件夹下看到了更新的\bin\production。

似乎Azure打包工具正在忽略工作角色库设置的配置。我该如何让它从适当的配置中选择配置文件?


cspack(Azure 打包工具)不依赖于应用程序配置(app.config),而是使用服务定义,如此处所述 http://msdn.microsoft.com/en-us/library/gg432988.aspx。如果您能提供有关在构建配置中要包含哪些 app config 设置以及它们如何定义的更多信息,我可以提供帮助。另外,您是通过命令行还是 VS UI 构建软件包呢? - AvkashChauhan
通过 VS UI。我正在尝试将一个应用程序移植到 Azure,不想重写大部分内容来忽略 app.config。像系统网络邮件配置这样的东西,我通常会通过配置转换进行转换。 - James Alexander
我过去使用过SlowCheetah,并发现它只适用于已安装它的开发人员 - 它不适用于未安装它的开发人员。换句话说,它对您的.csproj所做的更改并不足以使它对其他所有人都能够“正常工作” - 需要额外的东西。但是,我不知道那个额外的东西是什么。 :-( - Jaxidian
这些都已经不相关了。SlowCheetah现在支持Azure Worker Role配置转换。太好了! - James Alexander
@JamesAlexander,当在Azure中创建包时,SlowCheetah无法转换app.Production.config文件。你是如何做到的? - fiberOptics
@fiberOptics 他们在一年前就加入了对它的支持,根据我的最后一条评论。我经常使用它。 - James Alexander
4个回答

10

当你知道如何操作时,是可以做到的,而且非常容易。 App.config没有被设计成自动转换,但幸运的是Azure团队专门为这种情况设计了可扩展的构建/部署过程。你需要做的就是按照文档所述进行操作,虽然有点绕,但大多数文章都默认你已经熟悉了MSBuild脚本之类的内容。

下面是你需要在项目中添加的代码行,通过这些代码行,你可以完成所需的操作。整个过程不会超过五分钟。请注意,这不是黑客技术,整个Azure部署过程都是为了支持这种操作而设计的。

如果你想了解更多,请参考底部的相关文章链接。

一些概念性的要点

  1. 在Azure中实现此类操作的推荐方法是不要使用Web.config和App.config,而是使用CloudConfigurationManager并使用Role Settings。然而,有时候这并不是正确的答案,通常是因为内置或第三方组件需要*.config设置(smtp、wcf、elmah等)。
  2. Web Config transformations只用于转换web.config。这意味着app.config没有被设计成自动转换。
  3. Web Config transformations只在发布时启动,因此即使在本地运行(甚至是云仿真器中),你的Web.config也不会被转换。

我们可以通过在Cloud项目的构建过程中进行钩子操作来解决这个问题。当你将项目部署到Azure时,Cloud项目将使用一个可供你钩子操作的构建过程进行构建。简而言之,云项目会构建web和worker角色,并将它们放在你的云项目的Obj文件夹下。然后它会运行一个进程,压缩所有内容,并最终将结果放入Bin文件夹中。从那里,"zip"文件和配置文件将上传到Azure。

解决方案

手动编辑Cloud.csproj文件(如果你在Visual Studio中操作,需要先取消加载项目)。 然后在闭合的</project>标签上方添加以下代码:

  <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.targets" />
    <PropertyGroup>
      <WorkerRoleDir>$(IntermediateOutputPath)WorkerRole1\</WorkerRoleDir>
      <AppConfigOriginal>$(WorkerRoleDir)WorkerRole1.dll.config</AppConfigOriginal>
      <AppConfigTransformer>$(SolutionDir)WorkerRole1\App.$(Configuration).config</AppConfigTransformer>
      <AppConfigAfterTransformed>$(WorkerRoleDir)AfterTransformed.config</AppConfigAfterTransformed>
    </PropertyGroup>
    <Target Name="TransformAppConfig" AfterTargets="AfterPackageComputeService">
      <Message Text="Transforming $(AppConfigOriginal) via $(AppConfigTransformer) to $(AppConfigAfterTransformed)" />
      <TransformXml Source="$(AppConfigOriginal)" Transform="$(AppConfigTransformer)" Destination="$(AppConfigAfterTransformed)" />
      <Copy SourceFiles="$(AppConfigOriginal)" DestinationFiles="$(WorkerRoleDir)App.Config.Original" />
      <Copy SourceFiles="$(AppConfigAfterTransformed)" DestinationFiles="$(AppConfigOriginal)" />
    </Target>

注释

  • 代码中有几个硬编码路径需要修改。我相信有一种方法可以使它们变得更灵活,但这需要比我拥有的更多的MSBuild技能。
  • 当你部署到本地云仿真器时,转换实际上会运行,但不会被使用。因此,这与Web.config的行为是一致的,Web.config也没有进行任何转换。但是,如果您的转换失败,即使只在仿真器中运行,您也将获得构建错误。
  • 请参见此 Stack Overflow问题
  • 深入探讨
  • Tom Hollanders直接从MSBuild部署的高度关联文章

1
实际上,我有 Web.Production.config(在MVC中),ServiceConfiguration.Production.cscfg(在Cloud项目中),app.Production.config(在Worker Role中),但只有 app.Production.config 没有被转换。但是 app.Debug.configapp.Release.config 能够正确转换。所以我想删除所有的 Production 配置,并将值传输到 Debug 和 Release 中。有什么建议吗? - fiberOptics
我已经删除了所有的“Production”配置,并在“Debug和Release”配置中放置了正确的值。使用您上面的配置代码,一切都可以正常工作。但是如果您的代码还可以转换自定义配置文件,例如“app.Production.config”,那将更好。 - fiberOptics
可以 - 我自己就是这样使用的。关键在于项目构建配置与 Azure 部署配置不同。 - flytzen
顺便说一下,我发现另一个问题。当我清除解决方案时,AppConfigOriginal会引发错误。它会显示找不到文件。如果我删除您的自定义配置并为云项目创建包,则该文件会重新出现。然后我会再次添加您的配置。再次创建包,并进行转换(针对Debug和Release)。但是,如果我清理/重建解决方案,则以上缺少文件的错误会再次出现。我试图理解您的配置代码,使其不会查看Cloud项目obj文件夹,而是查看WorkerRole项目文件夹中的WorkerRole.dll.config文件。 - fiberOptics
嗨,我觉得我在这里错过了一些要点:“在Azure中实现这种类型的事情的推荐方法是不使用Web.config和App.config,而是使用CloudConfigurationManager并使用角色设置。” 我按照你说的做了,一切都很好。非常感谢你。+1 - fiberOptics
显示剩余3条评论

9

我觉得@Frans的答案太复杂了,下面是我在互联网找到的代码。假设你已经设置好并且使用了app.config转换,打开你的云项目(.ccproj)的文本编辑器,在其中找到这行代码:

<Import Project="$(CloudExtensionsDir)Microsoft.WindowsAzure.targets" />

在此之后插入以下内容:

  <!-- Get worker role transform start -->
  <Target Name="CopyWorkerRoleConfigurations" AfterTargets="CopyWorkerRoleFiles">
    <Copy SourceFiles="$(WorkerTargetDir)\YOUR-PROJECT-NAME.dll.config" DestinationFolder="$(IntermediateOutputPath)YOUR-PROJECT-NAME" OverwriteReadOnlyFiles="true" />
  </Target>
  <!-- Get worker role transform end -->

请将YOUR-PROJECT-NAME替换为您的工作项目名称。

更新

我实际上发现了一种更好的方法来做这件事(MSBuild 4+):如果您在Azure项目中有多个具有app.config转换的工作角色,则上面的脚本将无法工作。以下是更通用的方法:

  <Target Name="CopyWorkerRoleConfigurations" AfterTargets="CopyWorkerRoleFiles">
    <PropertyGroup>
         <RootFolder>$([System.IO.Path]::GetDirectoryName($(MSBuildProjectDirectory)))</RootFolder>
    </PropertyGroup>

    <Copy SourceFiles="$(RootFolder)\%(ProjectName)\bin\$(Configuration)\%(EntryPoint).config" DestinationFolder="%(WorkerRoleReferences.OutputDir)" OverwriteReadOnlyFiles="true" />
  </Target>  

1
我发现如果你的模板设置为OutputLocation = SingleFolder,需要稍微调整一下才能在使用TFS Build Services时使其正常工作。我将SourceFiles更改为<Copy SourceFiles="$(WorkerTargetDir)\%(EntryPoint).config" DestinationFolder="%(WorkerRoleReferences.OutputDir)" OverwriteReadOnlyFiles="true" />。 - John Kattenhorn

0

确保您的云服务配置已设置。右键单击云项目,您应该看到您要打包的配置。例如,我会重命名并使用本地、测试和生产配置。然后,您的云服务项目应包含3个配置文件:

  • ServiceConfiguration.Local.cscfg
  • ServiceConfiguration.PROD.cscfg
  • ServiceConfiguration.TEST.cscfg
右键单击云服务项目,选择“打包”,并为部署选择正确的服务和构建配置。
注意:在构建过程中,除非您添加了一个 MS - 请参阅此 SO 答案 来执行构建过程中的转换。然而,对于云部署,最好使用 ServiceConfiguration.*.cscfg 文件与 CloudConfigurationManager.GetSetting("settingsKey") 结合使用 - CloudConfigurationManager.GetSetting 在 SDK 1.7 中添加 - 如果在角色中,则从 ServiceConfig 获取值,否则从 web.config/app.config appSettings 获取值。

那行不通。服务配置对app.config没有任何影响。 - James Alexander
1
我建议使用ServiceConfiguration.*.cscfg文件而不是appSettings。这些可以在门户中更新,无需重新部署角色。回答已编辑。 - viperguynaz

0

有一个技巧。也许对某些人会有用。Azure Worker Role builder包括标记为“Copy”的文件。但是app.config将被转换为WorkerRole1.dll.config(或其他一些文件),这在设计时不存在。要欺骗VS:

卸载角色项目.csproj。

在项目中查找包含文件的ItemGroup部分。我有以下几个:

<None Include="app.config">
  <SubType>Designer</SubType>
</None>
<None Include="app.Debug.config">
  <DependentUpon>app.config</DependentUpon>
</None>
<None Include="app.Release.config">
  <DependentUpon>app.config</DependentUpon>
  <SubType>Designer</SubType>
</None>

然后设置在之前或之后:

<Content Include="bin\$(Configuration)\WorkerRole1.dll.config">
  <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  <Link>WorkerRole1.dll.config</Link>
</Content>

这个技巧告诉构建器 "WorkerRole1.dll.config" 存在于一个链接中,它将在构建(和转换)后获得并包含在 WorkerRole 包中。


稍作修正即可解决重建问题(当bin被清除时)。构建器尝试复制不存在的文件,导致重建失败。为了解决这个问题,在项目根目录中插入名为WorkerRole1.dll.config的虚拟文件,并设置Content\Copy Always参数。构建器将首先复制虚拟文件,然后成功复制。Azure角色部署程序读取此文件的“Content”属性并复制新的转换文件。这样可以避免额外的复制,并且更加清晰简洁。 - Dmitry A. Kalianov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接