Расширение VSIX для VS2012 не работает при отладке

Я создал новый проект расширения VSIX в Visual Studio 2012 и написал классификатор MEF (как тест), который должен просто выделить весь текст в файле .mylang. Вот соответствующие части моего кода .NET 4.5:

internal static class MyLangLanguage
{
    public const string ContentType = "mylang";

    public const string FileExtension = ".mylang";

    [Export(typeof(ClassificationTypeDefinition))]
    [Name(ContentType)]
    [BaseDefinition("code")]
    internal static ContentTypeDefinition MyLangSyntaxContentTypeDefinition = null;

    [Export]
    [FileExtension(FileExtension)]
    [ContentType(ContentType)]
    internal static FileExtensionToContentTypeDefinition MyLangSyntaxFileExtensionDefinition = null;
}

[Export(typeof(IClassifierProvider))]
[ContentType(MyLangLanguage.ContentType)]
[Name("MyLangSyntaxProvider")]
internal sealed class MyLangSyntaxProvider : IClassifierProvider
{
    [Import]
    internal IClassificationTypeRegistryService ClassificationRegistry = null;

    public IClassifier GetClassifier(ITextBuffer buffer)
    {
        return buffer.Properties.GetOrCreateSingletonProperty(() => new MyLangSyntax(ClassificationRegistry, buffer));
    }
}

internal sealed class MyLangSyntax : IClassifier { }

Вот полный код.

Это соответствующие части из моего файла source.extension.vsixmanifest. Основываясь на предложениях и подобных файлах, которые я нашел через Интернет, я добавил зависимость от MPF и двух активов.

<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
    <!-- ... -->
    <Dependencies>
        <Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="4.5" />
        <Dependency d:Source="Installed" Id="Microsoft.VisualStudio.MPF.11.0" DisplayName="Visual Studio MPF 11.0" Version="[11.0,12.0)" />
    </Dependencies>
    <Assets>
        <Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgdefProjectOutputGroup|" />
        <Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%|" />
    </Assets>
</PackageManifest>

Я также пробовал манифест версии 1.0:

<?xml version="1.0" encoding="utf-8"?>
<Vsix Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
    <!-- ... -->
    <References />
    <Content>
        <MefComponent>|%CurrentProject%|</MefComponent>
    </Content>
</Vsix>

Когда я запускаю его, он запускает экспериментальный экземпляр Visual Studio 2012, а окно "Расширения и обновления" показывает, что мое расширение активно. Однако, когда я загружаю или создаю файл .mylang, он ничего не делает. Любые исключения, которые я бросаю (как тест) из моего расширения, никогда не бросаются. Точки останова никогда не попадают и получают восклицательный знак со следующим предупреждением:

В настоящий момент точка останова не будет удалена. Для этого документа не были загружены никакие символы.

Мне кажется, что мое расширение никогда не загружается вообще. Моя проблема аналогична этой проблеме и этой проблеме, но я использую Visual Studio 2012, которая использует новый формат манифеста VSIX.

Что я знаю:

  • Я могу найти свой файл DLL и VSIX в папке %localappdata%\Microsoft\VisualStudio\11.0Exp\Extensions\MyLang\VSIXProject1\1.0, поэтому я знаю, что они скопированы.
  • Их временная метка соответствует тому, когда я последний раз строил проект, поэтому я знаю, что они актуальны.
  • Свойства проектa > Отладкa > Запустить внешнюю программу: уже автоматически установлено значение C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe, а аргументы командной строки автоматически установлены на /rootsuffix Exp.
  • Журнал Visual Studio (созданный с помощью опции /log) имеет две записи, связанные с моим расширением: Successfully loaded extension... и Extension is enabled....
  • Моя DLL не появляется на вкладке "Модули" (список всех загруженных DLL) отладки Visual Studio, в то время как некоторые (не все) другие расширения появляются.
  • Он не загружается в Visual Studio 2012 или 2010 как на моем ноутбуке, так и на моем настольном ПК.

Что я пробовал:

  • Установите <IncludeAssemblyInVSIXContainer> в true в файле .csproj, за это предложение, но это не имеет никакого значения.
  • Я не могу добавить строку <MefComponent>|%CurrentProject%|</MefComponent> в файл source.extension.vsixmanifest, поскольку он использует другой формат (2.0), чем проекты VSIX для предыдущих версий Visual Studio (1.0).
  • Это предложение (настройка IncludeAssemblyInVSIXContainer и друзей в моем .csproj на true), но это не имеет значения. И мои контрольные точки все еще показывают предупреждение и не попадают.
  • Reset Экспериментальный экземпляр VS с использованием Reset ярлыка экспериментальной инстанции Visual Studio 2012 в меню "Пуск" в соответствии с этим предложением. Это не имело значения.

Как я могу, по крайней мере, убедиться, что мое расширение VSIX MEF загружено и работает? И если это возможно, как я могу сделать работу контрольной точки и отладить ее?

Ответ 1

Изменить: Проблема заключается в том, что вы неправильно экспортировали ContentTypeDefinition как ClassificationTypeDefinition. Вместо этого вы должны использовать следующее:

[Export] // <-- don't specify the type here
[Name(ContentType)]
[BaseDefinition("code")]
internal static ContentTypeDefinition MyLangSyntaxContentTypeDefinition = null;

Вот мои две догадки прямо сейчас:

  • Попробуйте удалить следующую строку из vsixmanifest. Я предполагаю, что у вас нет класса в вашем проекте, который расширяет Package, и в этом случае Visual Studio может отказаться от загрузки вашего пакета из-за следующей строки Asset ( ваше расширение фактически не предоставляет этот актив).

    <Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgdefProjectOutputGroup|" />
    
  • Если это не удается, попробуйте заменить текущий источник source.extension.vsixmanifest на один, записанный на старую схему (версия 1.0). Я знаю, что эта форма все еще работает в Visual Studio 2012, потому что все ~ 20 расширений, над которыми я работаю (s > 10 общедоступными выпусками), используют старую схему.

Ответ 2

280Z28 решил проблему! Для полноты, это полный проверенный и проверенный код, который создаст сверхпростую VSIX Visual Studio MEF, которая окрасит весь текст в файл .mylang синий (или любой цвет текущего ключевого слова).

Как создать простую раскраску расширения MEF VSIX

  • Убедитесь, что установлен пакет Visual Studio SDK. (VS2010 SP1 SDK, VS2012 SDK)
  • Создайте новый проект VSIX
    (Из шаблона в разделе Installed → Templates → Visual С# → Расширяемость.)
  • Введите что-то в поле "Автор" в редакторе манифеста VSIX, затем сохраните и закройте его.
  • Добавьте ссылки на следующие библиотеки:
    версию 10.0.0.0 для VS2010 или 11.0.0.0 для VS2012:

    • Microsoft.VisualStudio.CoreUtility.dll
    • Microsoft.VisualStudio.Language.StandardClassification.dll
    • Microsoft.VisualStudio.Text.Data.dll
    • Microsoft.VisualStudio.Text.Logic.dll
    • Microsoft.VisualStudio.Text.UI.dll
    • Microsoft.VisualStudio.Text.UI.Wpf.dll
  • Добавьте ссылку на следующую библиотеку:

    • System.ComponentModel.Composition.dll версия 4.0.0.0
  • Создайте и добавьте новый файл кода MyLang.cs и скопируйте и вставьте код ниже в него.

  • Измените source.extension.vsixmanifest как XML.

    • Для Visual Studio 2010 добавьте следующий XML непосредственно перед закрывающим тегом </Vsix> и сохраните:

      <Content>
          <MefComponent>|%CurrentProject%|</MefComponent>
      </Content>
      

      (Если уже существует пустой <Content/>, удалите его.)

    • Для Visual Stuio 2012 добавьте следующий XML непосредственно перед закрывающим тегом </PackageManifest> и сохраните:

      <Assets>
          <Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%|" />
      </Assets>
      

      (Если уже существует пустой <Assets/>, удалите его.)

  • Только для Visual Studio 2010:

    • Выгрузите проект VSIX (щелкните правой кнопкой мыши проект project → Unload).

    • Отредактируйте файл проекта .csproj (щелкните правой кнопкой мыши проект → Edit MyProject.csproj).

    • Измените значение с <IncludeAssemblyInVSIXContainer> на true.

    • Сохраните и закройте файл.

    • Перезагрузите проект VSIX (щелкните правой кнопкой проект project → Reload).

  • Теперь создайте и запустите его. Когда вы загружаете файл .mylang, весь текст должен быть окрашен в синий цвет (или любой цвет ключевого слова по умолчанию).


MyLang.cs

using Microsoft.VisualStudio.Language.StandardClassification;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Utilities;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;

namespace VSIXProject1
{
    internal static class MyLangLanguage
    {
        public const string ContentType = "mylang";

        public const string FileExtension = ".mylang";

        [Export]
        [Name(ContentType)]
        [BaseDefinition("code")]
        internal static ContentTypeDefinition MyLangSyntaxContentTypeDefinition = null;

        [Export]
        [FileExtension(FileExtension)]
        [ContentType(ContentType)]
        internal static FileExtensionToContentTypeDefinition MyLangSyntaxFileExtensionDefinition = null;
    }

    [Export(typeof(IClassifierProvider))]
    [ContentType(MyLangLanguage.ContentType)]
    [Name("MyLangSyntaxProvider")]
    internal sealed class MyLangSyntaxProvider : IClassifierProvider
    {
        [Import]
        internal IClassificationTypeRegistryService ClassificationRegistry = null;

        public IClassifier GetClassifier(ITextBuffer buffer)
        {
            return buffer.Properties.GetOrCreateSingletonProperty(() => new MyLangSyntax(ClassificationRegistry, buffer));
        }
    }

    internal sealed class MyLangSyntax : IClassifier
    {
        private ITextBuffer buffer;
        private IClassificationType identifierType;
        private IClassificationType keywordType;

        public event EventHandler<ClassificationChangedEventArgs> ClassificationChanged;

        internal MyLangSyntax(IClassificationTypeRegistryService registry, ITextBuffer buffer)
        {
            this.identifierType = registry.GetClassificationType(PredefinedClassificationTypeNames.Identifier);
            this.keywordType = registry.GetClassificationType(PredefinedClassificationTypeNames.Keyword);
            this.buffer = buffer;
            this.buffer.Changed += OnBufferChanged;
        }

        public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan snapshotSpan)
        {
            var classifications = new List<ClassificationSpan>();

            string text = snapshotSpan.GetText();
            var span = new SnapshotSpan(snapshotSpan.Snapshot, snapshotSpan.Start.Position, text.Length);
            classifications.Add(new ClassificationSpan(span, keywordType));

            return classifications;
        }

        private void OnBufferChanged(object sender, TextContentChangedEventArgs e)
        {
            foreach (var change in e.Changes)
                ClassificationChanged(this, new ClassificationChangedEventArgs(new SnapshotSpan(e.After, change.NewSpan)));
        }
    }
}

Ответ 3

Установите <IncludeAssemblyInVSIXContainer> значение true в файле .csproj, за это предложение.

У меня была точно такая же проблема, и это решило ее. Сделайте полную перестройку.