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

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

'MyClassName' is inaccessible due to its protection level

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

 Eric Schoonover20 сент. 2008 г., 05:04
Можете ли вы опубликовать то, что у вас есть для атрибута InternalsVisibleTo в классе, который вы пытаетесь выставить? Трудно сказать, что не так, не видя, на что вы смотрите.

Ответы на вопрос(19)

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

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

Я переименовал свой проект, но это не приводит к автоматическому обновлению имени сборки. Щелкните правой кнопкой мыши ваш проект и нажмитеProperties, ПодApplicationубедитесь, чтоAssembly Name а такжеDefault Namespace это то, что вы ожидаете.

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

Решение Вопроса

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

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

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

 06 июл. 2009 г., 11:54
Чтобы получить открытый ключ сборки друзей & quot; sn -Tp MyFriendAssembly & quot;
 23 нояб. 2009 г., 17:37
-1000 для документов MSDN по этому вопросу, которые еще не завершены.
 08 февр. 2013 г., 18:10
Чтобы уточнить комментарий @Ian G ', откройте командную строку Visual Studio, измените каталог (CD) на соответствующий каталог, содержащий «a Friend». Сборка DLL файла. В командной строке введитеsn.exe -Tp NameOfAssembly, или простоsn - Tp NameOfAssembly как сказал Ян Это использует инструмент строгого имени Microsoft для поиска и отображения полного открытого ключа из сборки. Если у вас есть только файл .pub, содержащий ваш ключ, вы можете извлечь его, используяsn.exe -p NameOfKeyFile.snk NameOfKeyPairFile.pub, Это создаст файл ключа NameOfKeyFile.snk, который затем позволит вам следовать предыдущим инструкциям.
 21 мая 2015 г., 07:44
Действительно важно, по крайней мере с VS2012, это то, что[assembly:InternalsVisibleTo("...")] атрибутmust be on a single line несмотря на очевидное форматирование примера здесь и в документации MSDN. Вы не можете просто скопировать и вставить вывод открытого ключа изsn.exe -Tp MyFriendAssembly а затем использовать@"multi line string" (обратите внимание на символ @) или компилятор будет жаловаться...does not contain a definition for 'X' and no extension method 'X' ... could be found при попытке получить доступ к вашим внутренностям из MyFriendAssembly.
 06 февр. 2012 г., 18:33
отлично, так как мне получить этот ключ?

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

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

Стоит отметить, что если «друг» Сборка (тесты) написана на C ++ / CLI, а не на C # / VB.Net, тогда вам нужно использовать следующее:

#using "AssemblyUnderTest.dll" as_friend

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

 10 мая 2010 г., 03:25
Вау, не знал, что

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

You're invoking an internal method defined in X from another assembly Y The method signature uses internal types defined in Z You then have to add [InternalsVisibleTo] in X AND in 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, вы можете быть озадачены, почему ваш код по-прежнему не компилируется.

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

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

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
 23 мар. 2012 г., 10:08
Спасибо, @ я запомню это в следующий раз!

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

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

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

 26 сент. 2011 г., 19:02
Спасибо, это была моя проблема, и больше нигде я не мог найти этот ответ.
 09 мая 2013 г., 12:18
Это спасло меня после получения & quot; MyAssembly.dll не представляет сборку со строгим именем & quot; при вызове sn.exe -Tp MyAssembly.dll

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

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

 21 мая 2013 г., 19:15
По умолчанию цели Microsoft C # добавят/out опция, если файл .msbuild содержит следующие строки:<PropertyGroup> <AssemblyName>YourFriendAssemblyName</AssemblyName> </PropertyGroup>, Это также может быть установлено в свойствах проекта, в «Приложении». на вкладке «Имя сборки» поле.
 26 нояб. 2013 г., 00:33
Бинго, это тоже была моя проблема. Спасибо 5 лет спустя!

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

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

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

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

<Assembly: InternalsVisibleTo("friend_unsigned_B")>

Инструмент AssemblyHelper это сгенерирует синтаксис InternalsVisibleTo для вас. Здесь & APOS; sссылка на последнюю версию, Просто отметьте, что это работает только для сборок со строгим именем.

 06 февр. 2019 г., 15:34
Странно, даже используя это, он все еще не работает в моем тестовом приложении .NET core 2.2

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

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

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

Решением было привести (X как YourInterface) .InterfaceMethod в тестовую библиотеку, и тогда все заработало.

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

1- Sign the test project: В Visual Studio перейдите в окно свойствthe test project а такжеSign the assembly установив флажок с той же фразой вSigning Вкладка.

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

sn -Tp TestProject.dll

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

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

[сборка: InternalsVisibleTo (& quot;TestProjectAssemblyName, PublicKey= 2066212d128683a85f31645c60719617ba512c0bfdba6791612ed56350368f6cc40a17b4942ff16cda9e760684658fa3f357c137a1005b04cb002400000480000094000000060200000024000052534131000400000100010065fe67a14eb30ffcdd99880e9d725f04e5c720dffc561b23e2953c34db8b7c5d4643f476408ad1b1e28d6bde7d64279b0f51bf0e60be2d383a6c497bf27307447506b746bd2075 & Quot;)]

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

4- Make the private method internal: В тестируемом проекте измените модификатор доступа метода к внутреннему.

internal static void DoSomething () {...}

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

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

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

 23 окт. 2016 г., 20:58
Спасибо! Я перепробовал все в VS2015. Подписание обеих сборок исправило это для меня.

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

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

После долгих царапин я перепроверилThingamajigAutoTests в свойствах проекта и обнаружил, что имя сборки было указано как «ThingamajigAutoTests.dll». Бинго - я добавил & quot; .dll & quot; расширение имени сборки вInternalsVisibleTo атрибут, и кусочки встали на свои места.

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

 30 апр. 2015 г., 05:44
Я могу подтвердить, что @kmote прав: мне пришлосьremove & quot; .dll & quot; для решения для построения (и Intellisense для работы). (.NET 4.5, VS2013, неподписанные сборки) Очень странное поведение. Этот вопрос иall его ответы потрясающие, чтобы решить проблемы с этим, по-видимому, проблематичным признаком
 10 янв. 2016 г., 21:08
С моей точностью набора текста я довольно обречен, когда дело доходит до правильной настройки этого атрибута. Полезный совет!
 21 мая 2017 г., 14:46
+1 это будет также в случае с пробелами. Почему в имени моей сборки есть пробел, я не знаю, но это исправило это. : D
 17 июн. 2014 г., 23:04
Хм. Как раз наоборот для меня. Мне пришлосьremove & quot; .dll & quot; для решения, чтобы построить.
 12 сент. 2013 г., 17:40
+1, поскольку ваш комментарий помог мне: в моем случае я переименовал сборку в какой-то момент, но VS оставил Имя сборки и пространство имен по умолчанию в Свойствах проекта как старые значения

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

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

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

To add a Get Assembly Public Key item to the Tools menu

В Visual Studio щелкнитеExternal Tools в меню Сервис.

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

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

В поле Аргументы введите следующее (с учетом регистра):-Tp $(TargetPath). Select the Use Output window check box.

НажмитеOK, Новая команда добавлена в меню Инструменты.

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

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

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

Благодаря @Joe

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

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

Внутри командной строки Developper («Запуск»> «Программы»> «Visual Studio 2015»> «Командная строка разработчика для VS2015»). Благодаря @Ian G.

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

Ваш ответ на вопрос