Я нашел решение этой проблемы. Я не думаю, что кто-либо когда-либо сталкивался с этим, поэтому я сомневаюсь, что будет «правильное» решение. Я опубликую здесь то, что я сделал, чтобы мои файлы .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.
Шаг второй. Зная, где искать, я декомпилировал задачу. Я использовал JustDecompile Telerik, но я также придумал тот же код в 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 с настраиваемыми выводами файлы wsp, созданные решениями SharePoint!
Я использовал этот сайт как ресурс: http://blogs.like10.com/2011/08/04/team-build-2010-customized-output-directories-sharepoint-2010-wsps/
(Возможно, я использовал еще один или два сайта в качестве ресурса, но на данный момент я могу найти их в истории браузера).
Ваш пробег может отличаться, но, пожалуйста, дайте мне знать, есть ли у кого-нибудь подобная проблема и сможет ли ее исправить "взломанным" способом.
ОБНОВЛЕНИЕ
Похоже, вся эта проблема возникла из-за исходной установки TFS, которую я администрировал. Недавно я перевел нашу команду на правильный сервер TFS (2012 г.) с полностью новой установкой ОС и новым сервером базы данных. После того, как я перенес базы данных и выполнил задачи обновления в TFS, я смог внести некоторые небольшие изменения в сборку, чтобы моя сборка работала с 2012 годом, и я не сталкивался с этой проблемой во второй раз. Я считаю, что эта проблема возникла из-за того, что исходная TFS 2010 была на переделанной машине dev.
person
Mike G
schedule
29.05.2012