New to Telerik UI for ASP.NET AJAXStart a free 30-day trial

Converting Filter States in RadPivotGrid with RadPersistenceManager After Security Update

Updated on Aug 14, 2025

Environment

VersionProductAuthor
2024.4.1114 and laterPivotGrid for Telerik UI for ASP.NET AJAXAttila Antal

Description

I need to update legacy filter states in RadPivotGrid because a security update in Telerik.Web.UI removed support for filters serialized using the unsafe .NET BinaryFormatter. Older persisted filter states fail to deserialize after the upgrade, resulting in errors. While manually removing old persisted values, reapplying filters, and saving works, I need a scalable solution for hundreds of saved views.

This knowledge base article also answers the following questions:

  • How can I convert persisted filter states in RadPivotGrid?
  • How do I handle filter serialization issues after upgrading Telerik.Web.UI?
  • What is the workaround for updating legacy filter states in RadPivotGrid?

Solution

To convert legacy filter states in RadPivotGrid to the new JSON-based format, use the following approach. This code handles scenarios where filter states are stored as strings or files.

The following example shows how to convert the persisted state from the old (ViewState) format to new (JSON) format:

C#
// The actual logic for converting the state
private string ConvertState(string oldState)
{
    XDocument doc = XDocument.Parse(oldState);

    XElement filterPersistenceElement = doc.Descendants("ControlSetting")
        .Where(setting => setting.Element("Name").Value == "FiltersPersistence").FirstOrDefault();

    if (filterPersistenceElement != null)
    {
        string[] oldFilterStates = filterPersistenceElement.Element("Value").Element("string").Value.Trim().Split(',');

        List<string> newFilterStates = new List<string>();

        foreach (string filterState in oldFilterStates)
        {
            string[] options = filterState.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);

            options[2] = SerializeObject(DeserializeObject(options[2]));

            newFilterStates.Add(string.Join(";", options));
        }

        filterPersistenceElement.Element("Value").Element("string").Value = string.Join(",", newFilterStates.ToArray());
    }

    return doc.ToString();
}

// Legacy code for deserializing the state
// WARNING: This method uses BinaryFormatter.Deserialize(), which is deprecated and insecure.
// Only use this on trusted data during migration. Do NOT use in production or with untrusted data.
// See: https://learn.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide
public static object DeserializeObject(string objectToDeserialize)
{
    byte[] unencodedArray = Convert.FromBase64String(objectToDeserialize);
    BinaryFormatter bf = new BinaryFormatter();
    using (MemoryStream ms = new MemoryStream(unencodedArray))
    {
        return bf.Deserialize(ms);
    }
}

// Current code for serializing the state
public static string SerializeObject(object objectToSerialize)
{
    var jsonString = JsonConvert.SerializeObject(objectToSerialize);
    byte[] bytes = Encoding.UTF8.GetBytes(jsonString);
    return Convert.ToBase64String(bytes);
}

You can create a few helper methods and plug-in the functions from above to handle different scenarios.

C#
// Update the state in files
private void UpdateStateInFile(string filePath)
{
    string oldState = GetFileContents(filePath);
    string newState = ConvertState(oldState);
    WriteFileContents(filePath, newState);
}

// Convert the old state from string to new state
private string GetConvertedState(string oldState)
{
    return ConvertState(oldState);
}

private string GetFileContents(string filePath)
{
    string contents;
    using (var stream = new FileStream(Server.MapPath(filePath), FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    using (var reader = new StreamReader(stream))
    {
        contents = reader.ReadToEnd();
    }
    return contents;
}

private void WriteFileContents(string filePath, string contents)
{
    using (var stream = new FileStream(Server.MapPath(filePath), FileMode.Create, FileAccess.Write, FileShare.Read))
    using (var writer = new StreamWriter(stream))
    {
        writer.Write(contents);
    }
}

See Also