سؤال

أحاول استخدام InternalsVisibleTo سمة التجميع لجعل فصولي الداخلية في مكتبة فئة .NET مرئية لمشروع اختبار الوحدة الخاص بي.لسبب ما، أتلقى باستمرار رسالة خطأ تقول:

لا يمكن الوصول إلى "MyClassName" نظرًا لمستوى الحماية الخاص به

تم توقيع كلا التجميعتين ولدي المفتاح الصحيح المدرج في إعلان السمة.أيه أفكار؟

هل كانت مفيدة؟

المحلول

هل أنت متأكد تمامًا من أن لديك المفتاح العام الصحيح المحدد في السمة؟لاحظ أنك تحتاج إلى تحديد المفتاح العام الكامل، وليس فقط الرمز المميز للمفتاح العام.يبدو شيء مثل:

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

إنها 320 رقمًا سداسيًا أو نحو ذلك.لست متأكدًا من سبب حاجتك إلى تحديد المفتاح العام الكامل - ربما باستخدام رمز المفتاح العام المستخدم في مراجع التجميع الأخرى فقط، سيكون من الأسهل على شخص ما انتحال هوية تجمع الأصدقاء.

نصائح أخرى

"مسكتك" محتملة أخرى:اسم تجمع الأصدقاء الذي تحدده في InternalsVisibleToAttribute يجب بالضبط قم بمطابقة اسم مجموعة أصدقائك كما هو موضح في خصائص مشروع الصديق (في علامة تبويب التطبيق).

في حالتي، كان لدي مشروع Thingamajig ومشروع مصاحب ThingamajigAutoTests (تم تغيير الأسماء لحماية المذنب) حيث أنتج كلاهما تجميعات غير موقعة.لقد أضفت السمة على النحو الواجب [assembly: InternalsVisibleTo( "ThingamajigAutoTests" )] إلى ملف Thingamajig\AssemblyInfo.cs، وقم بالتعليق على AssemblyKeyFile و AssemblyKeyName الصفات كما ذكرنا أعلاه.ال Thingamajig تم بناء المشروع على ما يرام، لكن أعضائه الداخليين رفضوا بعناد الظهور في مشروع الاختبار التلقائي.

بعد الكثير من خدش الرأس، قمت بإعادة فحص ThingamajigAutoTests خصائص المشروع، واكتشفت أنه تم تحديد اسم التجميع كـ "ThingamajigAutoTests.dll".Bingo - أضفت الامتداد ".dll" إلى اسم التجميع في ملف InternalsVisibleTo السمة، وسقطت القطع في مكانها.

أحياناً تكون أصغر الأشياء..

إذا لم يتم توقيع التجميعات الخاصة بك، ولكنك لا تزال تتلقى نفس الخطأ، فتحقق من ملف AssemblyInfo.cs الخاص بك بحثًا عن أي من الأسطر التالية:

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

ستستمر علامة التبويب "خصائص" في إظهار التجميع الخاص بك على أنه غير موقع في حالة وجود أحد هذين الخطين (أو كليهما)، لكن سمة InternalsVisibleTo تتعامل مع التجميع الذي يحتوي على هذه الأسطر على أنه موقع بقوة.ما عليك سوى حذف (أو التعليق) على هذه السطور، وسيعمل الأمر بشكل جيد بالنسبة لك.

تجدر الإشارة إلى أنه إذا كانت مجموعة "الصديق" (الاختبارات) مكتوبة بلغة C++/CLI، بدلاً من C#/VB.Net، فأنت بحاجة إلى استخدام ما يلي:

#using "AssemblyUnderTest.dll" as_friend

بدلا من مرجع المشروع أو المعتاد #using إفادة.لسبب ما، لا توجد طريقة للقيام بذلك في واجهة المستخدم المرجعية للمشروع.

يمكنك استخدام أداة مساعد التجميع من شأنها أن تولد بناء جملة InternalsVisibleTo لك.هنا الرابط إلى الإصدار الأحدث.لاحظ فقط أنه يعمل فقط مع التجميعات ذات الأسماء القوية.

إليك الماكرو الذي أستخدمه لإنشاء هذه السمة بسرعة.إنه اختراق قليلاً، لكنه يعمل.على الجهاز الخاص بي.عند دخول آخر ثنائي موقع /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

تحتاج إلى استخدام /out:مفتاح التحويل البرمجي عند تجميع مجموعة الصديق (التجميع الذي لا يحتوي على سمة InternalsVisibleto).

يحتاج المترجم إلى معرفة اسم التجميع الذي يتم تجميعه لتحديد ما إذا كان ينبغي اعتبار التجميع الناتج بمثابة تجميع صديق.

بالإضافة إلى كل ما سبق، عندما يبدو أن كل شيء على ما يرام، ولكن جمعية الأصدقاء ترفض بعناد رؤية أي شيء داخلي، إعادة تحميل الحل أو إعادة تشغيل Visual Studio يمكن أن تحل المشكلة.

في حالتي التي استخدمت فيها VS.Net 2015، كنت بحاجة إلى التوقيع كلاهما التجميعات (إذا تم توقيع تجميع واحد على الأقل أو إذا كنت تريد الرجوع إلى المفتاح العام لتجميعك).

لم يستخدم مشروعي التوقيع على الإطلاق.لذلك بدأت بإضافة مفتاح تسجيل إلى مكتبة الاختبار الخاصة بي واستخدام InternalsVisibleTo-Attribute في المكتبة الأساسية لمشروعي.لكن VS.Net أوضحت دائمًا أنها لا تستطيع الوصول إلى طرق الأصدقاء.

عندما بدأت في التوقيع على المكتبة الأساسية (يمكن أن يكون هو نفسه أو مفتاح تسجيل آخر - طالما قمت بالتوقيع على المكتبة الأساسية)، كان VS.Net قادرًا على العمل على الفور كما هو متوقع.

عملت الإجابات السابقة مع PublicKey:(فيجوال ستوديو 2015:يجب أن يكون على سطر واحد، وإلا فإنه يشكو من أن مرجع التجميع غير صالح أو لا يمكن الرجوع إليه.PublicKeyToken لم يعمل)

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

شكرا لجو

للحصول على المفتاح العام لتجميع الأصدقاء:

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

داخل موجه أوامر المطور (بدء التشغيل > البرامج > Visual Studio 2015 > أدوات Visual Studio > موجه أوامر المطور لـ VS2015).بفضل @ إيان ج.

على الرغم من أن اللمسة الأخيرة التي جعلت الأمر يعمل بالنسبة لي بعد ما ورد أعلاه كانت التوقيع على مشروع مكتبة صديقي بنفس الطريقة التي يتم بها التوقيع على مشروع المكتبة المراد مشاركتها.نظرًا لأنها كانت مكتبة اختبارية جديدة، فلم يتم التوقيع عليها بعد.

أنت مطالب بإنشاء مفتاح عام كامل جديد للتجميع ثم تحديد السمة للتجميع.

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

اتبع أدناه MSDN خطوات إنشاء مفتاح عام كامل جديد للتجميع من الاستوديو المرئي.

لإضافة عنصر Get Assembly Public Key إلى قائمة الأدوات

في Visual Studio، انقر فوق الأدوات الخارجية في القائمة أدوات.

في مربع الحوار أدوات خارجية، انقر فوق يضيف وأدخل الحصول على المفتاح العام للتجميع في مربع العنوان.

املأ مربع الأوامر بالاستعراض إلى sn.exe.يتم تثبيته عادةً في الموقع التالي: C:\ملفات البرنامج (x86)\Microsoft SDKs\Windows\v7.0a\Bin\x64\sn.exe.

في مربع الوسائط، اكتب ما يلي (حساس لحالة الأحرف): -Tp $(TargetPath).حدد خانة الاختيار استخدام نافذة الإخراج.

انقر نعم.تتم إضافة الأمر الجديد إلى قائمة الأدوات.

عندما تحتاج إلى رمز المفتاح العام للتجميع الذي تقوم بتطويره، انقر فوق أمر الحصول على المفتاح العام للتجميع في قائمة الأدوات، وسيظهر رمز المفتاح العام في نافذة الإخراج.

احتمال آخر قد يكون من الصعب تعقبه، اعتمادًا على كيفية كتابة التعليمات البرمجية الخاصة بك.

  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، فقد تشعر بالحيرة من سبب عدم تجميع التعليمات البرمجية الخاصة بك.

من المؤكد أن خطأ الترجمة يمكن أن يكون أكثر فائدة في هذه الحالة.

ينطبق فقط إذا كنت ترغب في الاحتفاظ بالتجميعات غير الموقعة كتجميع غير موقع (ولا تريد التوقيع عليها لعدة أسباب):

لا تزال هناك نقطة أخرى:إذا قمت بتجميع مكتبتك الأساسية من VS.Net إلى دليل محلي، فقد تعمل كما هو متوقع.

لكن:بمجرد تجميع المكتبة الأساسية الخاصة بك إلى محرك أقراص الشبكة، يتم تطبيق سياسات الأمان ولا يمكن تحميل التجميع بنجاح.يؤدي هذا مرة أخرى إلى فشل VS.NET أو المترجم عند التحقق من تطابق PublicKey.

أخيرًا، من الممكن استخدام التجميعات غير الموقعة:https://msdn.microsoft.com/en-us/library/bb384966.aspxيجب عليك التأكد من عدم توقيع كلا التجميعين ويجب أن تكون سمة التجميع بدون معلومات publickey:

<Assembly: InternalsVisibleTo("friend_unsigned_B")>

أنا أكتب هذا من الإحباط.تأكد من تسمية التجميع الذي تمنحه حق الوصول إليه كما تتوقع.

لقد قمت بإعادة تسمية مشروعي ولكن هذا لا يؤدي إلى تحديث اسم التجميع تلقائيًا.انقر بزر الماوس الأيمن فوق المشروع الخاص بك وانقر فوق ملكيات.تحت طلب, ، تأكد من أن اسم الجمعية و مساحة الاسم الافتراضية هي ما تتوقعه.

كان لي نفس المشكلة.لم ينجح أي من الحلول.

تم اكتشاف المشكلة في النهاية بسبب قيام الفئة X بتنفيذ الواجهة Y بشكل صريح، وهي واجهة داخلية.

لم تكن طريقة X.InterfaceMethod متاحة، على الرغم من أنني لا أملك أي فكرة عن السبب.

كان الحل هو إرسال (X كـ YourInterface).InterfaceMethod في مكتبة الاختبار، وبعد ذلك نجحت الأمور.

كملاحظة جانبية، إذا كنت تريد الحصول على المفتاح العام بسهولة دون الحاجة إلى استخدام sn ومعرفة خياراته، يمكنك تنزيل البرنامج المفيد هنا.فهو لا يحدد المفتاح العام فحسب، بل يقوم أيضًا بإنشاء "التجميع:InternalsVisibleTo..." سطر جاهز للنسخ إلى الحافظة ولصقه في التعليمات البرمجية الخاصة بك.

لقد قمت للتو بحل مشكلة مماثلة مع InternalsVisibleTo يصف.بدا كل شيء على ما يرام ولم أتمكن من معرفة سبب عدم إمكانية الوصول إلى الطبقة الداخلية التي كنت أستهدفها.

أدى تغيير حالة المفتاح من الأحرف الكبيرة إلى الأحرف الصغيرة إلى حل المشكلة.

إذا كان لديك أكثر من تجميع مرجعي واحد - تأكد من أن جميع التجميعات الضرورية تحتوي على سمة InternalsVisibleTo.في بعض الأحيان، لا يكون الأمر واضحًا ولا توجد رسالة مفادها أنه يتعين عليك إضافة هذه السمة إلى مجموعة واحدة أخرى.

1- التوقيع على مشروع الاختبار: في Visual Studio، انتقل إلى نافذة الخصائص مشروع الاختبار و التوقيع على التجمع عن طريق تحديد مربع الاختيار الذي يحتوي على نفس العبارة في التوقيع فاتورة غير مدفوعة.

2- إنشاء مفتاح عام لمشروع الاختبار: افتح موجه أوامر Visual Studio (على سبيل المثال.موجه أوامر المطور لـ VS 2017).انتقل إلى المجلد الذي يوجد به ملف .dll مشروع الاختبار موجود.قم بإنشاء مفتاح عام عبر sn.exe:

sn-Tp TestProject.dll

لاحظ أن الوسيطة هي -Tp، ولكنها ليست -tp.

3- قم بإدخال المفتاح العام للمشروع المراد اختباره: انتقل إلى ملف AssemblyInfo.cs في المشروع المراد اختباره وأضف هذا السطر مع PublicKey الذي تم إنشاؤه في الخطوة السابقة:

[حَشد:إنترينلسفيسيبليتو("اسم المشروع التجريبي, المفتاح العمومي=2066212d128683a85f31645c60719617ba512c0bfdba6791612ed56350368f6cc40a17b4942ff16cda9e760684658fa3f357c137a1005b04cb0024000004800000 94000000060200000024000052534131000400000100010065fe67a14eb30ffcdd99880e9d725f04e5c720dffc561b23e2953c34db8b7c5d4643f476408ad1b1e2 8d6bde7d64279b0f51bf0e60be2d383a6c497bf27307447506b746bd2075")]

لا تنس استبدال PublicKey أعلاه بمفتاحك.

4- جعل الطريقة الخاصة داخلية: في المشروع الذي سيتم اختباره، قم بتغيير معدل الوصول للطريقة إلى داخلي.

ساكنة داخلية باطلة تفعل شيئا (){...}

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top