سؤال

كنت أخلق وحدة HTTP وبين تصحيح الأخطاء التي لاحظتها شيئا ما في البداية (على الأقل) على سلوك غريب.

عندما أقوم بتعيين نقطة توقف في الطريقة الأولية ل httpModule، أستطيع أن أرى أن طريقة IN INTION HTTT HTTP تسمى عدة مرات على الرغم من أنني قد بدأت فقط في موقع الويب الخاص بتصحيح الأخطاء وتقديم طلب واحد (أحيانا يكون هناك وقت واحد فقط وأوقات أخرى تصل إلى 10 مرات).

أعلم أنه يجب أن أتوقع أن يتم تشغيل العديد من مثيلات httpapplication ولكل وحدة HTTP، ولكن عندما أطلب صفحة واحدة يجب التعامل معها بواسطة كائن تطبيق HTTP واحد، وبالتالي فقط أطلق النار على الأحداث المرتبطة مرة واحدة فقط، ولكن لا يزال يحرر الأحداث عدة مرات لكل طلب لا معنى له - بخلاف أنه يجب أن تضاف عدة مرات داخل هذا httpapplication - مما يعني أنها نفس طريقة HTTPModule التي يتم استدعاؤها في كل مرة وليس تطبيق HTTP جديد يتم إنشاؤها في كل مرة يضرب نقطة انقطاع (انظر مثال التعليمات البرمجية في الأسفل إلخ).

ماذا يمكن أن يكون خطأ هنا؟ هل أنا لأنني أخطب وضبط نقطة توقف في وحدة HTTP؟

لقد لاحظ أنه يبدو أنه إذا قمت بتشغيل موقع الويب الخاص بتصحيح الأخطاء والخطوة بسرعة عبر نقطة توقف في جهاز HttpModule، فلن تضغط إلا على طريقة INIT واحدة مرة واحدة وينطبق الشيء نفسه على eventhandler. إذا دعها بدلا من ذلك، يمكنك تعليقها عند نقطة توقف لبضع ثوان، وتسمى طريقة INITION عدة مرات (تبدو وكأنها تعتمد على المدة التي تنتظرها قبل أن تنتظر قبل انتهاء النقاط). ربما يمكن أن يكون هذا بعض المبنى في ميزة للتأكد من تهيئة httpmodule ويمكن أن يخدم تطبيق HTTP طلبات، ولكن يبدو أيضا أن شيئا يمكن أن يكون له عواقب وخيمة.

قد يبدو هذا منطقي، لأنه قد يحاول إنهاء الطلب وبما أنني قمت بتعيين نقطة الاستراحة، فهذا يفكر في أن هناك خطأ في الخطأ ومحاولة استدعاء طريقة INITE مرة أخرى؟ سو يمكن التعامل مع الطلب؟

ولكن هل هذا ما يحدث وهو كل شيء على ما يرام (أنا مجرد التخمين)، أم أنها مشكلة حقيقية؟

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

هذا السلوك يمكن أن يحقق بسرعة أي موقع لأسفل.

لقد بحثت في كود .NET الأصلي المستخدم المستخدمة ل httpModules لأشكالها و rolemanagermodule وغيرها ولكن التعليمات البرمجية الخاصة بي لا يختلف عن استخدام هذه الوحدات.

رمز بلدي يشبه هذا.

    public void Init(HttpApplication app)
    {
        if (CommunityAuthenticationIntegration.IsEnabled)
        {
            FormsAuthenticationModule formsAuthModule = (FormsAuthenticationModule) app.Modules["FormsAuthentication"];         

            formsAuthModule.Authenticate += new FormsAuthenticationEventHandler(this.OnAuthenticate);
        }
    }

فيما يلي مثال كيف يتم ذلك في Rolemangermodule من Framework .NET

    public void Init(HttpApplication app)
    {
        if (Roles.Enabled)
        {
            app.PostAuthenticateRequest += new EventHandler(this.OnEnter);
            app.EndRequest += new EventHandler(this.OnLeave);
        }
    }

هل يعرف أحد ما الذي يحدث؟

(آمل فقط أن يخبرني شخص ما السبب في أن هذا يحدث وأؤكد لي أن كل شيء بخير تماما) :)


تحديث:

لقد حاولت تضييق المشكلة وحتى الآن وجدت أن طريقة التفسير التي يتم استدعاؤها هي دائما على كائن جديد من وحدة HTTP (Contary إلى ما اعتقدت عليه من قبل).

يبدو أنه بالنسبة للطلب الأول (عند بدء تشغيل الموقع) جميع كائنات httpapplication التي يتم إنشاؤها وحجزها جميعها تحاول خدمة الطلب الأول وبالتالي تضرب كل شيء من EventHandler الذي يتم إضافته. لا أستطيع معرفة حقا لماذا يحدث هذا.

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

ولكن يبدو أيضا أنه إذا عدت بعد ذلك إلى الصفحة الأولى (أو واحدة أخرى) سيبدأ تشغيل httpapplication واحد فقط في الاعتناء بالطلب وكل شيء كما هو متوقع - طالما أنا لا أتركه يتعطل في نقطة انقطاع.

إذا سمحت بذلك في نقطة توقف، فستبدأ في إنشاء كائنات Httpapplication جديدة وتبدأ في إضافة جهاز httpapplications (أكثر من 1) لخدمة / التعامل مع الطلب (الذي يعمل بالفعل من خلال خدمته بواسطة httpapplication الذي يتوقف حاليا عند نقطة التوقف) وبعد

أعتقد أو آمل أن يكون الأمر ذكيا "وراء الكواليس" طريقة للمساعدة في توزيع الحمل و / أو الأخطاء. ولكن ليس لدي أدنى فكرة. آمل أن يكون هناك شخص ما يمكن أن أؤكد لي أنه جيد تماما وكيف من المفترض أن يكون؟

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

المحلول

  1. فحص HTTPCONTEXT.CURRENT.REQUEST لمعرفة، لأي تأييد يتم إطلاق الأزمة الوحدة. يمكن أن يكون متصفح إرسال طلب متعدد.

  2. إذا كنت متصلا ب IIS، فقم بفحص سجلات IIS لمعرفة ما إذا كان يتم استلام أي طلب في الوقت الذي تقيم فيه في نقطة انقطاع.

نصائح أخرى

من الطبيعي أن تسمى طريقة INIT () عدة مرات. عند بدء تشغيل التطبيق، ستقوم عملية ASP.NET Worker بإنشاء مثيل لأن العديد من كائنات httpapplication حيث تعتقد أنها تحتاجها، ثم سوف تجمعها (على سبيل المثال. إعادة استخدامها لطلبات جديدة، مشابهة تجمع اتصال قاعدة البيانات).

الآن لكل كائن httpapplication، ستقوم أيضا بإنشاء نسخة واحدة من كل IHTTPModule مسجلة واستدعاء طريقة INIT هذه عدة مرات. لذلك إذا تم إنشاء 5 كائنات httpapplication، فسيتم إنشاء 5 نسخ من IHTTPModule الخاص بك، وتسمى طريقة INIT الخاصة بك 5 مرات. منطقي؟

الآن لماذا تنفس إنشاء 5 كائنات httpapplications؟ حسنا، ربما تحتوي صفحة ASPX الخاصة بك على روابط إلى موارد أخرى سيحاول متصفحك التنزيل، CSS، JavaScript، Webresource.aspx، ربما IFRAME في مكان ما. أو ربما تكون عملية عامل ASP.NET في الحالة المزاجية لبدء تشغيل أكثر من 1 كائن httpapplication، فهذا هو حقا تفاصيل داخلية / تحسين عملية ASP.NET قيد التشغيل ضمن IIS (أو VS Build In WebServer).

إذا كنت تريد رمز مضمون لتشغيل مرة واحدة فقط (ولا تريد استخدام حدث Application_Startup في Global.asax)، فيمكنك تجربة ما يلي في IHTTPModule الخاص بك:

private static bool HasAppStarted = false;
private readonly static object _syncObject = new object();

public void Init(HttpApplication context)
{
    if (!HasAppStarted)
    {
        lock (_syncObject)
        {
            if (!HasAppStarted)
            {
                // Run application StartUp code here

                HasAppStarted = true;
            }
        }
    }
}

لقد فعلت شيئا مشابها ويبدو أنه يعمل، على الرغم من أن أرحب بنود عملي في حالة فقدان شيئا ما.

هنا قليلا من التفسير فيما يتعلق بما يجب استخدامه، متى، وكيف يعملون.عند استخدام Application_Start VS INIT في Global.asax؟

تحرير: المزيد من القراءة

عمود ASP: وحدات HTTP

INFO: مثيلات التطبيقات، أحداث التطبيقات، ولاية التطبيق في ASP.NET

لفتح أعلاه أقفال IHTTPModule لجميع الطلبات، ثم، فهو Frezes التطبيق بأكمله. إذا طلبت مكالماتك IHTTPModule الخاصة بك عدة مرات، فمن الضروري استدعاء طريقة httpapplication completeerequest والتخلص من مثيل httpapplication من IHTTPModule في حدث الإنجاب من أجل إزالة مثيل httpapplication مثل هذا:

public class TestModule :IHttpModule
    {
        #region IHttpModule Members

        public void Dispose()
        {

        }

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(context_BeginRequest);
            context.EndRequest += new EventHandler(context_EndRequest);
        }

        void context_EndRequest(object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;
            app.CompleteRequest();
            app.Dispose();
        }

        void context_BeginRequest(object sender, EventArgs e)
        {
            //your code here
        }

        #endregion
    }

إذا كنت في حاجة إلى طلبات IHTTPModule في كل مرة بدون rerequest على إعادة النشر، استخدم هذا الرمز أعلاه.

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