Weak reference to delegate, never do it

In previous post I explained how I modified the Broker class to store WeakReference to Action<Message<T>> delegate to avoid the broker preventing garbage collection of the subscribers. This is a strong requirement, an object register an handler to the broker, but it does not want to share the same lifecycle of the broker because it is singleton. After this modification I have a strange bug, the program works, but after some minutes messages stops flowing, I scratched my head and then understand that this is normal, because my code that uses a WeakReference to an even is flawed. If you do not understand where the error is, think with care what is happening under the hood.

When an object registers a message listener to the broker, he passes a Action<Message<T>> object, and this object is stored by the broker with a WeakReference. The problem is that an Action<T> is a class that inherits from Multicast Delegate, thus is a real object, that as shown in Figure 1 keeps a reference to the target object that contains the method to be called.

image

Figure 1: The implementation of Delegate object taken from Reflector.

Now let’s look again at the code needed to register a message listener to the broker (line 3).

   1: public Test(Broker broker)

   2: {    

   3:      broker.RegisterForMessage<String>(this, t => ExecuteMessage(t));

   4: }

If you think carefully, this test creates a delegate, pass that delegate to the broker and the brokers stores a WeakReference on it to send message (Figure 2).

image

Figure 2: The broker stores a WeakReference to delegate in a Registration object, but this is the only reference to the Delegate object.

The problem is that delegate is referenced only by a WeakDelegate and since no other object have a reference to it, it will be collected by the garbage collector after some time. To verify this problem we can change the code that register for message a little bit.

   1: public Test(Broker broker)

   2: {

   3:    Registration = broker.RegisterForMessage<String>(ExecuteMessage);

   4: }

   5:  

   6: public Broker.Registration Registration { get; set; }

   7:  

   8: private void ExecuteMessage(Message<string> obj)

   9: {

  10:     Interlocked.Increment(ref CallCount);

  11: }

The only difference is that the caller stores a reference to the Registration object returned from the RegisterForMessage method, the broker creates a registration object and store a WeakReference on it (Figure 3). This reference now keeps the delegate alive.

image

Figure 3: Now the object stores a reference to the registration object, and the broker a WeakReference to the same object

This is the original desired situation, until Object is alive, it takes a reference to the registration object, that keeps the delegate and the object alive. When the object is not references by any other root, except from the delegate, the garbage collector verify that the registration/delegate and object could be collected, because Broker has only a WeakReference to the Registration object.

This solution is not perfect, because if “object” forgot to keep references to Registration object, it will cease to receive message at the first passage of the garbage collector. A possible solution is using reflection to call instance methods.

   1: public class WeakRegistration : ActionRegistrationBase

   2: {

   3:     private WeakReference<Object> Target { get; set; }

   4:  

   5:     private MethodInfo MethodInfo { get; set; }

   6:  

   7:     public WeakRegistration(object target, MethodInfo methodInfo)

   8:         : base(null)

   9:     {

  10:         Target = new WeakReference<object>(target);

  11:         MethodInfo = methodInfo;

  12:     }

  13:  

  14:     public override void Execute<T>(Message<T> message)

  15:     {

  16:         Object target = Target.Target;

  17:         if (target != null)

  18:         {

  19:             MethodInfo.Invoke(target, new object[] { message });

  20:         }

  21:     }

  22:  

  23:     public override bool IsAlive

  24:     {

  25:         get { return Target.IsAlive; }

  26:     }

  27: }

There is no secret here, I pass target object and a method info to the constructor and then use Methodinfo.Invoke to call the handler method through reflection. This technique can be used only if the caller pass a call to an instance method, as done in this snippet.

   1: public Test(Broker broker)

   2: {

   3:     broker.RegisterForMessage<String>(this, t => ExecuteMessage(t));

   4: }

   5:  

   6: private void ExecuteMessage(Message<string> obj)

   7: {

   8:     Interlocked.Increment(ref CallCount);

   9: }

As you can see I’m passing to RegisterForMessage both the object (this) and a lambda that calls the method, here is the implementation of this new version of RegisterForMessage.

   1: public void RegisterForMessage<T>(Object target, Expression<Action<Message<T>>> action)

   2: {

   3:     if (action.Body is MethodCallExpression)

   4:     {

   5:         MethodCallExpression mex = (MethodCallExpression)action.Body;

   6:         if (target != null && mex.Method.DeclaringType == target.GetType())

   7:         {

   8:             WeakRegistration registration = new WeakRegistration(target, mex.Method);

   9:             RegisterForMessage<T>(null, false, registration);

  10:             return;

  11:         }

  12:     }

  13:     Action<Message<T>> action1 = action.Compile();

  14:     RegisterForMessage<T>(null, false, new ActionRegistration(null, action1));

  15: }

This method accepts an Expression, and if the expression is a MethodCallExpression, we can use some Expression manipulation to extract the MethodInfo needed to create an instance of WeakRegistration class. If the Expression is not a methodCAllExpression defined on the same object passed as instance I can compile the expression and pass the compiled Action<Message<T>> to the standard ActionRegistration Object.

This is not a perfect solution, but if the caller restrict itself to register only instance method in the broker, we do not risk any leak.

Alk.

Changing app.config value at runtime

Sometimes there is the need to modify the value of some part of the configuration file of a .NET application at runtime, this is an example: I have a software that read some content from xml files, and have several paths listed in the AppSettings section of application configuration file.

During the very first run the software should extract xml data from a zip file to a directory chosen by the user, then the software should update all these settings to reflect this changes. Here is the code

   1: DirectoryInfo di = new DirectoryInfo(xmlFileLocation)

   2: Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

   3: foreach (KeyValueConfigurationElement setting in config.AppSettings.Settings)

   4: {

   5:    if (setting.Key.StartsWith("docroot"))

   6:    {

   7:        setting.Value = di.FullName;

   8:    } 

   9: }

  10: config.Save(ConfigurationSaveMode.Modified);

  11: ConfigurationManager.RefreshSection("appSettings");

With this code I cycle to all path that begins with docroot, (there are many of them in app.config) and then change all of them pointing to the new folder, then save the application config again.

alk.

Error during clickonce deploy with mshtml – Strong name signature not valid for this assembly

To deploy application that use mshtml with clickonce, you need to be sure that microsoft.mshtml.dll is included in the setup of click once, or the application will not install if mshtml.dll is not present on the machine at the time of deploy. But if you include it sometimes clients are not able to install application due to the following error

Strong name signature not valid for this assembly Microsoft.mshtml.dll

this is due to the fact that you reference a partially signed version in your project. To solve this remove the reference to mshtml.dll and reference the dll in

C:\Program Files (x86)\Microsoft.NET\Primary Interop Assemblies\Microsoft.mshtml.dll

Remove the (x86) if you are on a 32 bit system. Now with the reference to this assembly be sure that is included in the clickonce application files and everything should now work.

alk.

Pass a serialized object in querystring with less chars

I’ve some legacy code where stuff have to be passed with querystring, because we need to issue Get request to the server, and I need to pass various set of parameters for some reporting functions, but those parameters have 20 field, and are somewhat used as a tree. I decided to serialize everything and pass the result with querystring using HttpUtility.UrlEncoding… the result was frustrating because the url are simply too long.

So I begin investigating on how to reduce data size of serialized object to be encoded with UrlEncode. This is the first solution

using (MemoryStream ms = new MemoryStream())
{
    BinaryFormatter f = new BinaryFormatter();
    f.Serialize(ms, param);
    serialized =HttpUtility.UrlEncode(ms.ToArray());
}

For a typical object it uses 3264 charachters.. ouch too much, so I try with compression

using (MemoryStream ms = new MemoryStream())
using (GZipStream gzstream = new GZipStream(ms, CompressionMode.Compress))
{
    BinaryFormatter f = new BinaryFormatter();
    f.Serialize(gzstream, param);
    gzstream.Flush();
    gzstream.Close();
    serialized = HttpUtility.UrlEncode(ms.ToArray());
}

With compression I decreased the size to 2204 chars, still too much but If I look at the output string it is a really mess of escaping chars. UrlEncoding is not so good in encoding binary stream, a better solution is Base64

using (MemoryStream ms = new MemoryStream())
using (GZipStream gzstream = new GZipStream(ms, CompressionMode.Compress))
{
    BinaryFormatter f = new BinaryFormatter();
    f.Serialize(gzstream, param);
    gzstream.Flush();
    gzstream.Close();
    serialized = HttpUtility.UrlEncode(Convert.ToBase64String(ms.ToArray()));
}

I gzipped the serialized stream, then convert in Base64 and finally encoded with UrlEncode, the result is 1402 chars, really better but I want a string less than 1000 chars if possible. Since I know that DataContractSerializer produces a very compact string, I simply used it with a little trick

using (StringWriter sw = new StringWriter())
{
    DataContractSerializer serializer = new DataContractSerializer(param.GetType());
    XmlWriterSettings settings = new XmlWriterSettings();
    settings.OmitXmlDeclaration = true;
    settings.Indent = true;
    settings.NewLineOnAttributes = true;
    using (XmlWriter writer = XmlWriter.Create(sw, settings))
    {
        serializer.WriteObject(writer, param);
    }
    using (MemoryStream ms = new MemoryStream())
    using (GZipStream gzstream = new GZipStream(ms, CompressionMode.Compress))
    {
        Byte[] allcontent = Encoding.UTF8.GetBytes(sw.ToString());
        gzstream.Write(allcontent, 0, allcontent.Length);
        gzstream.Flush();
        gzstream.Close();
        serialized = HttpUtility.UrlEncode(Convert.ToBase64String(ms.ToArray()));
    }
}

I use DataContractSerializer to have a xml serialized stream, then I encode in UTF8 with Gzip compression, and finally I convert to Base64 and UrlEncode it, the result is 948 chars :) quite good, because now I’m under 1000 chars, respect the first version with plain binary serialization that was 3264 chars.

Alk.

Tags: