Team XSockets.NET

Custom PersistentProperty Module (Binary Serializer)

We recommend that you read the previous sections about Persistent Properties before reading this section.

In the previous sample we wrote a custom module for the PersistentProperty that stored the persistent properties to a Azure Storage Tables. Now we will show a sample using a Binary Serializer.

Considerations

Both the Azure sample and this sample will store property values and repopulate even if the server stops and then restarts. The big difference between the sample with Azure Storage Tables and binary serialization is that writing values to disk will be an issue if you ScaleOut servers. If using ScaleOut and Custom Property Storage you will either need a central storage (that all servers can access) or you will need sticky sessions.

Implement the PersistentPropertyStorage

There is a template for CustomPersistentPropertyStorage. Choose Add->NewItem and go to XSockets.NET 5

custom persistent property storage

This will give us something like

using System;
using System.Threading.Tasks;
using XSockets.Core.XSocket;

public class AzurePersistentPropertyStorage : PersistentPropertyStorage
{
    public override async Task ReadFromPropertyStorage<T>(T controller)
    {
        throw new NotImplementedException("Implement custom storage for property values");
    }

    public override async Task WriteToPropertyStorage<T>(T controller)
    {
        throw new NotImplementedException("Implement custom storage for property values");
    }
}

Reading/Writing to disk

The complete sample module looks like this.

using System;
using System.Threading.Tasks;
using XSockets.Core.XSocket;

public class FilePersistentPropertyStorage : PersistentPropertyStorage
{
    public override async Task ReadFromPropertyStorage<T>(T controller)
    {
        foreach (var pi in this.GetPersistentProperties(controller.GetType()))
        {
            pi.ReadProperty(controller);
        }
    }

    public override async Task WriteToPropertyStorage<T>(T controller)
    {
        foreach (var pi in this.GetPersistentProperties(controller.GetType()))
        {
            var v = pi.GetValue(controller, null);
            if (v == GetDefault(pi.PropertyType)) continue;

            pi.WriteProperty(v, controller);
        }
    }

    public static object GetDefault(Type type)
    {
        if (type.IsValueType)
        {
            return Activator.CreateInstance(type);
        }
        return null;
    }
}

Helpers

As you can see above that we call ReadProperty and WriteProperty for saving and retrieving entities (or persisted properties).

The helper class is pasted in below. Basically the helpers just serialize and deserialize properties to/from disk.

using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using XSockets.Core.Common.Socket;
using XSockets.Core.Common.Utility.Logging;
using XSockets.Plugin.Framework;

public static class StorageHelpers
{
    public const string storageFolder = "PropertyValues";
    private const string storagePath = storageFolder + "\\{0}.{1}.{2}.bin";

    static StorageHelpers()
    {
        if (!Directory.Exists(storageFolder))
            Directory.CreateDirectory(storageFolder);
    }

    public static void ReadProperty(this PropertyInfo pi, IXSocketController controller)
    {
        var uniqueName = string.Format(storagePath, controller.Alias, controller.PersistentId, pi.Name);
        if (!File.Exists(uniqueName)) return;

        using (var fs = new FileStream(uniqueName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
        {
            try
            {
                var formatter = new BinaryFormatter();
                pi.SetValue(controller, formatter.Deserialize(fs), null);
            }
            catch (SerializationException e)
            {
                Composable.GetExport<IXLogger>().Error(e, "Failed to deserialize. Reason: {e}" + e.Message);
            }

        }
    }

    public static void WriteProperty(this PropertyInfo pi, object o, IXSocketController controller)
    {
        var uniqueName = string.Format(storagePath, controller.Alias, controller.PersistentId, pi.Name);

        using (var fs = new FileStream(uniqueName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
        {            
            try
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(fs, o);
            }
            catch (SerializationException e)
            {
                Composable.GetExport<IXLogger>().Error(e, "Failed to deserialize. Reason: {e}" + e.Message);
            }
        }
    }
}

Test

So, if we repeat the Putty stuff from the Persistent Property Sample section you will see that values are written to disk at the specified location when the connection is closed. You will also get back the value from the Custom Storage when you reconnect

Binary Property Storage

Note: You can also see that subscriptions are persisted. So the server will remember the clients subscriptions between connections.

results matching ""

    No results matching ""