Skip to content

Commit 3ab1832

Browse files
attilaantalCopilot
andauthored
Create pivotgrid-update-old-persisted-filter-states-after-security-up… (#713)
* Create pivotgrid-update-old-persisted-filter-states-after-security-update.md * Update knowledge-base/pivotgrid-update-old-persisted-filter-states-after-security-update.md Co-authored-by: Copilot <[email protected]> * Update knowledge-base/pivotgrid-update-old-persisted-filter-states-after-security-update.md Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]>
1 parent 4890b3f commit 3ab1832

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
---
2+
title: Converting Filter States in RadPivotGrid with RadPersistenceManager After Security Update
3+
description: Learn how to update RadPivotGrid filter states stored by RadPersistenceManager after a recent security update in Telerik.Web.UI.
4+
type: how-to
5+
page_title: How to Update RadPivotGrid Filter States in RadPersistenceManager
6+
meta_title: How to Update RadPivotGrid Filter States in RadPersistenceManager
7+
slug: pivotgrid-update-old-persisted-filter-states-after-security-update
8+
tags: persistenceframework, ui-for-asp.net-ajax, radpivotgrid, radpersistencemanager, filters-persistence, filter-states
9+
ticketid: 1694223
10+
res_type: kb
11+
---
12+
13+
## Environment
14+
15+
| Version | Product | Author |
16+
| --- | --- | ---- |
17+
| 2024.4.1114 | PivotGrid for Telerik UI for ASP.NET AJAX | [Attila Antal](https://github.com/attilaantal)|
18+
19+
## Description
20+
21+
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.
22+
23+
This knowledge base article also answers the following questions:
24+
25+
- How can I convert persisted filter states in `RadPivotGrid`?
26+
- How do I handle filter serialization issues after upgrading Telerik.Web.UI?
27+
- What is the workaround for updating legacy filter states in `RadPivotGrid`?
28+
29+
30+
## Solution
31+
32+
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.
33+
34+
The following example shows how to convert the persisted state:
35+
36+
````C#
37+
// The actual logic for converting the state
38+
private string ConvertState(string oldState)
39+
{
40+
XDocument doc = XDocument.Parse(oldState);
41+
42+
XElement filterPersistenceElement = doc.Descendants("ControlSetting")
43+
.Where(setting => setting.Element("Name").Value == "FiltersPersistence").FirstOrDefault();
44+
45+
if (filterPersistenceElement != null)
46+
{
47+
string[] oldFilterStates = filterPersistenceElement.Element("Value").Element("string").Value.Trim().Split(',');
48+
49+
List<string> newFilterStates = new List<string>();
50+
51+
foreach (string filterState in oldFilterStates)
52+
{
53+
string[] options = filterState.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
54+
55+
options[2] = SerializeObject(DeserializeObject(options[2]));
56+
57+
newFilterStates.Add(string.Join(";", options));
58+
}
59+
60+
filterPersistenceElement.Element("Value").Element("string").Value = string.Join(",", newFilterStates.ToArray());
61+
}
62+
63+
return doc.ToString();
64+
}
65+
66+
// Legacy code for deserializing the state
67+
// WARNING: This method uses BinaryFormatter.Deserialize(), which is deprecated and insecure.
68+
// Only use this on trusted data during migration. Do NOT use in production or with untrusted data.
69+
// See: https://learn.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide
70+
public static object DeserializeObject(string objectToDeserialize)
71+
{
72+
byte[] unencodedArray = Convert.FromBase64String(objectToDeserialize);
73+
BinaryFormatter bf = new BinaryFormatter();
74+
using (MemoryStream ms = new MemoryStream(unencodedArray))
75+
{
76+
return bf.Deserialize(ms);
77+
}
78+
}
79+
80+
// Current code for serializing the state
81+
public static string SerializeObject(object objectToSerialize)
82+
{
83+
var jsonString = JsonConvert.SerializeObject(objectToSerialize);
84+
byte[] bytes = Encoding.UTF8.GetBytes(jsonString);
85+
return Convert.ToBase64String(bytes);
86+
}
87+
````
88+
````VB.NET
89+
'The actual logic for converting the state
90+
Private Function ConvertState(oldState As String) As String
91+
Dim doc As XDocument = XDocument.Parse(oldState)
92+
93+
Dim filterPersistenceElement As XElement = doc.Descendants("ControlSetting") _
94+
.Where(Function(setting) setting.Element("Name").Value = "FiltersPersistence") _
95+
.FirstOrDefault()
96+
97+
If filterPersistenceElement IsNot Nothing Then
98+
Dim oldFilterStates As String() = filterPersistenceElement.Element("Value").Element("string").Value.Trim().Split(","c)
99+
100+
Dim newFilterStates As New List(Of String)()
101+
102+
For Each filterState As String In oldFilterStates
103+
Dim options As String() = filterState.Split(New String() {";"}, StringSplitOptions.RemoveEmptyEntries)
104+
105+
options(2) = SerializeObject(DeserializeObject(options(2)))
106+
107+
newFilterStates.Add(String.Join(";", options))
108+
Next
109+
110+
filterPersistenceElement.Element("Value").Element("string").Value = String.Join(",", newFilterStates.ToArray())
111+
End If
112+
113+
Return doc.ToString()
114+
End Function
115+
116+
' Legacy code for deserializing the state
117+
Public Shared Function DeserializeObject(objectToDeserialize As String) As Object
118+
Dim unencodedArray As Byte() = Convert.FromBase64String(objectToDeserialize)
119+
Dim bf As New BinaryFormatter()
120+
Using ms As New MemoryStream(unencodedArray)
121+
Return bf.Deserialize(ms)
122+
End Using
123+
End Function
124+
125+
' Current code for serializing the state
126+
Public Shared Function SerializeObject(objectToSerialize As Object) As String
127+
Dim jsonString As String = JsonConvert.SerializeObject(objectToSerialize)
128+
Dim bytes As Byte() = Encoding.UTF8.GetBytes(jsonString)
129+
Return Convert.ToBase64String(bytes)
130+
End Function
131+
````
132+
133+
You can create a few helper methods and plug-in the functions from above to handle different scenarios.
134+
135+
````C#
136+
// Update the state in files
137+
private void UpdateStateInFile(string filePath)
138+
{
139+
string oldState = GetFileContents(filePath);
140+
string newState = ConvertState(oldState);
141+
WriteFileContents(filePath, newState);
142+
}
143+
144+
// Convert the old state from string to new state
145+
private string GetConvertedState(string oldState)
146+
{
147+
return ConvertState(oldState);
148+
}
149+
150+
private string GetFileContents(string filePath)
151+
{
152+
string contents;
153+
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
154+
using (var reader = new StreamReader(stream))
155+
{
156+
contents = reader.ReadToEnd();
157+
}
158+
return contents;
159+
}
160+
161+
private void WriteFileContents(string filePath, string contents)
162+
{
163+
using (var stream = new FileStream(Server.MapPath(filePath), FileMode.Create, FileAccess.Write, FileShare.Read))
164+
using (var writer = new StreamWriter(stream))
165+
{
166+
writer.Write(contents);
167+
}
168+
}
169+
````
170+
````VB.NET
171+
'Update the state in files
172+
Private Sub UpdateStateInFile(filePath As String)
173+
Dim oldState As String = GetFileContents(filePath)
174+
Dim newState As String = ConvertState(oldState)
175+
WriteFileContents(filePath, newState)
176+
End Sub
177+
178+
'Convert the old state from string to new state
179+
Private Function GetConvertedState(oldState As String) As String
180+
Return ConvertState(oldState)
181+
End Function
182+
183+
Private Function GetFileContents(filePath As String) As String
184+
Dim contents As String
185+
Using stream As New FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
186+
Using reader As New StreamReader(stream)
187+
contents = reader.ReadToEnd()
188+
End Using
189+
End Using
190+
Return contents
191+
End Function
192+
193+
Private Sub WriteFileContents(filePath As String, contents As String)
194+
Using stream As New FileStream(Server.MapPath(filePath), FileMode.Create, FileAccess.Write, FileShare.Read)
195+
Using writer As New StreamWriter(stream)
196+
writer.Write(contents)
197+
End Using
198+
End Using
199+
End Sub
200+
````
201+
202+
203+
## See Also
204+
205+
* [Persisting PivotGrid Settings](https://demos.telerik.com/aspnet-ajax/pivotgrid/examples/applicationscenarios/persisting-radpivotgrid-settings/defaultcs.aspx)

0 commit comments

Comments
 (0)