تقوم الإعدادات.Default.<property> دائمًا بإرجاع القيمة الافتراضية بدلاً من القيمة الموجودة في التخزين المستمر (ملف XML)

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

سؤال

لقد قمت مؤخرًا بكتابة ملف DLL بلغة C# (.Net 2.0) والذي يحتوي على فئة تتطلب عنوان IP.قام أحد زملائي في العمل بتغيير الفصل لاسترداد عنوان IP من ملف ".dll.config" (XML) - يبدو أن هذا يتم إنشاؤه تلقائيًا بواسطة ملف "إعدادات التطبيق" الذي أنشأه (Settings1.settings).وكانت فائدة ذلك هي السماح للمستخدم النهائي بتغيير عنوان IP في ملف XML/config حسب الرغبة.

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

يبدو المنشئ الذي يستدعي ملف التكوين كما يلي:

    public class form : System.Windows.Forms.Form
    {
        public form()
        {
            // This call is required by the Windows Form Designer.
            InitializeComponent();
            IP = IPAddress.Parse(Settings1.Default.IPAddress);
        }
    }

وجدت إشارة إلى هذه المشكلة في منتديات MSDN حيث قال أحد المستخدمين:

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

  1. هل هذا يعني أنه لا يمكنني تخزين قيمة خارجية لملف DLL في ملف التكوين؟(لقد قام زميلي في العمل بهذا العمل بطريقة ما ...)

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

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

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

جانبًا، يمكنني تغيير "نوع الإخراج" للتجميع الخاص بي من "مكتبة الفئات" إلى "تطبيق Windows" وإضافة الأسطر التالية في بداية كود DLL الخاص بي:

    [STAThread]
    public static void Main(string[] args)
    {
        System.Windows.Forms.Application.Run(new form());
    }

عندما أقوم بتشغيل هذا، فإنه يقوم بإنشاء ملف تكوين مختلف (".exe.config") وهذا الملف الذي يمكنني تعديله وجعله يسحب البيانات الجديدة من الملف.لذلك أنا مرتبك بعض الشيء.أيه أفكار؟

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

المحلول

إنني أتناول هذه المشكلة بالتحديد في أحد التطبيقات، وأنا في منتصف عملية إنشاء النماذج الأولية.على الرغم من أن اقتراح ديكر باختراق ملفات التكوين معًا يجب أن ينجح، إلا أنني أعتقد أن هذا اختراق يدوي غير مناسب جدًا لتنفيذه كجزء من دورة البناء.بدلاً من ذلك، قررت أن الحل الأنظف هو أن تقوم كل مكتبة بتحليل ملف Library.dll.config الخاص بها.إنها لا تزال غير مثالية وتتطلب بعض التعليمات البرمجية النموذجية الإضافية، ولكن يبدو أنها الطريقة الوحيدة للالتفاف على الطريقة البيزنطية التي يتعامل بها .Net مع ملفات app.config هذه.

نصائح أخرى

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

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

فيما يلي مقتطف يوضح هذه السمة:

فيما يلي مقتطف يوضح القيمة الافتراضية لـ ConcordanceServicesEndpointName في الفئة التي تم إنشاؤها:

    [global::System.Configuration.ApplicationScopedSettingAttribute()]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Configuration.DefaultSettingValueAttribute("InternalTCP")]

    public string ConcordanceServicesEndpointName {
        get {
            return ((string)(this["ConcordanceServicesEndpointName"]));
        }
    }

ما تريد القيام به هو نسخ قسم التكوين من ملف app.config من مشروع تجميع المكتبة ودمجه (بعناية) في web.config أو app.config المناسب للتجميع الرئيسي.في وقت التشغيل، هذا هو ملف التكوين الوحيد الذي يتم استخدامه.

هنا مثال:

<configSections>
    <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
      <section name="LitigationPortal.Documents.BLL.DocumentsBLLSettings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup>
  </configSections>
  <applicationSettings>
    <LitigationPortal.Documents.BLL.DocumentsBLLSettings>
      <setting name="ConcordanceServicesEndpointName" serializeAs="String">
        <value>InternalTCP</value>
      </setting>
    </KayeScholer.LitigationPortal.Documents.BLL.DocumentsBLLSettings>
  </applicationSettings>

يجب عليك نسخ هذه الأقسام إلى ملف التكوين "الحقيقي".

لقد واجهت نفس المشكلة لفترة طويلة - إنها مزعجة.

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

أحد الأشياء التي قمت بها في الماضي لتسهيل الأمر على الأقل هو التأكد من أن أي قيم تكوين في ملفSetting1.Settings غير صالحة.

على سبيل المثال، لدي فصل يستخدم LINQ-To-SQL للتحدث إلى قاعدة البيانات.لذا فهو يحتوي على ملفSetting1.settings الذي يقوم بتخزين سلسلة الاتصال بقاعدة البيانات فيه.القيمة الافتراضية التي يتم إدخالها (عند سحب وإفلات جداول قاعدة البيانات في المصمم) هي سلسلة الاتصال بقاعدة بيانات التطوير.

بمجرد إنشاء ملف DBML استنادًا إلى قاعدة بيانات الاختبار، يمكنني الدخول وتحرير ملف الإعدادات وكتابة اسم قاعدة البيانات مثل "FAKE_DATABASE".

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

بالطبع، إذا كان عليك العمل مع المصمم مرة أخرى، فسيتعين عليك تغيير القيمة مرة أخرى إلى قيمة قاعدة بيانات التطوير الخاصة بك.

ألم ضخم.عليهم تغيير هذا بطريقة أو بأخرى.

من الواضح أن تطبيقك يحاول القراءة من ملف التكوين الافتراضي (والذي من المحتمل أن يكون ملف تكوين التطبيق).للتأكد، أضف زوج المفتاح والقيمة في ملف التكوين الخاص بـ dll إلى ملف التكوين الخاص بالتطبيق، وقم بتشغيل التطبيق ومعرفة ما إذا كان قد تمت قراءته هذه المرة.

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

إصلاح ذلك هو التأكد من أن التطبيق الخاص بك وتجميعات الدعم لها نفس مساحة الاسم أو التأكد من دمج محتويات AppName.exe.config وDllName.dll.config (نعم عندما تقوم بتجميع ملف .dll الآن فإنه ينشئ هذا الملف، ولكن يتم تجاهله إذا قمت بنسخه إلى دليل التطبيق ولا يتم دمجه تلقائيًا)

لذلك إما أن أحتفظ بملف DLL والتطبيق في نفس مساحة الاسم - أو - لا بد لي من دمج محتويات ملف تكوين DLL مع ملف تكوين التطبيق.

(أليس هذا النوع من الهزيمة هو غرض DLL؟اعتقدت أنه من المفترض أن يكون DLL مكتبة مستقلة.)

ربما هذا هو السبب في أنه يعمل مع زميلي في العمل.يشترك تطبيق الإنتاج في نفس مساحة الاسم مثل DLL.(من الواضح أن تطبيق الاختبار الخاص بي لا...)

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

لقد رأيت مشكلة مماثلة عند استخدام app.config.حاول تشغيل التطبيق الخاص بك من ملف .exe بدلاً من Visual Studio ومعرفة ما إذا كان يتصرف كما هو متوقع.

من الممكن أن يكون لديك في ملف DLL الخاص بك معدل الوصول (للإعدادات 1. الإعدادات) مضبوطًا على داخلي (صديق لـ VB).حاول تغيير Access MOdifier إلى Public ومعرفة ما إذا كان ذلك يسمح لتطبيقك بقراءة/كتابة القيم من تكوين dll.

الجواب من هوارد يغطي النظرية.

إحدى الطرق السريعة والقذرة لحل هذه المشكلة هي تحليل ملف تكوين xml يدويًا.

    string configFile = Assembly.GetExecutingAssembly().Location + ".config";
    XDocument.Load(configFile).Root.Element("appSettings")....

الخطأ الذي أعتقد أنكم جميعًا ترتكبونه هو أنك تشير على ما يبدو إلى إعدادات DLL عبر Settings1.Default.IPAddress بينما من المفترض ببساطة أن تفعل هذا Settings1.IPAddress.

الفرق هو أنه عندما تستخدم Settings1.Default.IPAddress يتم الحصول على القيم من القيم المشفرة المضمنة في ملف التجميع (.dll أو .exe) كسمة [global::System.Configuration.DefaultSettingValueAttribute(...)].

بينما Settings1.IPAddress هي القيمة القابلة للتحرير في الملف .dll.config (ملف XML)**.لذا فإن أي تغييرات تجريها على ملف XML، لا تنعكس في القيمة الافتراضية المشفرة في التجميع.

ليس هذا:

IP = IPAddress.Parse(Settings1.Default.IPAddress);

لكن جرب هذا:

*IP = IPAddress.Parse(Settings1.IPAddress);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top