تضمين واحد dll داخل آخر باعتبارها جزءا لا يتجزأ من الموارد ومن ثم استدعاء من قانون بلدي

StackOverflow https://stackoverflow.com/questions/96732

  •  01-07-2019
  •  | 
  •  

سؤال

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

هذا مع C#.NET framework 3.5.

الطريقة أود أن تفعل هذا من خلال تخزين الطرف الثالث DLL باعتبارها جزءا لا يتجزأ من الموارد التي لا ثم ضع في المكان المناسب أثناء تنفيذ أول DLL.

الطريقة التى كان مقررا في الأصل للقيام بذلك هي من خلال كتابة كود لوضع الطرف الثالث DLL في الموقع المحدد من قبل System.Reflection.Assembly.GetExecutingAssembly().Location.ToString() ناقص الماضي /nameOfMyAssembly.dll.يمكنني بنجاح حفظ الطرف الثالث .DLL في هذا الموقع (الذي ينتهي في

C:\Documents and Settings\myUserName\Local Settings\Application البيانات\assembly\dl3\KXPPAX6Y.ZCY\A1MZ1499.1TR\e0115d44\91bb86eb_fe18c901

) ، ولكن عندما أحصل على جزء من التعليمات البرمجية التي تتطلب هذا DLL, فإنه لا يمكن العثور عليه.

لا أحد لديه أي فكرة عن ما كنت بحاجة إلى أن تفعل بشكل مختلف ؟

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

المحلول

بمجرد جزءا لا يتجزأ من طرف ثالث الجمعية كمورد ، إضافة رمز الاشتراك AppDomain.AssemblyResolve الحدث الحالي المجال خلال بدء التطبيق.وقع هذا الحدث كلما الانصهار النظام الفرعي من CLR فشلت في تحديد موقع الجمعية وفقا التحقيق (السياسات) في التأثير.في حال معالج AppDomain.AssemblyResolve, تحميل الموارد باستخدام Assembly.GetManifestResourceStream و تغذية المحتوى كما صفيف بايت في المقابلة Assembly.Load الزائد.وفيما يلي كيفية هذا التنفيذ قد تبدو في C#:

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
    var resName = args.Name + ".dll";    
    var thisAssembly = Assembly.GetExecutingAssembly();    
    using (var input = thisAssembly.GetManifestResourceStream(resName))
    {
        return input != null 
             ? Assembly.Load(StreamToBytes(input))
             : null;
    }
};

حيث StreamToBytes يمكن تعريفه بأنه:

static byte[] StreamToBytes(Stream input) 
{
    var capacity = input.CanSeek ? (int) input.Length : 0;
    using (var output = new MemoryStream(capacity))
    {
        int readLength;
        var buffer = new byte[4096];

        do
        {
            readLength = input.Read(buffer, 0, buffer.Length);
            output.Write(buffer, 0, readLength);
        }
        while (readLength != 0);

        return output.ToArray();
    }
}

وأخيرا بضع سبق ذكره ، ILMerge قد يكون هناك خيار آخر للنظر ، وإن كان إلى حد ما أكثر المشاركة.

نصائح أخرى

في النهاية أنا فعلت هذا بالضبط تقريبا الطريقة raboof اقترح (و على غرار ما dgvid المقترح) ، ما عدا بعض التغييرات الطفيفة وبعض السهو الثابتة.اخترت هذا الأسلوب لأنه كان أقرب إلى ما كنت أبحث عنه في المقام الأول و لا تتطلب استخدام أي طرف ثالث التنفيذية وكذا.يعمل كبيرة!

هذا هو ما رمز انتهى تبدو مثل:

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

هذا هو نسخة محدثة الذي يسمح لك بالمرور في الجمعية مع جزءا لا يتجزأ من dlls.

embeddedResourcePrefix هو سلسلة الطريق إلى الموارد المضمنة, فإنه عادة ما يكون اسم الجمعية تليها أي بنية المجلد يحتوي على الموارد (على سبيل المثال"MyComapny.MyProduct.MyAssembly.الموارد" إذا كان dll في مجلد يسمى الموارد في المشروع).فإنه يفترض أيضا أن dll لديه .dll.الموارد التمديد.

   public static void EnableDynamicLoadingForDlls(Assembly assemblyToLoadFrom, string embeddedResourcePrefix) {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { // had to add =>
            try {
                string resName = embeddedResourcePrefix + "." + args.Name.Split(',')[0] + ".dll.resource";
                using (Stream input = assemblyToLoadFrom.GetManifestResourceStream(resName)) {
                    return input != null
                         ? Assembly.Load(StreamToBytes(input))
                         : null;
                }
            } catch (Exception ex) {
                _log.Error("Error dynamically loading dll: " + args.Name, ex);
                return null;
            }
        }; // Had to add colon
    }

    private static byte[] StreamToBytes(Stream input) {
        int capacity = input.CanSeek ? (int)input.Length : 0;
        using (MemoryStream output = new MemoryStream(capacity)) {
            int readLength;
            byte[] buffer = new byte[4096];

            do {
                readLength = input.Read(buffer, 0, buffer.Length); // had to change to buffer.Length
                output.Write(buffer, 0, readLength);
            }
            while (readLength != 0);

            return output.ToArray();
        }
    }

هناك أداة تسمى IlMerge التي يمكن أن إنجاز هذا: http://research.microsoft.com/~mbarnett/ILMerge.aspx

ثم يمكنك جعل مجرد بناء الحدث مشابهة لما يلي.

Set Path="C:\Program Files\Microsoft\ILMerge"

ilmerge /out:$(ProjectDir)\Deploy\LevelEditor.exe $(ProjectDir)\bin elease elease.exe $(ProjectDir)\bin elease\InteractLib.dll $(ProjectDir)\bin elease\SpriteLib.dll $(ProjectDir)\bin elease\LevelLibrary.dll

لقد كان النجاح تفعل ما كنت تصف ، ولكن لأن الطرف الثالث DLL هو أيضا .صافي الجمعية لم كتابتها إلى القرص, أنا فقط تحميل من الذاكرة.

أنا الحصول على الموارد المضمنة الجمعية صفيف بايت مثل ذلك:

        Assembly resAssembly = Assembly.LoadFile(assemblyPathName);

        byte[] assemblyData;
        using (Stream stream = resAssembly.GetManifestResourceStream(resourceName))
        {
            assemblyData = ReadBytesFromStream(stream);
            stream.Close();
        }

ثم تحميل البيانات مع الجمعية.الحمل().

أخيرا, إضافة إلى معالج AppDomain.CurrentDomain.AssemblyResolve لإعادة تحميلها الجمعية عندما اكتب محمل يبدو.

ترى .صافي الانصهار ورشة عمل للحصول على تفاصيل إضافية.

يمكنك تحقيق ذلك بشكل ملحوظ بسهولة باستخدام Netz, ، .صافي صافي التنفيذية ضاغط & باكر.

بدلا من كتابة الجمعية إلى القرص يمكنك محاولة القيام الجمعية.تحميل(byte[] rawAssembly) حيث يمكنك إنشاء rawAssembly من الموارد المضمنة.

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