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

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

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

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


person skb    schedule 20.09.2008    source источник
comment
Можете ли вы опубликовать то, что у вас есть для атрибута InternalsVisibleTo, в классе, который вы пытаетесь раскрыть? Трудно сказать, что не так, не видя того, на что вы смотрите.   -  person Eric Schoonover    schedule 20.09.2008


Ответы (19)


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

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

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

person Joe    schedule 20.09.2008
comment
Чтобы получить открытый ключ дружественной сборки sn -Tp MyFriendAssembly - person Ian G; 06.07.2009
comment
@Tyler: Вот почему вам следует @ people. Я добавляю ответ ниже, содержащий макрос VS, который можно использовать для создания IVT для проекта в вашем решении. - person ; 22.03.2012
comment
Чтобы прояснить комментарий @Ian G, откройте командную строку Visual Studio, смените каталог (компакт-диск) на соответствующий каталог, содержащий файл dll сборки друга. В командной строке введите sn.exe -Tp NameOfAssembly или просто sn - Tp NameOfAssembly, как сказал Ян. При этом используется Microsoft Strong Name Tool для поиска и отображения полного открытого ключа из сборки. Если у вас есть только файл .pub, содержащий ваш ключ, вы можете извлечь его с помощью sn.exe -p NameOfKeyFile.snk NameOfKeyPairFile.pub. Это создаст ключевой файл NameOfKeyFile.snk, который затем позволит вам следовать предыдущим инструкциям. - person Sheridan; 08.02.2013
comment
Действительно важно, по крайней мере, для VS2012, что атрибут [assembly:InternalsVisibleTo("...")] должен находиться в одной строке, несмотря на очевидное форматирование примера здесь и в документации MSDN. Вы не можете просто скопировать и вставить вывод открытого ключа из sn.exe -Tp MyFriendAssembly, а затем использовать @"multi line string" (обратите внимание на символ @), иначе компилятор будет жаловаться на ...does not contain a definition for 'X' and no extension method 'X' ... could be found при попытке доступа к вашим внутренним компонентам из MyFriendAssembly. - person AlwaysLearning; 21.05.2015
comment
Также убедитесь, что вы не создали новый файл ключа в проекте модульного теста. Вы должны загрузить ключевой файл из основного проекта. Я был немного медленным и сделал это (в первый раз) и немного поругался, пытаясь понять, почему это все еще не работает. Кроме того, очень простой способ получить открытый ключ можно найти по адресу БЛОГ MSDN. Затем замените аргумент -T $(TargetPath) на -Tp $(TargetPath) - person famousKaneis; 09.07.2015
comment
Я работаю с большой устаревшей базой кода, обновляя ее ... и получаю проблемы с Sgen ... Я не могу собрать сборку моего друга, пока не соберу свою основную сборку, так как можно получить токен от моего друга. dll, когда он еще не может его построить? - person GilesDMiddleton; 27.07.2015
comment
@Gilesey, вы используете упомянутый инструмент sn, вы можете настроить таргетинг на файл snk или pfx, который вы используете в Visual Studio, чтобы извлечь полный открытый ключ, а затем использовать его в атрибуте сборки. Просто убедитесь, что вы выбрали правильный ключевой файл для сборки, о которой вы говорите. Если визуальная студия жалуется на идентичность сборки, внутренности видны и не являются именем, которое она может разрешить, используйте заменяющую сборку (пустую сборку, подписанную), пока не дойдете до той точки разработки, когда оба компилируются. - person Allen Clark Copeland Jr; 22.12.2015

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

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

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

Иногда это мелочи ...

person John Beyer    schedule 26.07.2013
comment
+1, поскольку ваш комментарий помог мне: в моем случае я в какой-то момент переименовал сборку, но VS оставил имя сборки и пространство имен по умолчанию в свойствах проекта в качестве старых значений - person Nij; 12.09.2013
comment
Хм. Для меня как раз наоборот. Мне пришлось удалить .dll для построения решения. - person kmote; 18.06.2014
comment
Я могу подтвердить, что @kmote прав: мне пришлось удалить .dll для решения для сборки (и Intellisense для работы). (.NET 4.5, VS2013, неподписанные сборки) Очень странное поведение. Этот вопрос и все ответы на него отлично подходят для решения проблем с этим явно проблематичным атрибутом. - person davidbak; 30.04.2015
comment
С моей точностью набора текста я в значительной степени обречен, когда дело доходит до правильного определения этого атрибута. Полезный совет! - person timmyl; 10.01.2016
comment
+1 то же самое и с пробелами. Почему в имени моей сборки есть пробел, я не знаю, но это исправило. : D - person user3797758; 21.05.2017

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

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

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

person Skimedic    schedule 29.08.2010
comment
Спасибо, это была моя проблема, и я нигде больше не мог найти этот ответ. - person Andre; 26.09.2011
comment
Это спасло меня после того, как MyAssembly.dll не представлял строго именованную сборку при вызове sn.exe -Tp MyAssembly.dll - person Dunc; 09.05.2013

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

#using "AssemblyUnderTest.dll" as_friend

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

person Colin Desmond    schedule 20.04.2009


Вот макрос, который я использую для быстрой генерации этого атрибута. Это немного взломано, но работает. На моей машине. Когда последний подписанный двоичный файл находится в /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
person Community    schedule 22.03.2012

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

person Alex J    schedule 17.09.2014
comment
Повторная загрузка двух проектов устранила это для меня в Visual Studio 2017. - person Bob Lokerse; 05.07.2019

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

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

person Ash    schedule 20.09.2008
comment
По умолчанию целевые объекты Microsoft C # добавят параметр /out, если файл .msbuild содержит следующие строки: <PropertyGroup> <AssemblyName>YourFriendAssemblyName</AssemblyName> </PropertyGroup>. Это также можно установить в свойствах проекта на вкладке «Приложение» в поле «Имя сборки». - person Suzanne Soy; 21.05.2013

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

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

Чтобы сгенерировать новый полный открытый ключ для сборки из Visual Studio.

Чтобы добавить элемент "Получить открытый ключ сборки" в меню "Инструменты"

В Visual Studio выберите Внешние инструменты в меню Инструменты.

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

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

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

Нажмите ОК. Новая команда добавлена ​​в меню «Инструменты».

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

person Murugan Sivananantha Perumal    schedule 18.10.2015
comment
Путь к Visual Studio 2019: C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\sn.exe - person Vishal; 23.03.2020
comment
и вы можете скачать sdk здесь developer.microsoft.com/ ru-us / windows / downloads / windows-10-sdk - person Walter Vehoeven; 03.07.2020

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

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

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

person Jochen    schedule 25.11.2015

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

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

Спасибо @Joe

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

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

Внутри командной строки Developper (Startup> Programs> Visual Studio 2015> Visual Studio Tools> Developer Command Prompt for VS2015). Благодаря @Ian G.

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

person Micaël    schedule 14.10.2015

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

  1. Вы вызываете внутренний метод, определенный в X, из другой сборки Y
  2. В сигнатуре метода используются внутренние типы, определенные в Z
  3. Затем вам нужно добавить [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 вы можете быть озадачены, почему ваш код все еще не компилируется.

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

person Tatiana Racheva    schedule 08.10.2016

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

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

person Kameron Kincade    schedule 19.10.2017

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

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

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

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

<Assembly: InternalsVisibleTo("friend_unsigned_B")>

person Jochen    schedule 25.11.2015

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

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

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

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

person Sentinel    schedule 29.03.2018

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

person Bill W    schedule 26.04.2012

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

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

person Keysharpener    schedule 26.02.2013

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

person VladExL    schedule 29.03.2018

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 () {...}

person karr    schedule 03.12.2018