Home

Castle Stronghold

Castle Project Forum Index Castle Project
Support forum
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

SynchronizeFacility available

 
Post new topic   Reply to topic    Castle Project Forum Index -> Facilities
View previous topic :: View next topic  
Author Message
cneuwirt



Joined: 24 Jun 2006
Posts: 5

PostPosted: Sun Apr 15, 2007 2:53 pm    Post subject: SynchronizeFacility available Reply with quote

I just committed a SynchronizeFacility which does the following

- Recognizes the implicit sync interface ISynchronizeInvoke and
coordinates it api. This eliminates the code pollution of having to
call InvokeRequired and pass a delegate to the currrent method.
The most common use is to prevent the dread thread access
violation which using WinForms, but works for any component
implementing the interface.

- Recognizes Control component implementation and installs a
custom activator to ensure that Controls are always created in
the context of the main ui thread. This is necessary since controls
in one thread cannot be added to controls in another.

- Integrates the .Net 2 SynchronizationContext support by allowing
attributes (or configuration) to specify the default SynchronizationContext
of a class with the opportunity to override the context on a per-method
basis. This works seamlessly with the BackgroundWorker component.

Any feedback is welcome and appreciated.

craig[/list][/list]
Back to top
View user's profile Send private message
idavis



Joined: 11 Jul 2007
Posts: 5

PostPosted: Wed Jul 11, 2007 1:23 pm    Post subject: Reply with quote

I have been trying to get just a simple example to run, but all attempts have failed. I have been trying to get a piece of code that queries a web page for the current time and updates a RichTextBox. It is just a toy app, but it simulates background updating. I have looked over the unit tests many times but I am still missing what exactly is needed to get this code to not throw an InvalidOperationException for cross thread calls. I have removed all Synchronization attributes as nothing I have tried has worked. Do you have any documentation on usages other than the unit tests?

Code:

namespace SafelyUpdatingWinForm {
    public partial class MainForm : Form {
        public MainForm() {
            InitializeComponent();

            Thread t = new Thread( new ThreadStart( UpdateTime ) );
            t.Start();
        }

        protected virtual void UpdateTime() {
            while ( true ) {
                string text = GetWebPage( "http://www.time.gov/timezone.cgi?Eastern/d/-5" );
                Regex regex = new Regex( @"<b>\d\d:\d\d:\d\d<br>" );
                Match match = regex.Match( text );
                string time = match.Value.TrimStart( "<b>".ToCharArray() ).TrimEnd( "<br>".ToCharArray() );
                richTextBox.Text = time;
                Thread.Sleep( 2000 );
            }
        }

        private static string GetWebPage( string page ) { ... }
}


TIA,

Ian
Back to top
View user's profile Send private message
cneuwirt



Joined: 24 Jun 2006
Posts: 5

PostPosted: Sat Jul 21, 2007 9:52 pm    Post subject: Synchronization issues Reply with quote

Assuming you registered the SafelyUpdatingWinForm with the container, your problem might be the fact that the UpdateTime is protected and thus not managed by the synchronization facility. Try making it public. I usually use interfaces for my views to hide the implementation details.

craig
Back to top
View user's profile Send private message
idavis



Joined: 11 Jul 2007
Posts: 5

PostPosted: Sat Jul 21, 2007 11:29 pm    Post subject: Reply with quote

Thanks. I will try this as soon as I get back on Monday. Have you considered creating a page for this facility on the http://wiki.castleproject.org/index.php/Facilities page?
Back to top
View user's profile Send private message
idavis



Joined: 11 Jul 2007
Posts: 5

PostPosted: Sun Jul 22, 2007 2:41 pm    Post subject: Reply with quote

Ok. I couldn't wait until Monday. I have it working now.
In Program.cs:

Code:

    internal static class Program {
        [STAThread]
        private static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault( false );

            WindsorContainer container = new WindsorContainer();
            container.AddFacility( "sync.facility", new SynchronizeFacility() );
            container.AddComponent( "mainform.form.class", typeof ( MainForm ) );

            Application.Run( container.Resolve( "mainform.form.class" ) as Form );
        }
    }


And then in MainForm.cs:
Code:

    [Synchronize()]
    public partial class MainForm : Form {
        private Thread updateLoop;
        private bool loop = true;
        private const int delay = 2000;

        public MainForm() {
            InitializeComponent();

            updateLoop = new Thread( new ThreadStart( UpdateLoop ) );
            updateLoop.Name = "UpdateLoop";
            updateLoop.Start();
        }

        public virtual void UpdateLoop() {
            while ( loop ) {
                UpdateTime();
                Thread.Sleep( delay );
            }
        }

        [Synchronize( typeof ( WindowsFormsSynchronizationContext ) )]
        protected virtual void UpdateTime() {
            string text = GetWebPage();
            Regex regex = new Regex( @"<b>\d\d:\d\d:\d\d<br>" );
            Match match = regex.Match( text );
            string time = match.Value.TrimStart( "<b>".ToCharArray() ).TrimEnd( "<br>".ToCharArray() );
            richTextBox.Text = string.Format( "{0}\t{1}", time, Thread.CurrentThread.Name );
        }

        private static string GetWebPage() {
            string url = "http://www.time.gov/timezone.cgi?Eastern/d/-5";
            HttpWebRequest webRequest = WebRequest.Create( url ) as HttpWebRequest;
            webRequest.Method = "GET";
            using (WebResponse webResponse = webRequest.GetResponse()) {
                using (StreamReader sr = new StreamReader( webResponse.GetResponseStream(), Encoding.UTF8 )) {
                    return sr.ReadToEnd();
                }
            }
        }

        protected override void OnClosing( CancelEventArgs e ) {
            loop = false;
            while ( updateLoop.IsAlive ) {}
            base.OnClosing( e );
        }
    }


One mistake I discovered is that I had synchronized the update loop - it is fun watching your app get stuck. Also, the code will work if the attributed method is public, protected, or protected internal. I added the current thread name to the time to show that we are not in the UpdateLoop thread.

Thanks a lot for the facility and your feedback.
Back to top
View user's profile Send private message
cneuwirt



Joined: 24 Jun 2006
Posts: 5

PostPosted: Wed Jul 25, 2007 9:40 pm    Post subject: Reply with quote

Yup, I need to add the documentation for SynchronizeFacility to the website.

As for your problem, you don't need to do the WindowsSynchronizationContext stuff. You can get the built-in support using without requiring explicit sync attributes. However, you're original code base had 1 small problem. You started the thread in the constructor (instead of the Load event) and the thread started running before your Application.Run completed. As a result, the ISynchornizeInvoke.Invoke was hopelessly blocked since the Windows Message Loop is needed to service the ISynchronizeInvoke.Invoke and that only starts when Application.Run completes. Simple fix, start thread in Load

Code:

   public partial class MainForm : Form
   {
      private Thread updateLoop;
      private bool loop = true;
      private const int delay = 2000;

      public MainForm()
      {
         InitializeComponent();
      }

      private void UpdateLoop()
      {
         while (loop)
         {
            UpdateTime();
            Thread.Sleep(delay);
         }
      }

      protected virtual void UpdateTime()
      {
         string text = GetWebPage();
         Regex regex = new Regex(@"<b>\d\d:\d\d:\d\d<br>");
         Match match = regex.Match(text);
         string time = match.Value.TrimStart("<b>".ToCharArray()).TrimEnd("<br>".ToCharArray());
         richTextBox.Text = string.Format("{0}\t{1}", time, Thread.CurrentThread.Name);
      }

      private static string GetWebPage()
      {
         string url = "http://www.time.gov/timezone.cgi?Eastern/d/-5";
         HttpWebRequest webRequest = WebRequest.Create(url) as HttpWebRequest;
         webRequest.Method = "GET";
         using (WebResponse webResponse = webRequest.GetResponse())
         {
            using (StreamReader sr = new StreamReader(webResponse.GetResponseStream(), Encoding.UTF8))
            {
               return sr.ReadToEnd();
            }
         }
      }

      protected override void OnClosing(CancelEventArgs e)
      {
         loop = false;
         while (updateLoop.IsAlive)
         {
         }
         base.OnClosing(e);
      }

      private void MainForm_Load(object sender, System.EventArgs e)
      {
         updateLoop = new Thread(new ThreadStart(UpdateLoop));
         updateLoop.Name = "UpdateLoop";
         updateLoop.Start();
      }
   }
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Castle Project Forum Index -> Facilities All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group