0

我对这个 SO 帖子有一个非常相似的问题:TFS Build 2010 - Custom Binary Location and SharePoint WSP。没有明显的答案,但提供的唯一答案似乎是要走的路。

我正在构建几个解决方案,需要将解决方案和项目放入自己的文件夹中。这导致生成输出更改为我正在使用的模板中的 MSBuild 调用。我已经使用它一段时间了,没有任何问题。

最近,一位开发人员抱怨我们的日常构建中没有生成 .wsp 文件。我对此进行了调查,并遇到了前面提到的 SO 帖子。

我按照说明操作,现在有一个新错误:

C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\SharePointTools\Microsoft.VisualStudio.SharePoint.targets (411):找不到方法:'Boolean Microsoft.VisualStudio.SharePoint.PathUtils.HasIllegalDeploymentPathCharacters(System.细绳)'。

我在目标文件中查看了这一行(411):

<PackageFiles LayoutPath="$(LayoutPath)%(EnumeratedFiles.Package)\" PackagePath="$(BasePackagePath)%(EnumeratedFiles.Package).$(PackageExtension)" />

PackageFiles目标定义为:

<UsingTask AssemblyFile="Microsoft.VisualStudio.SharePoint.Tasks.dll" TaskName="PackageFiles" />

我检查了 GAC 并没有看到它,所以我添加了它。TFS 2010 Build 机器上安装了 Visual Studio 2010 和 Sharepoint 2010。除了更改此任务之外,我认为我不需要做任何事情:

<CreateSharePointProjectService Configuration="$(Configuration)"
                                Platform="$(Platform)"
                                ProjectFile="$(MSBuildProjectFile)"
                                ProjectReferences="@(SharePointProjectReference)"
                                OutDir="$(TargetDir)">
  <Output PropertyName="ProjectService" TaskParameter="ProjectService" />
</CreateSharePointProjectService>

所以OutDir 指向 $(TargetDir)

我是否遗漏了一些关于为什么在现在找不到方法的情况下出现此错误的信息?这个错误非常令人恼火,因为无论使用 Google Fu,网络上都没有任何信息!

更新 我已经拆开了构建服务器上的 Microsoft.VisualStudio.SharePoint.dll。没有 PathUtils 类或命名空间。我可能有这个文件的错误版本吗?我怎样才能检测到这个?我应该在构建服务器上安装 Sharepoint SDK。它已经安装了 Sharepoint 2010。

更新 2
我检查了 GAC。Microsoft.VisualStudio.Sharepoint 程序集出现。但是,我只能在运行 x64 版本的 Visual Studio 命令提示符时找到它。当我运行正常时,我没有得到任何组装。我假设这是因为 Sharepoint 程序集是 64 位的。据我所知,TFS 设置为 64 位。这会是我的问题吗?

4

3 回答 3

2

PathUtils.HasIllegalDeploymentPathCharacters 方法存在于 Microsoft.VisualStudio.SharePoint.Designers.Models.dll 的版本 10.0.40219.1 中,而不是版本 10.0.30319.1 中(我看到此错误的地方)。

于 2013-01-14T01:58:29.840 回答
0

我找到了解决这个问题的方法。我认为没有人遇到过这种情况,所以我怀疑是否会有“正确”的解决方案。我将在这里发布我所做的以允许我的 .wsp 文件在解决方案中构建。

如果您认为有更好的解决方案或者我解决问题的方式不符合标准,请务必发布答案(或对此答案或原始问题发表评论)。

我将按照我想出的解决问题的步骤来解释这一点。

第一步PackageFiles 任务给了我这个问题。此任务找不到要调用的方法。查看文件C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\SharePointTools\Microsoft.VisualStudio.SharePoint.targets我们可以在第 56 行找到:

<UsingTask AssemblyFile="Microsoft.VisualStudio.SharePoint.Tasks.dll" TaskName="PackageFiles" /> 

我知道在哪里可以找到PackageFiles任务/类。

第二步 知道在哪里看后,我反编译了任务。我使用了 Telerik 的 JustDecompile,但我也在 Reflector 中提出了相同的代码。

我可以清楚地看到这条线:

if (PathUtils.HasIllegalDeploymentPathCharacters(str2))

这是错误的。

第三步 我最终决定PathUtils.HasIllegalDeploymentPathCharacters方法只是作为安全检查。我可以在自己的自定义库中重新创建此任务,然后将其插入自定义目标文件中。

这是我想出的课程:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using Microsoft.VisualStudio.SharePoint.Tasks;
using Microsoft.Build.Framework;

namespace SharepointTaskLibrary
{
  public class PackageFiles : BuildTask
  {
    [Required]
    public ITaskItem LayoutPath
    {
      get;
      set;
    }

    [Required]
    public ITaskItem PackagePath
    {
      get;
      set;
    }

    public PackageFiles()
    {

    }

    protected override void OnCheckParameters()
    {
      if (this.LayoutPath == null)
      {
        throw new InvalidOperationException(Strings.GetString("LayoutPathNotSpecified"));
      }
      if (this.PackagePath == null)
      {
        throw new InvalidOperationException(Strings.GetString("PackagePathNotSpecified"));
      }
    }

    protected override void OnExecute()
    {
      object[] objArray;
      object[] objArray2;
      object[] objArray3;
      string metadata = this.LayoutPath.GetMetadata("FullPath");
      string str1 = this.PackagePath.GetMetadata("FullPath");

      Assembly sharepointTasksAss = Assembly.Load("Microsoft.VisualStudio.SharePoint.Tasks");

      if (sharepointTasksAss != null)
        base.Log.LogMessage(MessageImportance.High, "Found Tasks assembly!");
      else
      {
        base.Log.LogError("Couldn't find the tasks assembly");
        return;
      }

      if (!Directory.Exists(metadata))
      {
        base.Log.LogErrorFromResources("LayoutPathDoesNotExist", new object[] { metadata });
      }
      else
      {
        MethodInfo createCabMethod = GetStaticMethod(sharepointTasksAss, "Microsoft.VisualStudio.SharePoint.Tasks.Utilities.CabCreator", "CreateCabinet");

        if (createCabMethod == null)
        {
          base.Log.LogError("the method could not be retrieved on type.");
          return;
        }
        else
          base.Log.LogMessage(MessageImportance.High, "Found method: " + createCabMethod.Name);

        IEnumerable<string> strs = createCabMethod.Invoke(null, new object[] { metadata, str1 }) as IEnumerable<string>;

        /*
         * The following code would error in the original task.
         */
        //foreach (string str2 in strs)
        //{
        //  if (PathUtils.HasIllegalDeploymentPathCharacters(str2))
        //  {
        //    base.Log.LogWarningFromResources("FileNameContainsIllegalDeploymentPathCharacters", new object[] { str2 });
        //  }
        //}
        base.Log.LogMessage(MessageImportance.High, Strings.GetString("PackageCreatedSuccessfully"), new object[] { str1 });
      }

      Type codeMarkersType = null;

      try
      {
        codeMarkersType = sharepointTasksAss.GetType("Microsoft.Internal.Performance.CodeMarkers", true);
      }
      catch (Exception e)
      {
        base.Log.LogErrorFromException(e, true);
      }

      if (codeMarkersType == null)
      {
        base.Log.LogError("Couldn't get the CodeMarkers class!");
        return;
      }
      else
        base.Log.LogMessage(MessageImportance.High, "Found the type: " + codeMarkersType.FullName);

      /*
       * This has yet to be added back in.
       */
      //CodeMarkers.Instance.CodeMarker(CodeMarkerEvent.perfSharePointPackageWspPackageEnd);
    }

    private MethodInfo GetStaticMethod(Assembly assembly, string typeName, string methodName)
    {
      Type type = null;

      try
      {
        type = assembly.GetType(typeName, true);
      }
      catch (Exception e)
      {
        base.Log.LogErrorFromException(e, true);
      }

      if (type == null)
      {
        base.Log.LogError("Couldn't get the type: " + typeName);
        return null;
      }
      else
        base.Log.LogMessage(MessageImportance.High, "Found the type: " + type.FullName);

      MethodInfo methodInfo = type.GetMethod(methodName, BindingFlags.Static);

      if (methodInfo == null)
      {
        MethodInfo[] methods = type.GetMethods().Union(type.GetMethods(BindingFlags.Static)).ToArray();

        base.Log.LogWarning(string.Format("Wasn't able to find {0} directly. Searching through the static {1} method(s) on {2}", methodName, methods.Length, type.FullName));

        foreach (MethodInfo info in methods)
        {
          if (info.Name == methodName && methodInfo == null)
            methodInfo = info;
        }

        if (methodInfo == null)
        {
          MemberInfo[] members =
                  type.GetMembers().Union(type.GetMembers(BindingFlags.Static | BindingFlags.NonPublic)).Union(type.GetMembers(BindingFlags.NonPublic)).ToArray();

          base.Log.LogWarning(string.Format("Wasn't able to find {0}. Searching through the {1} members(s) on {2}", methodName, methods.Length, type.FullName));

          MemberInfo createCabMember = null;

          foreach (MemberInfo member in members)
          {
            if (member.Name == methodName)
            {
              createCabMember = member;
              break;
            }
            else
              base.Log.LogMessage(MessageImportance.High, "Found member: " + member.Name);
          }

          if (createCabMember == null)
            base.Log.LogError("Still wasn't able to find " + methodName + " in the members!");
        }
      }

      return methodInfo;
    }
  }
}

由于大多数类和方法都被标记为内部的,我不得不使用反射来获取实际构建 cab/wsp 文件所需的类型和方法。这是在方法中完成的:GetStaticMethod

第四步 如果您阅读反编译代码和我的自定义版本的类,您会注意到Strings类。它似乎是一个资源访问器类。我决定我也只是反编译该代码并将其用于我的解决方案中,以生成自定义任务,而不是每次我想访问字符串资源时都进行反映。该文件最终不是直接反编译,因为它有一行this.GetType().Assembly用于获取包含资源的当前程序集。这在原始程序集中可以正常工作,但在此自定义程序集中会导致问题。

原行:

internal Strings()
{
    this.resources = new ResourceManager("Strings", this.GetType().Assembly);
}

该行必须更改为:

Assembly sharepointTasksAss = Assembly.Load("Microsoft.VisualStudio.SharePoint.Tasks");
this.resources = new ResourceManager("Strings", sharepointTasksAss);

第五步 在我有一个模仿原始的自定义构建任务之后,我现在需要将它放入目标文件中。然后,我备份了原始目标文件并制作了一个自定义文件来替换UsingTask部分,如下所示:

  <UsingTask AssemblyFile="Microsoft.VisualStudio.SharePoint.Tasks.dll" TaskName="CreateSharePointProjectService" />
  <UsingTask AssemblyFile="Microsoft.VisualStudio.SharePoint.Tasks.dll" TaskName="EnumerateFiles" />
  <UsingTask AssemblyFile="Microsoft.VisualStudio.SharePoint.Tasks.dll" TaskName="EnumerateFeature" />
  <UsingTask AssemblyFile="Microsoft.VisualStudio.SharePoint.Tasks.dll" TaskName="EnumeratePackage" />
  <UsingTask AssemblyFile="Microsoft.VisualStudio.SharePoint.Tasks.dll" TaskName="EnumerateProjectItem" />
  <UsingTask AssemblyFile="Microsoft.VisualStudio.SharePoint.Tasks.dll" TaskName="LayoutFiles" />
  <!-- The next task is a mimic of the one from the other assembly.  I decompiled it and recreated it so it wouldn't error.  LOL -->
  <UsingTask AssemblyFile="C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\SharePointTools\SharepointTaskLibrary.dll" TaskName="PackageFiles" />
  <UsingTask AssemblyFile="Microsoft.VisualStudio.SharePoint.Tasks.dll" TaskName="ResolveProjectMember" />
  <UsingTask AssemblyFile="Microsoft.VisualStudio.SharePoint.Tasks.dll" TaskName="SetPackagingProperties" />
  <UsingTask AssemblyFile="Microsoft.VisualStudio.SharePoint.Tasks.dll" TaskName="ValidatePackage" />

这使得任务指向包含自定义任务的我的 DLL。具体来说,这一行:

<UsingTask AssemblyFile="C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\SharePointTools\SharepointTaskLibrary.dll" TaskName="PackageFiles" />

最后
,我将编译的 DLL 和编辑的目标文件放入C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\SharePointTools目录(再次备份原始目标文件)。

这使我能够通过 TFS 2010 构建自定义输出由 SharePoint 解决方案生成的 wsp 文件!

我将此站点用作资源:http: //blogs.like10.com/2011/08/04/team-build-2010-customized-output-directories-sharepoint-2010-wsps/

(我可能使用了另外一两个站点作为资源,但我现在可以在浏览器历史记录中找到它们)。

您的里程可能会有所不同,但请让我知道是否有人有类似的问题并且能够以非“黑客”的方式修复它。

更新
这整个问题似乎来自我正在管理的原始 TFS 安装。我最近将我们的团队搬到了一个合适的 TFS 服务器(2012),安装了全新的操作系统和一个新的数据库服务器。一旦我迁移数据库并在 TFS 中运行升级任务,我就能够进行一些小的构建编辑以使我的构建与 2012 一起工作,并且我没有第二次遇到这个问题。我相信,因为最初的 2010 TFS 是在经过转换的开发机器上,所以会导致这个问题。

于 2012-05-29T15:16:29.587 回答
0

您缺少程序集“Microsoft.VisualStudio.SharePoint.Designers.Models.dll”

必须将以下程序集复制到构建系统的 GAC:

Microsoft.VisualStudio.SharePoint.Designers.Models.dll Microsoft.VisualStudio.SharePoint.Designers.Models.Features.dll Microsoft.VisualStudio.SharePoint.Designers.Models.Packages.dll Microsoft.VisualStudio.SharePoint.dll

有关所需程序集的更多信息,请参阅以下文章:

http://msdn.microsoft.com/en-us/ff622991.aspx

问候,

韦斯麦克唐纳

于 2012-05-30T17:33:28.670 回答