Атрибут InternalsVisibleTo не работает

Я пытаюсь использовать атрибут сборки InternalsVisibleTo, чтобы сделать мои внутренние классы в библиотеке классов .NET видимыми для моего проекта unit test. По какой-то причине я продолжаю получать сообщение об ошибке:

"MyClassName" недоступно из-за уровня защиты

Обе сборки подписаны, и у меня есть правильный ключ, указанный в объявлении атрибута. Любые идеи?

Ответ 1

Вы абсолютно уверены, что у вас есть правильный открытый ключ, указанный в атрибуте? Обратите внимание, что вам нужно указать полный открытый ключ, а не только токен открытого ключа. Это выглядит примерно так:

[assembly: InternalsVisibleTo("MyFriendAssembly,
PublicKey=0024000004800000940000000602000000240000525341310004000001000100F73
F4DDC11F0CA6209BC63EFCBBAC3DACB04B612E04FA07F01D919FB5A1579D20283DC12901C8B66
A08FB8A9CB6A5E81989007B3AA43CD7442BED6D21F4D33FB590A46420FB75265C889D536A9519
674440C3C2FB06C5924360243CACD4B641BE574C31A434CE845323395842FAAF106B234C2C140
6E2F553073FF557D2DB6C5")]

Это 320 или около того шестнадцатеричных цифр. Не знаете, почему вам нужно указать полный открытый ключ - возможно, с помощью только токена открытого ключа, который используется в других ссылках на сборки, для кого-то было бы легче подделать идентификатор сборки друга.

Ответ 2

Другая возможная "gotcha": имя сборника друзей, которое вы указываете в InternalsVisibleToAttribute, должно точно соответствовать имени вашей сборки друга, как показано в свойствах проекта friend (в приложении вкладка).

В моем случае у меня был проект Thingamajig и проект-компаньон ThingamajigAutoTests (имена были изменены для защиты виновных), которые производили неподписанные сборки. Я должным образом добавил атрибут [assembly: InternalsVisibleTo( "ThingamajigAutoTests" )] в файл Thingamajig\AssemblyInfo.cs и прокомментировал атрибуты AssemblyKeyFile и AssemblyKeyName, как указано выше. Thingamajig Проект построен только штраф, но его внутренние члены упорно не обнаруживаться в проекте автотестов.

После большой царапины головы я перепроверил свойства проекта ThingamajigAutoTests и обнаружил, что имя сборки было указано как "ThingamajigAutoTests.dll". Bingo - я добавил расширение ".dll" к имени сборки в атрибуте InternalsVisibleTo, и куски упали на место.

Иногда это самые маленькие вещи...

Ответ 3

Если ваши сборки не подписаны, но вы по-прежнему получаете ту же ошибку, проверьте файл AssemblyInfo.cs для любой из следующих строк:

[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]

Вкладка свойств по-прежнему будет показывать вашу сборку как unsigned, если присутствует (или оба) этих строк, но атрибут InternalsVisibleTo рассматривает сборку с этими строками как сильно подписанную. Просто удалите (или закомментируйте) эти строки, и он будет отлично работать для вас.

Ответ 4

Следует отметить, что если сборка "friend" (tests) написана на С++/CLI, а не на С#/VB.Net, вам необходимо использовать следующее:

#using "AssemblyUnderTest.dll" as_friend

вместо ссылки на проект или обычного оператора #using. По какой-то причине, нет возможности сделать это в пользовательском интерфейсе проекта.

Колин

Ответ 6

Вот макрос, который я использую для быстрого создания этого атрибута. Это немного взломанный, но он работает. На моей машине. Когда последний подписанный двоичный файл находится в /bin/debug. Etc equivocation и т.д. Во всяком случае, вы можете видеть, как он получает ключ, так что это даст вам подсказку. Исправить/улучшить, как позволяет ваше время.

Sub GetInternalsVisibleToForCurrentProject()
    Dim temp = "[assembly:  global::System.Runtime.CompilerServices." + _
               "InternalsVisibleTo(""{0}, publickey={1}"")]"
    Dim projs As System.Array
    Dim proj As Project
    projs = DTE.ActiveSolutionProjects()
    If projs.Length < 1 Then
        Return
    End If

    proj = CType(projs.GetValue(0), EnvDTE.Project)
    Dim path, dir, filename As String
    path = proj.FullName
    dir = System.IO.Path.GetDirectoryName(path)
    filename = System.IO.Path.GetFileNameWithoutExtension(path)
    filename = System.IO.Path.ChangeExtension(filename, "dll")
    dir += "\bin\debug\"
    filename = System.IO.Path.Combine(dir, filename)
    If Not System.IO.File.Exists(filename) Then
        MsgBox("Cannot load file " + filename)
        Return
    End If
    Dim assy As System.Reflection.Assembly
    assy = System.Reflection.Assembly.Load(filename)
    Dim pk As Byte() = assy.GetName().GetPublicKey()
    Dim hex As String = BitConverter.ToString(pk).Replace("-", "")
    System.Windows.Forms.Clipboard.SetText(String.Format(temp, assy.GetName().Name, hex))
    MsgBox("InternalsVisibleTo attribute copied to the clipboard.")
End Sub

Ответ 7

При компиляции сборки друга вам необходимо использовать переключатель /out: compiler (сборка, которая не содержит атрибута InternalsVisibleTo).

Компилятор должен знать имя скомпилированной сборки, чтобы определить, следует ли рассматривать сборку в сборке друзей.

Ответ 8

В дополнение ко всему вышесказанному, когда все кажется правильным, но сборник друзей упрямо отказывается видеть какие-либо внутренние компоненты, перезагрузка решения или перезапуск Visual Studio может решить проблему.

Ответ 9

В моем случае, используя VS.Net 2015, мне нужно было подписать BOTH сборки (если хотя бы одна сборка должна быть подписана или вы хотите ссылаться на открытый ключ вашей сборки).

Мой проект вообще не использовал подпись. Поэтому я начал добавлять знак знака в свою тестовую библиотеку и использовать InternalsVisibleTo-Attribute в моей базовой библиотеке проектов. Но VS.Net всегда объяснял, что не может получить доступ к методам друзей.

Когда я начал подписывать базовую библиотеку (это может быть тот же самый или другой знаковый ключ - пока вы подписываете базовую библиотеку), VS.Net сразу мог работать как ожидалось.

Ответ 10

Предыдущие ответы с PublicKey сработали: (Visual Studio 2015: НЕОБХОДИМО быть в одной строке, иначе он жалуется, что ссылка на сборку недействительна или не может быть указана. PublicKeyToken не работал)

[assembly: InternalsVisibleTo("NameSpace.MyFriendAssembly, PublicKey=0024000004800000940000000602000000240000525341310004000001000100F73F4DDC11F0CA6209BC63EFCBBAC3DACB04B612E04FA07F01D919FB5A1579D20283DC12901C8B66A08FB8A9CB6A5E81989007B3AA43CD7442BED6D21F4D33FB590A46420FB75265C889D536A9519674440C3C2FB06C5924360243CACD4B641BE574C31A434CE845323395842FAAF106B234C2C1406E2F553073FF557D2DB6C5")]

Благодаря @Joe

Чтобы получить открытый ключ сборки друга:

sn -Tp path\to\assembly\MyFriendAssembly.dll

Внутри командной строки разработчика (Startup > Programs > Visual Studio 2015 > Инструменты Visual Studio > Командная строка разработчика для VS2015). Благодаря @Ian G.

Несмотря на то, что последний штрих, который заставило его работать для меня после вышеупомянутого, заключался в том, чтобы подписать проект библиотеки друзей так же, как и подписанный проект библиотеки. Поскольку это была новая тестовая библиотека, она еще не была подписана.

Ответ 11

Вам необходимо создать новый полный открытый ключ для сборки, а затем указать атрибут для сборки.

[assembly: InternalsVisibleTo("assemblyname,
PublicKey="Full Public Key")]

Следуйте приведенным ниже MSDN шагам, чтобы сгенерировать новый полный открытый ключ для сборки из visual studio.

Чтобы добавить элемент "Общий доступ к сборке" в меню "Сервис"

В Visual Studio нажмите Внешние инструменты в меню "Сервис".

В диалоговом окне "Внешние инструменты" нажмите Добавить и введите "Открытый ключ сборки" в поле "Название".

Заполните поле Command, перейдя на sn.exe. Обычно он устанавливается в следующем месте: C:\Program Files (x86)\Microsoft SDK\Windows\v7.0a\Bin\x64\sn.exe.

В поле "Аргументы" введите следующее (с учетом регистра): -Tp $(TargetPath). Установите флажок Использовать окно вывода.

Нажмите ОК. Новая команда добавляется в меню "Сервис".

Всякий раз, когда вам нужен токен открытого ключа сборки, которую вы разрабатываете, щелкните команду "Получить открытый ключ сборки" в меню "Сервис", а токен открытого ключа появится в окне "Вывод".

Ответ 12

Другая возможность, которая может быть сложной для отслеживания, в зависимости от того, как написан ваш код.

  • Вы вызываете внутренний метод, определенный в X из другой сборки Y
  • Подпись метода использует внутренние типы, определенные в Z
  • Затем вам нужно добавить [InternalsVisibleTo] в X И в Z

Например:

// In X
internal static class XType
{
    internal static ZType GetZ() { ... }
}

// In Y:
object someUntypedValue = XType.GetZ();

// In Z:
internal class ZType { ... }

Если у вас это написано, как указано выше, где вы не ссылаетесь на ZType непосредственно в Y, добавив Y в качестве друга X, вы можете быть удивлены, почему ваш код все еще не компилируется.

Ошибка компиляции может оказаться более полезной в этом случае.

Ответ 13

Применяется только в том случае, если вы хотите сохранить неподписанные сборки как неподписанную сборку (и не хотите подписывать ее по нескольким причинам):

Есть еще один момент: если вы скомпилируете свою базовую библиотеку из VS.Net в локальный каталог, она может работать как ожидалось.

НО: Как только вы скомпилируете базовую библиотеку на сетевой диск, применяются политики безопасности, и сборка не может быть успешно загружена. Это снова приводит к сбою VS.NET или компилятора при проверке соответствия PublicKey.

Наконец, можно использовать неподписанные сборки: https://msdn.microsoft.com/en-us/library/bb384966.aspx Вы должны убедиться, что сборки BOTH НЕ ПОДПИСАНЫ Атрибут Assembly должен быть без информации PublicKey:

<Assembly: InternalsVisibleTo("friend_unsigned_B")>

Ответ 14

Я пишу это из разочарования. Убедитесь, что сборка, к которой вы предоставляете доступ, названа так, как вы ожидаете.

Я переименовал свой проект, но это не автоматически обновляет имя сборки. Щелкните правой кнопкой мыши свой проект и выберите "Свойства". В разделе "Приложение" убедитесь, что Имя сборки и Место по умолчанию - это то, что вы ожидаете.

Ответ 15

У меня такая же проблема. Ни одно из решений не работало.

В конце концов выяснилось, что проблема связана с тем, что класс X явно реализует интерфейс Y, который является внутренним.

метод X.InterfaceMethod был недоступен, хотя я понятия не имею, почему.

Решением было бросить (X как YourInterface).InterfaceMethod в тестовой библиотеке, а затем все сработало.

Ответ 16

В качестве побочного примечания, если вы хотите легко получить открытый ключ, не используя sn и выяснить его параметры, вы можете загрузить удобную программу здесь. Он не только определяет открытый ключ, но также создает строку "assembly: InternalsVisibleTo...", которая готова к копированию в буфер обмена и вставлена ​​в ваш код.

Ответ 17

Я просто решил аналогичную проблему с атрибутом InternalsVisibleTo. Все казалось правильным, и я не мог понять, почему внутренний класс, к которому я стремился, еще не был доступен.

Изменение случая ключа от верхнего к нижнему регистру устраняет проблему.

Ответ 18

Если у вас есть более одной ссылочной сборки - убедитесь, что все необходимые сборки имеют атрибут InternalsVisibleTo. Иногда это не очевидно, и нет сообщения, что вы должны добавить этот атрибут в одну сборку.

Ответ 19

1- Подпишите тестовый проект: в Visual Studio перейдите в окно свойств тестового проекта и подпишите сборку, установив флажок с той же фразой на вкладке " Подписание ".

2- Создайте PublicKey для тестового проекта: Откройте командную строку Visual Studio (например, Командная строка разработчика для VS 2017). Перейдите в папку, где существует DLL файл тестового проекта. Создать открытый ключ через sn.exe:

sn -Tp TestProject.dll

Обратите внимание, что аргумент -Tp, но не -Tp.

3- Представьте PublicKey для тестируемого проекта. Перейдите в файл AssemblyInfo.cs в тестируемый проект и добавьте эту строку с помощью PublicKey, созданного на предыдущем шаге:

[сборка: InternalsVisibleTo ("TestProjectAssemblyName, ОткрытыйКлюч= 2066212d128683a85f31645c60719617ba512c0bfdba6791612ed56350368f6cc40a17b4942ff16cda9e760684658fa3f357c137a1005b04cb002400000480000094000000060200000024000052534131000400000100010065fe67a14eb30ffcdd99880e9d725f04e5c720dffc561b23e2953c34db8b7c5d4643f476408ad1b1e28d6bde7d64279b0f51bf0e60be2d383a6c497bf27307447506b746bd2075" )]

Не забудьте заменить вышеуказанный PublicKey своим.

4- Сделайте частный метод внутренним: в тестируемом проекте измените модификатор доступа метода на внутренний.

внутренний статический void DoSomething() {...}