سؤال

لقد قمت بإنشاء خدمة Windows التي ستتم الاتصال ببعض مكونات COM، لذلك قمت بمعالجة [Stathread] إلى الوظيفة الرئيسية. ومع ذلك، عند حرائق الموقت، فإنها تقارير MTA وتفشل مكالمات COM. كيف يمكنني اصلاح هذا؟

using System;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
using System.Timers;



namespace MyMonitorService
{
    public class MyMonitor : ServiceBase
    {
        #region Members
        private System.Timers.Timer timer = new System.Timers.Timer();
        #endregion

        #region Construction
        public MyMonitor ()
        {
            this.timer.Interval = 10000; // set for 10 seconds
            this.timer.Elapsed += new System.Timers.ElapsedEventHandler(this.timer_Elapsed);
        }
        #endregion

        private void timer_Elapsed (object sender, ElapsedEventArgs e)
        {
            EventLog.WriteEntry("MyMonitor", String.Format("Thread Model: {0}", Thread.CurrentThread.GetApartmentState().ToString()), EventLogEntryType.Information);
        }

        #region Service Start/Stop
        [STAThread]
        public static void Main ()
        {
            ServiceBase.Run(new MyMonitor());
        }

        protected override void OnStart (string[] args)
        {
            EventLog.WriteEntry("MyMonitor", "My Monitor Service Started", EventLogEntryType.Information);
            this.timer.Enabled = true;
        }

        protected override void OnStop ()
        {
            EventLog.WriteEntry("MyMonitor", "My Monitor Service Stopped", EventLogEntryType.Information);
            this.timer.Enabled = false;
        }
        #endregion
    }
}
هل كانت مفيدة؟

المحلول

يتم تشغيل الخدمات بنظام استضافة خدمة Windows، والذي يعمل باستخدام مؤشرات الترابط MTA. لا يمكنك التحكم في هذا. عليك إنشاء جديد خيط و تعيين apartmentstate لها إلى ستا, ، قم بعملك على هذا الموضوع.

إليك فئة تمتد ServiceBase التي تفعل هذا:

public partial class Service1 : ServiceBase
{
    private System.Timers.Timer timer;

    public Service1()
    {
        InitializeComponent();
        timer = new System.Timers.Timer();
        this.timer.Interval = 10000; // set for 10 seconds
        this.timer.Elapsed += new System.Timers.ElapsedEventHandler(Tick);
    }

    protected override void OnStart(string[] args)
    {
        timer.Start();
    }

    private void Tick(object sender, ElapsedEventArgs e)
    {
        // create a thread, give it the worker, let it go
        // is collected when done (not IDisposable)
        var thread = new Thread(WorkerMethod);
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
        OnStop(); // kill the timer
    }

    private void WorkerMethod(object state)
    {
        // do your work here in an STA thread
    }

    protected override void OnStop()
    {
        timer.Stop();
        timer.Dispose();
    }
}

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

في موقف مثل هذا، سأقوم بإنشاء عدد محدد من مؤشرات الترابط STA (ربما 2x عدد النوى للبدء مع) الذي يراقب قائمة انتظار آمنة للخيط لعناصر العمل. سيكون حدث التجزئة الموقت مسؤولا عن تحميل قائمة الانتظار مع العمل الذي يحتاج إلى القيام به.

كل هذا يتوقف على ما تقوم به فعلا كل عشر ثوان، سواء كان ينبغي إكماله في المرة التالية في المرة التالية، ما يجب القيام به في هذا الموقف، إلخ.

نصائح أخرى

وضع سمة Stathread لن تعمل على خدمة. لا يتم التعامل معها بنفس الطريقة كمحدث، لذلك سيتم تجاهل ذلك.

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

ومع ذلك، ستكون هناك مشكلة أخرى هنا - سيكون عليك إعادة صياغة الطريقة التي تعمل بها خدمتك. لا يمكنك فقط استخدام system.threading.timer. مثيل للتوقيت - يعمل على مؤشر ترابط منفصل، لن يكون Sta. عندما حرائق الحدث المنقضي، ستكون تعمل على موضوع مختلف وغير STA.

بدلا من القيام بعملك في حدث Timer، ربما ترغب في القيام بعملك الرئيسي في مؤشر الترابط الذي تنشئه صراحة. يمكنك الحصول على حدث إعادة تعيين في هذا الموضوع الذي يحظر، ولديه مؤقت "تعيين" للسماح بتشغيل منطقك في مؤشر ترابط STA.

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

النظر إلى مثال مماثل: http://www.aspfree.com/c/a/c-sharp/createing-a-windows-service-with-c-sharp-introduction/1/

ماذا لو كان لديك الرئيسية ...

    [STAThread]
    public static void Main ()
    {
        MyMonitor m = new MyMonitor();
        m.Start();
    }

وتحريك بداية الموقت / التوقف عن الأحداث ...

 public void Start() { this.timer.Enabled = true;}
 public void Stop() { this.timer.Enabled = false;}

  protected override void OnStart (string[] args)
    {
        EventLog.WriteEntry("MyMonitor", "My Monitor Service Started", EventLogEntryType.Information);
    }

    protected override void OnStop ()
    {
        EventLog.WriteEntry("MyMonitor", "My Monitor Service Stopped", EventLogEntryType.Information);
    }

هذه التقارير التي تستخدمها ستا. يعتمد على اقتراح الإرادة و http://en.csharp-online.net/createing_a_.net_windows_service٪E2٪80٪94alternative_1:_use_a_separate_thread.

using System;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;



namespace MyMonitorService
{
    internal class MyMonitorThreaded : ServiceBase
    {
        private Boolean bServiceStarted = false;
        private Thread threadWorker;

        private void WorkLoop ()
        {
            while (this.bServiceStarted)
            {
                EventLog.WriteEntry("MyMonitor", String.Format("Thread Model: {0}", Thread.CurrentThread.GetApartmentState().ToString()), EventLogEntryType.Information);

                if (this.bServiceStarted)
                    Thread.Sleep(new TimeSpan(0, 0, 10));
            }

            Thread.CurrentThread.Abort();
        }

        #region Service Start/Stop
        protected override void OnStart (String[] args)
        {
            this.threadWorker = new Thread(WorkLoop);
            this.threadWorker.SetApartmentState(ApartmentState.STA);
            this.bServiceStarted = true;
            this.threadWorker.Start();
        }

        protected override void OnStop ()
        {
            this.bServiceStarted = false;
            this.threadWorker.Join(new TimeSpan(0, 2, 0));
        }
        #endregion
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top