Friday, November 30, 2007

Dispatcher versus SynchronizationContext

Today I had the pleasure of playing with the Dispatcher and SynchronizationContext classes. I found that the Dispatcher class is useful when your sure that you are calling within the context of the user interface thread and the SynchronizationContext is useful when you're not quite sure.

If you obtain your Dispatcher class using the static Dispatcher.CurrentDispatcher method on some non-UI thread and call the BeginInvoke method, nothing will happen (No exception, no warning, nada). However, if you obtain your SynchronizationContext class via the static SynchronizationContext.Current method, it will return null if the thread is not a UI thread. This feedback is extremely useful since it allows you to react to both a UI thread and a non-UI thread accordingly.

Here is an example using the Dispatcher class:


using System;
using System.Threading;
using System.Windows.Threading; // WindowsBase.dll

namespace Test
{
public delegate void WriteTextDelegate(string message);

public class DispatcherTest
{
public void Start()
{
// Calling thread determines Dispatcher
m_Dispatcher = Dispatcher.CurrentDispatcher;

if (m_Timer == null)
m_Timer = new Timer(new TimerCallback(WriteText),
null, 1000, 2000);
else m_Timer.Change(1000, 2000);
}

public void Stop()
{
if (m_Timer != null)
m_Timer.Change(Timeout.Infinite, Timeout.Infinite);
}

public event WriteTextDelegate Message;

private Timer m_Timer;
private System.Windows.Threading.Dispatcher m_Dispatcher;

private void WriteText(object state)
{
m_Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
new WriteTextDelegate(OnMessage),
DateTime.Now.ToString());
}

private void OnMessage(string message)
{
if (Message != null)
Message(message);
}
}
}



Here is an example using the SynchronizationContext class:

using System;
using System.Threading;

namespace Test
{
public delegate void WriteSomeTextDelegate(string message);

public class SyncTest
{
public void Start()
{
// Calling thread determines SynchronizationContext
m_Context = SynchronizationContext.Current;

if (m_Timer == null)
m_Timer = new Timer(new TimerCallback(WriteText),
null, 1000, 2000);
else m_Timer.Change(1000, 2000);
}

public void Stop()
{
if (m_Timer != null)
m_Timer.Change(Timeout.Infinite, Timeout.Infinite);
}

public event WriteSomeTextDelegate Message;

private System.Threading.Timer m_Timer;
private System.Threading.SynchronizationContext m_Context;

private void WriteText(object state)
{
string message = DateTime.Now.ToString();

if (m_Context != null)
{
m_Context.Post(new SendOrPostCallback(PostCallback), message);
}
else OnMessage(message); // non-UI thread called Start
}

private void OnMessage(string message)
{
if (Message != null)
Message(message);
}

private void PostCallback(object state)
{
if (state is string)
{
OnMessage(state as string);
}
else throw new ArgumentException("State should be a string");

}
}
}


Notes:
  • I used Reflector to look inside the WindowsBase.dll; however, I had problems finding the dll. I expected to find it in a directory below the usual location (C:\ Windows\ Microsoft.NET\ Framework\ v3.0); however, it was in this directory: C:\ Program Files\ Reference Assemblies\ Microsoft\ Framework\ v3.0
  • WCF: Asynchronous Operations

Friday, November 9, 2007

WCF Security Exception: Timestamp is invalid because its creation time is in the future

Well, I ran into a real fun bug today that surfaced itself on the user's computer as a "Security Exception see Inner Exception". Upon examining the inner exception, it told me that the message was incorrectly secured. After placing some tracing on the server, I found this error message:

The security timestamp is invalid because its creation time ('11/9/2007 10:37:07 PM') is in the future. Current time is '11/9/2007 10:28:52 PM' and allowed clock skew is '00:05:00'.

After fixing the user's clock, which was roughly 8 minutes fast, everything worked great. The next question is "How do I increase the maximum skew time"? It took a bit of searching to figure out that I need to create a custom binding to change the values. Here is an example of how to do it:

<bindings>
<customBinding>
<binding name="MaxClockSkewBinding">
<textMessageEncoding />
<security authenticationMode="Kerberos">
<localClientSettings maxClockSkew="00:07:00" />
<localServiceSettings maxClockSkew="00:07:00" />

<secureConversationBootstrap />
</security>
<httpTransport />
</binding>
</customBinding>
</bindings>

For more information, see How To: Set a Max Clock Skew on MSDN.


More References: