10

我正在使用 MSBUILD 脚本创建发布,它看起来像这样:

msbuild "<Project>.vbproj" 
          /t:Publish 
          /p:Configuration=Release 
          /p:ProductName="<Application Name> - <Region Name>" 
          /p:PublishDir="<Region Specific>"

到目前为止,这工作正常。

是否可以使用 MSBUILD 创建多个发布到可以一起安装的不同位置?我知道如果应用程序相同,默认情况下 ClickOnce 不允许您从不同位置安装应用程序(我相信它通过使用程序集名称来确定这一点)。

我在这里回顾了这个线程:

具有不同部署标识但应用程序标识相同的多个 ClickOnce 安装

正因为如此,我修改了我的脚本来做到这一点:

msbuild "<Project>.vbproj" 
          /t:Publish 
          /p:Configuration=Release 
          /p:ProductName="<Application Name> - <Region Name>" 
          /p:PublishDir="<Region Specific Unc>"
          /p:AssemblyName="<Application Name>_<Region Name>"

但是我得到了大量的错误(比如 1300+),但我不确定发生了什么。但是,如果我在 Visual Studios 中更改程序集名称并构建它,一切都很好。

有什么想法吗?

4

2 回答 2

12

发生的情况是,在 msbuild 在主项目的依赖链中构建的所有项目中,属性 AssemblyName 都被覆盖。这导致了很多编译错误。当您通过 Visual Studio 更改 assemblyName 时,您只更改了主项目,这使得它能够正确构建。在我的一个项目中,我所做的是在主 .vbproj 文件上添加一个名为 OverridenAssemblyName 的属性,并在 OverridenAssemblyName 不为空时设置 AssemblyName = OverridenAssemblyName。这样,您可以仅为要发布的项目设置 AssemblyName,而其他项目保持不变。

编辑:

让我们想象一个场景,您有 2 个项目。项目 A 是要发布的项目,项目 B 是由项目 A 引用的。在 .vbproj 文件中,您有这样的标签<AssemblyName>YourProjectName</AssemblyName>。因此,在项目 A 文件中,您将拥有<AssemblyName>Project A</AssemblyName>,而<AssemblyName>Project B</AssemblyName>在项目 B 中。

该标签定义了在构建期间为项目创建的程序集的名称。

当您传入 /p:AssemblyName="<Application Name>_<Region Name>"msbuild 命令行时,您将覆盖构建过程中每个项目的标签 AssemblyName。由于该属性定义了项目的程序集名称,因此所有项目都使用相同的名称生成它们的程序集。那,可能是你的问题的原因。

一个可能的解决方案是执行以下操作:

  1. 将此添加到您的主项目(要发布的项目)

    <PropertyGroup Condition="$(PublishAssemblyName) != ''"> <AssemblyName>$(PublishAssemblyName)</AssemblyName> </PropertyGroup>

  2. 将您的命令行更改为:

msbuild "<Project>.vbproj" /t:Publish /p:Configuration=Release /p:ProductName="<Application Name> - <Region Name>" /p:PublishDir="<Region Specific Unc>" /p:PublishAssemblyName="<Application Name>_<Region Name>"

我希望这对你有帮助。

于 2013-11-18T13:27:22.110 回答
2

我只能通过执行一次 msbuild/publish 来获得成功,然后编写一个单独的“部署”程序来更改和重新签署清单,因为它们移动到每个环境。它将部署到 QA 并为其提供新名称和配置文件。然后稍后再次“部署”到生产环境,同时给它一个新的名称和配置文件。

该过程需要重命名以删除 .deploy 扩展名,替换配置文件,更改应用程序清单,更改部署清单,(在我的情况下,更新 .xlsx 文件,因为我正在执行 vsto excel 加载项),然后重新签名应用程序清单,恢复 .deploy 扩展名,重新签名部署清单,最后将结果复制到部署位置。

这导致部署到 QA 时,“单击一次”会在添加/删除程序中创建“Application-QA”,而生产部署会在“单击一次”时创建“Application-PROD”。两者可以同时运行,因为程序集名称和“solutionId”guid 已更新为在每个环境中都不同。

下面是一些关于如何更改应用程序和部署清单以在每个环境中为它们赋予唯一名称的代码。如果您决定采用这种方法并且想要辞职代码,我可以提供帮助。

Private Function UpdateAppManifestBasedOnTarget(caller As IReleaseExecutionCaller, appName As String, appManifestFileInfo As IO.FileInfo) As String

    Log.Write(Me.Name, String.Format("update the app manifest based on the target environment..."))

    Dim appManifestXML As New Xml.XmlDocument()
    Dim appManifestNamespaces As New Xml.XmlNamespaceManager(appManifestXML.NameTable)
    appManifestNamespaces.AddNamespace("asmv1", "urn:schemas-microsoft-com:asm.v1")
    appManifestNamespaces.AddNamespace("vstav3", "urn:schemas-microsoft-com:vsta.v3")
    appManifestNamespaces.AddNamespace("vstov4", "urn:schemas-microsoft-com:vsto.v4")
    appManifestXML.Load(appManifestFileInfo.FullName)
    'assemblyIdentity
    Dim assemblyNode = appManifestXML.SelectSingleNode("/asmv1:assembly/asmv1:assemblyIdentity", appManifestNamespaces)
    assemblyNode.Attributes("name").Value = appName & "-" & caller.Release.EnvironmentCode & ".dll"
    'description
    Dim descNode = appManifestXML.SelectSingleNode("/asmv1:assembly/asmv1:description", appManifestNamespaces)
    descNode.InnerXml = appName & "-" & caller.Release.EnvironmentCode
    'soluionid guid
    Dim custNode = appManifestXML.SelectSingleNode("/asmv1:assembly/vstav3:addIn/vstav3:application/vstov4:customizations/vstov4:customization/vstov4:document", appManifestNamespaces)
    Dim currentGUID = custNode.Attributes("solutionId").Value

    Dim newGuid As String = String.Format("{0:x8}{1}", caller.Release.EnvironmentCode.ToLower.GetHashCode(), currentGUID.Substring(8))
    custNode.Attributes("solutionId").Value = newGuid
    appManifestXML.Save(appManifestFileInfo.FullName)

    Return newGuid

End Function

Private Sub UpdateDeploymentManifestBasedOnTarget(caller As IReleaseExecutionCaller, appName As String, vstoFileInfo As IO.FileInfo)

    Log.Write(Me.Name, String.Format("update the deployment manifest based on the target environment..."))
    Dim vstoXML As New Xml.XmlDocument
    Dim vstoManifestNamespaces As New Xml.XmlNamespaceManager(vstoXML.NameTable)
    vstoManifestNamespaces.AddNamespace("asmv1", "urn:schemas-microsoft-com:asm.v1")
    vstoManifestNamespaces.AddNamespace("asmv2", "urn:schemas-microsoft-com:asm.v2")
    vstoXML.Load(vstoFileInfo.FullName)
    'assemblyIdentity
    Dim assemblyNode = vstoXML.SelectSingleNode("/asmv1:assembly/asmv1:assemblyIdentity", vstoManifestNamespaces)
    assemblyNode.Attributes("name").Value = appName & "-" & caller.Release.EnvironmentCode & ".vsto"
    'description
    Dim descNode = vstoXML.SelectSingleNode("/asmv1:assembly/asmv1:description", vstoManifestNamespaces)
    descNode.Attributes("asmv2:product").Value = appName & "-" & caller.Release.EnvironmentCode
    'dependancy assemblyIdentity
    Dim depAssmblyIdentityNode = vstoXML.SelectSingleNode("/asmv1:assembly/asmv2:dependency/asmv2:dependentAssembly/asmv2:assemblyIdentity", vstoManifestNamespaces)
    depAssmblyIdentityNode.Attributes("name").Value = appName & "-" & caller.Release.EnvironmentCode & ".dll"
    vstoXML.Save(vstoFileInfo.FullName)

End Sub
于 2013-11-25T20:46:27.747 回答