1 需求场景
在部署项目的时候,通常会有测试环境和产品环境。测试环境用于测试场景,而产品环境用于实际使用。两种环境的不同通常在于一些配置文件,比如数据库连接串的不同。
在Visual Studio中,默认的配置环境有只Debug和Release,它们之间的区别主要在于是否在编译时优化代码,设置Debug、Release变量等。在早期,其并未涉及到其它配置文件的切换,而在后来的Web项目中,微软为Web.Config文件添加了Web.Debug.Config和Web.Release.Config,实现了在发布项目时,根据配置自动替换相应的Web.Config。
问题来了:
如果不是Web项目该怎么办呢?
如果项目有很多自定义配置,而不仅是Web.Config或App.Config,又该如何?
如果不仅仅只有测试和产品环境,而是测试1、2、3,产品1、2、3多个环境呢?
2 解决方案
充分利用项目属性的Build Events来实现一键切换。
假设现在需要4种配置环境:
配置 | 环境 | 其它 |
Debug | 本机 | 代码无优化,可以设置断点 |
Test | 测试 | 代码无优化,可以设置断点 |
Production | 产品 | 代码无优化,可以设置断点 |
Release | 产品 | 代码优化,不能设置断点 |
首先通过配置管理器新建Production和Test两种配置:
接着为每个需要切换的配置加上对应文件,如为*.config加上其它3种环境的配置,分别为*.Production.config,*.Release.config,*.Test.config,默认的*.config将对应Debug环境。
最后在Post-build event里加上相应脚本。脚本的目的在于根据当前配置名称替换相应文件,如将*.Production.config替换成*.config。
这里用到的脚本ReplaceFileName.bat内容如下:
::Author: locus
::Go to help block to see the description.
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set oldstr=
set newstr=
set targetPath=
if "%~1"=="/?" goto :help
if "%~1"=="" goto :help
set oldstr=%~1
set newstr=%~2
shift
shift
if "%~1"=="" (
set targetPath=%CD%
) else set targetPath=%~1
if not exist "%targetPath%" (echo path "%targetPath%" not exist, exit now.&goto :EOF)
for /f "tokens=*" %%I in ('dir "%targetPath%\*%oldstr%*" /B /S') do (
rem echo %%I
set currentPath=%%~dpI
rem echo !currentPath!
set currentFile=%%~nxI
rem echo !currentFile!
rem replace the oldstr with newstr
set toFile=!currentFile:%oldstr%=%newstr%!
echo copy /Y "!currentPath!!currentFile!" "!currentPath!!toFile!"
copy /Y "!currentPath!!currentFile!" "!currentPath!!toFile!"
rem cleanup
set currentPath=
set currentFile=
set toFile=
)
goto :EOF
:help
echo Purpose: According to a substring, copy the related file and replace the name.
echo syntax: ReplaceFileName.bat OldStr NewStr [Path]
echo e.g. ReplaceFileName.bat D:\temp\ .debug ""
echo will copy D:\temp\app.debug.config to D:\temp\app.config
在Post-build event里加上的脚本如下,意思是将 .<ConfigurationName>. 替换成 . 。(不管文件扩展名,因为配置文件可能为txt/xml等)
"$(SolutionDir)ReplaceFileName.bat" .$(ConfigurationName). . "$(TargetDir)"
而由于app.config比较特殊,生成时将会用程序集命名,所以单独处理:
if exist "$(ProjectDir)app.$(ConfigurationName).config" copy /Y "$(ProjectDir)app.$(ConfigurationName).config" "$(TargetDir)$(TargetName).exe.config"