Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This article shows you how to upgrade your Windows Forms clipboard and drag-and-drop operations to the new type-safe APIs in .NET 10. You'll learn how to use the new Clipboard.TryGetData and Clipboard.SetDataAsJson<T>(String, T) methods, understand which built-in types work without changes, and discover strategies for handling custom types and legacy data after the removal of BinaryFormatter.
BinaryFormatter was removed from the runtime in .NET 9 because of security vulnerabilities. This change broke clipboard and drag-and-drop operations with custom objects. .NET 10 introduces new APIs that use JSON serialization and type-safe methods to restore this functionality, improve security, and provide better error handling and cross-process compatibility.
Clipboard.SetData(String, Object) no longer works with custom types that require BinaryFormatter for serialization. This method performs a copy operation (by default) that serializes data immediately, but that serialization now fails for types that need BinaryFormatter because it has been removed. Clipboard.GetData(String) is obsolete in .NET 10. When BinaryFormatter is required for deserialization but isn't enabled, GetData() returns a NotSupportedException instance. Use the new Clipboard.TryGetData and Clipboard.SetDataAsJson<T>(String, T) methods for type-safe operations and JSON serialization of custom objects.
The following sections provide detailed migration guidance, explain which types work without changes, and show how to handle both new development and legacy data scenarios.
Prerequisites
Before you continue, review these concepts:
- How applications used
BinaryFormatterin clipboard and drag-and-drop scenarios before .NET 9. - The security vulnerabilities that led to the removal of
BinaryFormatter. - How to work with
System.Text.Jsonserialization patterns and their limitations.
For more information, see these articles:
Breaking changes from BinaryFormatter removal
Removing BinaryFormatter in .NET 9 fundamentally changes how Windows Forms handles clipboard and drag-and-drop operations with custom types. These changes affect existing code patterns and require careful migration to maintain functionality.
Custom types no longer serialize automatically
In .NET 8 and earlier, you could place any serializable custom object on the clipboard by calling SetData(). The BinaryFormatter handled serialization automatically. Starting with .NET 9, SetData() still performs a copy operation that serializes data immediately, but this serialization fails for types that require BinaryFormatter because it has been removed.
The following code no longer works:
[Serializable]
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void BrokenCustomTypeExample()
{
// This worked in .NET 8 and earlier but silently fails starting with .NET 9
Person person = new Person { Name = "John", Age = 30 };
Clipboard.SetData("MyApp.Person", person); // No data is stored
// Later attempts to retrieve the data return a NotSupportedException instance
object data = Clipboard.GetData("MyApp.Person");
}
<Serializable>
Public Class Person
Public Property Name As String
Public Property Age As Integer
End Class
Public Shared Sub BrokenCustomTypeExample()
' This worked in .NET 8 and earlier but silently fails starting with .NET 9
Dim person As New Person With {.Name = "John", .Age = 30}
Clipboard.SetData("MyApp.Person", person) ' No data is stored
' Later attempts to retrieve the data return a NotSupportedException instance
Dim data As Object = Clipboard.GetData("MyApp.Person")
End Sub
What you might see
- The
SetData()method completes without throwing an exception. - The data is placed on the clipboard, but serialization fails for types that require
BinaryFormatter. - Later attempts to retrieve the data with
GetData()return a NotSupportedException instance that indicatesBinaryFormatteris required but not enabled.
Migration guidance
Use the new SetDataAsJson<T>() method or manually serialize to a string or byte[]. For details, see the Work with custom types section.
GetData() is obsolete - use TryGetData<T>() instead
The legacy GetData() method is obsolete in .NET 10. This method returns data successfully in most cases, but when BinaryFormatter is required for deserialization and isn't enabled, GetData() returns a NotSupportedException instance that indicates BinaryFormatter is needed. You should migrate to the new type-safe TryGetData<T>() methods for better error handling and type safety.
The following example shows the obsolete pattern you should avoid:
public static void ObsoleteGetDataExample()
{
// Don't use - GetData() is obsolete in .NET 10
object data = Clipboard.GetData("MyApp.Person"); // Obsolete method
// Returns a NotSupportedException instance for a custom object type
if (data is Person person)
{
Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}");
}
}
Public Shared Sub ObsoleteGetDataExample()
' Don't use - GetData() is obsolete in .NET 10
Dim data As Object = Clipboard.GetData("MyApp.Person") ' Obsolete method
' Returns a NotSupportedException instance for a custom object type
If TypeOf data Is Person Then
Dim person As Person = DirectCast(data, Person)
Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}")
End If
End Sub
Instead, use the modern type-safe approach with TryGetData<T>():
public static void ModernTryGetDataExample()
{
var data = new Person { Name = "Alice", Age = 28 };
Clipboard.SetDataAsJson("MyAppData", data);
// Use this - type-safe approach with TryGetData<T>()
if (Clipboard.TryGetData("MyApp.Person", out Person person))
{
// person is guaranteed to be the correct type
Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}");
}
else
{
// Handle the case where data isn't available or is the wrong type
MessageBox.Show("Unable to retrieve person data from clipboard");
}
}
Public Shared Sub ModernTryGetDataExample()
Dim data As New Person With {.Name = "Alice", .Age = 30}
Clipboard.SetDataAsJson("MyAppData", data)
' Use this - type-safe approach with TryGetData(Of T)()
Dim person As Person = Nothing
If Clipboard.TryGetData("MyApp.Person", person) Then
' person is guaranteed to be the correct type
Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}")
Else
' Handle the case where data isn't available or is the wrong type
MessageBox.Show("Unable to retrieve person data from clipboard")
End If
End Sub
Benefits of TryGetData<T>()
- Type safety: No need for casting—the method returns the exact type you request.
- Clear error handling: Returns a Boolean success indicator instead of using null or exception patterns.
- Future-proof: Designed to work with new serialization methods and legacy data support.
How to identify affected code
Look for:
- Any
GetData()calls, as the entire method is obsolete regardless of data type. DataObject.GetData()andIDataObject.GetData()usage in drag-and-drop operations.
Migration guidance
Replace all GetData() usage with type-safe TryGetData<T>() methods. For comprehensive examples of all overloads, see the New type-safe APIs section.
New type-safe APIs
.NET 10 introduces three new API families that provide type safety, better error handling, and JSON serialization support for clipboard and drag-and-drop operations:
- TryGetData methods for retrieving data
- SetDataAsJson<T>(String, T) methods for storing data
- ITypedDataObject interface for drag-and-drop operations
TryGetData<T>() methods
The TryGetData<T>() family replaces the obsolete GetData() method. It provides type-safe retrieval and clear success or failure indication for your clipboard operations.
Basic type-safe retrieval
public static void BasicTypeSafeRetrievalExamples()
{
// Retrieve text data using a standard format
if (Clipboard.TryGetData(DataFormats.Text, out string textData))
Console.WriteLine($"Text: {textData}");
// Retrieve an integer using a custom format
if (Clipboard.TryGetData("NumberData", out int numberData))
Console.WriteLine($"Number: {numberData}");
// Retrieve Unicode text using a standard format
if (Clipboard.TryGetData(DataFormats.UnicodeText, out string unicodeText))
Console.WriteLine($"Unicode: {unicodeText}");
// Retrieve raw text data with OLE conversion control
if (Clipboard.TryGetData(DataFormats.Text, out string rawText))
Console.WriteLine($"Raw: {rawText}");
// Retrieve file drops using a standard format
if (Clipboard.TryGetData(DataFormats.FileDrop, out string[] files))
Console.WriteLine($"Files: {string.Join(", ", files)}");
}
Public Shared Sub BasicTypeSafeRetrievalExamples()
' Retrieve text data using a standard format
Dim textData As String = Nothing
If Clipboard.TryGetData(DataFormats.Text, textData) Then
Console.WriteLine($"Text: {textData}")
End If
' Retrieve an integer using a custom format
Dim numberData As Integer
If Clipboard.TryGetData("NumberData", numberData) Then
Console.WriteLine($"Number: {numberData}")
End If
' Retrieve Unicode text using a standard format
Dim unicodeText As String = Nothing
If Clipboard.TryGetData(DataFormats.UnicodeText, unicodeText) Then
Console.WriteLine($"Unicode: {unicodeText}")
End If
' Retrieve raw text data with OLE conversion control
Dim rawText As String = Nothing
If Clipboard.TryGetData(DataFormats.Text, rawText) Then
Console.WriteLine($"Raw: {rawText}")
End If
' Retrieve file drops using a standard format
Dim files As String() = Nothing
If Clipboard.TryGetData(DataFormats.FileDrop, files) Then
Console.WriteLine($"Files: {String.Join(", ", files)}")
End If
End Sub
Custom JSON types
public static void CustomJsonTypesExamples()
{
// Retrieve a custom type stored with SetDataAsJson<T>()
if (Clipboard.TryGetData("Person", out Person person))
Console.WriteLine($"Person: {person.Name}");
// Retrieve application-specific data formats
if (Clipboard.TryGetData("MyApp.Settings", out AppSettings settings))
Console.WriteLine($"Settings: {settings.Theme}");
// Retrieve complex custom objects
if (Clipboard.TryGetData("DocumentData", out DocumentInfo doc))
Console.WriteLine($"Document: {doc.Title}");
}
Public Shared Sub CustomJsonTypesExamples()
' Retrieve a custom type stored with SetDataAsJson(Of T)()
Dim person As Person = Nothing
If Clipboard.TryGetData("Person", person) Then
Console.WriteLine($"Person: {person.Name}")
End If
' Retrieve application-specific data formats
Dim settings As AppSettings = Nothing
If Clipboard.TryGetData("MyApp.Settings", settings) Then
Console.WriteLine($"Settings: {settings.Theme}")
End If
' Retrieve complex custom objects
Dim doc As DocumentInfo = Nothing
If Clipboard.TryGetData("DocumentData", doc) Then
Console.WriteLine($"Document: {doc.Title}")
End If
End Sub
SetDataAsJson<T>() methods
These methods provide automatic JSON serialization using System.Text.Json with type-safe storage.
Specify a custom format
public static void CustomFormatExample()
{
var settings = new AppSettings { Theme = "Dark", AutoSave = true };
// Use a custom format for better organization
Clipboard.SetDataAsJson("MyApp.Settings", settings);
}
Public Shared Sub CustomFormatExample()
Dim settings As New AppSettings With {.Theme = "Dark", .AutoSave = True}
' Use a custom format for better organization
Clipboard.SetDataAsJson("MyApp.Settings", settings)
End Sub
Automatic format inference
By specifying the type name as the data format, TryGetData<T> can infer the format automatically:
public static void AutomaticFormatInferenceExample()
{
var person = new Person { Name = "Alice", Age = 25 };
// Use the type name as the format
Clipboard.SetDataAsJson(typeof(Person).FullName, person);
// Retrieve the data and infer the format automatically
if (Clipboard.TryGetData(out Person retrievedPerson))
{
Console.WriteLine($"Retrieved: {retrievedPerson.Name}");
}
}
Public Shared Sub AutomaticFormatInferenceExample()
Dim person As New Person With {.Name = "Alice", .Age = 25}
' Use the type name as the format
Clipboard.SetDataAsJson(GetType(Person).FullName, person)
' Retrieve the data and infer the format automatically
Dim retrievedPerson As Person = Nothing
If Clipboard.TryGetData(retrievedPerson) Then
Console.WriteLine($"Retrieved: {retrievedPerson.Name}")
End If
End Sub
ITypedDataObject interface
The ITypedDataObject interface enables type-safe drag-and-drop operations by extending IDataObject with typed methods.
Starting with .NET 10, DataObject (a common type in drag-and-drop scenarios) implements ITypedDataObject.
Use ITypedDataObject in drag-and-drop scenarios
private void OnDragDrop(object sender, DragEventArgs e)
{
if (e.Data is ITypedDataObject typedData)
{
// Retrieve files from drag data using a standard format
if (typedData.TryGetData(DataFormats.FileDrop, out string[] files))
Console.WriteLine($"Dropped files: {string.Join(", ", files)}");
// Retrieve text using a standard format
if (typedData.TryGetData(DataFormats.Text, out string text))
Console.WriteLine($"Dropped text: {text}");
// Retrieve custom items using an application-specific format
if (typedData.TryGetData("CustomItem", out MyItem item))
Console.WriteLine($"Dropped custom item: {item.Name} = {item.Value}");
}
}
Private Sub OnDragDrop(sender As Object, e As DragEventArgs)
If TypeOf e.Data Is ITypedDataObject Then
Dim typedData As ITypedDataObject = CType(e.Data, ITypedDataObject)
' Retrieve files from drag data using a standard format
Dim files As String() = Nothing
If typedData.TryGetData(DataFormats.FileDrop, files) Then
Console.WriteLine($"Dropped files: {String.Join(", ", files)}")
End If
' Retrieve text using a standard format
Dim text As String = Nothing
If typedData.TryGetData(DataFormats.Text, text) Then
Console.WriteLine($"Dropped text: {text}")
End If
' Retrieve custom items using an application-specific format
Dim item As MyItem = Nothing
If typedData.TryGetData("CustomItem", item) Then
Console.WriteLine($"Dropped custom item: {item.Name} = {item.Value}")
End If
End If
End Sub
Types that don't require JSON serialization
Many built-in .NET types work with clipboard operations without requiring JSON serialization or BinaryFormatter support. These types automatically serialize into the .NET Remoting Binary Format (NRBF), which provides efficient storage and maintains type safety.
These types use NRBF, the same efficient binary format used by the legacy BinaryFormatter. NRBF serialization provides these key benefits:
- Compact binary representation: Enables efficient storage and transfer.
- Built-in type information: Preserves exact .NET types during round-trip operations.
- Cross-process compatibility: Works between different .NET applications.
- Automatic serialization: Types serialize without custom code.
Note
Methods like SetData() perform a copy operation that serializes data immediately, ensuring clipboard data persists even after the current process exits. If you use the DataObject type directly with SetDataObject(dataObject, copy), you can control when serialization occurs. Setting the copy parameter to true (the default) forces immediate serialization, while false defers serialization until needed. With copy set to false and the data is retrieved in the same process, serialization may not be necessary, but data won't persist after the process exits.
For technical details, see the .NET Remoting Binary Format specification.
Classes that support NRBF-encoded data are implemented in the System.Formats.Nrbf namespace.
Type safety guarantees
Windows Forms provides several safety mechanisms for these built-in types:
- Exact type matching. TryGetData returns only the requested type.
- Automatic validation. Windows Forms validates type compatibility during deserialization.
- No arbitrary code execution. Unlike custom types with BinaryFormatter, these types can't execute malicious code.
- Content validation required. You must still validate data content and ranges for your application logic.
- No size constraints. Large arrays or bitmaps aren't automatically limited. Monitor memory usage.
Supported primitive types
The following primitive types work seamlessly with clipboard and DataObject operations. You don't need custom serialization or configuration. The clipboard system automatically handles these built-in .NET types:
bool,byte,char,decimal,double,short,int, andlong.sbyte,ushort,uint,ulong,float, andstring.TimeSpanandDateTime.
The following examples show how these primitive types work directly with SetData() and TryGetData<T>() methods:
public static void PrimitiveTypesExample()
{
// Numeric types
Clipboard.SetData("MyInt", 42);
Clipboard.SetData("MyDouble", 3.14159);
Clipboard.SetData("MyDecimal", 123.45m);
// Text and character types
Clipboard.SetData("MyString", "Hello World");
Clipboard.SetData("MyChar", 'A');
// Boolean and date/time types
Clipboard.SetData("MyBool", true);
Clipboard.SetData("MyDateTime", DateTime.Now);
Clipboard.SetData("MyTimeSpan", TimeSpan.FromMinutes(30));
// Later retrieval with type safety
if (Clipboard.TryGetData("MyTimeSpan", out TimeSpan value))
{
Console.WriteLine($"Clipboard value is: {value}");
}
}
Public Shared Sub PrimitiveTypesExample()
' Numeric types
Clipboard.SetData("MyInt", 42)
Clipboard.SetData("MyDouble", 3.14159)
Clipboard.SetData("MyDecimal", 123.45D)
' Text and character types
Clipboard.SetData("MyString", "Hello World")
Clipboard.SetData("MyChar", "A"c)
' Boolean and date/time types
Clipboard.SetData("MyBool", True)
Clipboard.SetData("MyDateTime", DateTime.Now)
Clipboard.SetData("MyTimeSpan", TimeSpan.FromMinutes(30))
' Later retrieval with type safety
Dim value As TimeSpan
If Clipboard.TryGetData("MyTimeSpan", value) Then
Console.WriteLine($"Clipboard value is: {value}")
End If
End Sub
Collections of primitive types
Arrays and generic lists of supported primitive types work without extra configuration. However, keep these limitations in mind:
- All array and list elements must be supported primitive types.
- Avoid
string[]andList<string>because NRBF format has complexity handling null values in string collections. - Store strings individually or use JSON serialization for string collections.
The following examples show how arrays and lists can be set on the clipboard:
public static void CollectionsExample()
{
// Arrays of primitive types
int[] numbers = { 1, 2, 3, 4, 5 };
Clipboard.SetData("NumberArray", numbers);
double[] coordinates = { 1.0, 2.5, 3.7 };
Clipboard.SetData("Coordinates", coordinates);
// Generic lists
List<int> intList = new List<int> { 10, 20, 30 };
Clipboard.SetData("IntList", intList);
// Retrieval maintains type safety
if (Clipboard.TryGetData("NumberArray", out int[] retrievedNumbers))
{
Console.WriteLine($"Numbers: {string.Join(", ", retrievedNumbers)}");
}
}
Public Shared Sub CollectionsExample()
' Arrays of primitive types
Dim numbers As Integer() = {1, 2, 3, 4, 5}
Clipboard.SetData("NumberArray", numbers)
Dim coordinates As Double() = {1.0, 2.5, 3.7}
Clipboard.SetData("Coordinates", coordinates)
' Generic lists
Dim intList As New List(Of Integer) From {10, 20, 30}
Clipboard.SetData("IntList", intList)
' Retrieval maintains type safety
Dim retrievedNumbers As Integer() = Nothing
If Clipboard.TryGetData("NumberArray", retrievedNumbers) Then
Console.WriteLine($"Numbers: {String.Join(", ", retrievedNumbers)}")
End If
End Sub
System.Drawing types
Common graphics types from the System.Drawing namespace work seamlessly with clipboard and DataObject operations. These types are useful for applications that work with visual elements and need to transfer drawing-related data between components or applications. Be aware that serializing a Bitmap can consume a large amount of memory, especially for large images. The following types are supported:
Point,PointF,Rectangle,RectangleF.Size,SizeF,Color.Bitmap(can consume significant memory when serialized).
The following examples show how these graphics types can be used with clipboard operations:
public static void SystemDrawingTypesExample()
{
// Geometric types
Point location = new Point(100, 200);
Rectangle bounds = new Rectangle(0, 0, 500, 300);
Size dimensions = new Size(800, 600);
Clipboard.SetData("Location", location);
Clipboard.SetData("Bounds", bounds);
Clipboard.SetData("Size", dimensions);
// Color information
Color backgroundColor = Color.FromArgb(255, 128, 64, 192);
Clipboard.SetData("BackColor", backgroundColor);
// Bitmap data (use with caution for large images)
Bitmap smallIcon = new Bitmap(16, 16);
Clipboard.SetData("Icon", smallIcon);
}
Public Shared Sub SystemDrawingTypesExample()
' Geometric types
Dim location As New Point(100, 200)
Dim bounds As New Rectangle(0, 0, 500, 300)
Dim dimensions As New Size(800, 600)
Clipboard.SetData("Location", location)
Clipboard.SetData("Bounds", bounds)
Clipboard.SetData("Size", dimensions)
' Color information
Dim backgroundColor As Color = Color.FromArgb(255, 128, 64, 192)
Clipboard.SetData("BackColor", backgroundColor)
' Bitmap data (use with caution for large images)
Dim smallIcon As New Bitmap(16, 16)
Clipboard.SetData("Icon", smallIcon)
End Sub
Work with custom types
When you use SetDataAsJson<T>(String, T) and TryGetData with custom types, System.Text.Json handles serialization automatically. Many types work without any special configuration—records, simple classes, and structs with public properties serialize seamlessly.
Simple types that work without attributes
Most straightforward custom types don't require special configuration:
// Records work without any attributes.
public record PersonInfo(string Name, int Age, string Email);
// Simple classes serialize all public properties automatically.
public class DocumentMetadata
{
public string Title { get; set; }
public DateTime Created { get; set; }
public string Author { get; set; }
}
// Structs with public properties work seamlessly.
public struct Point3D
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
}
' Simple classes serialize all public properties automatically.
Public Class DocumentMetadata
Public Property Title As String
Public Property Created As DateTime
Public Property Author As String
End Class
' Structs with public properties work seamlessly.
Public Structure Point3D
Public Property X As Double
Public Property Y As Double
Public Property Z As Double
End Structure
Use JSON attributes for advanced control
Use System.Text.Json attributes only when you need to customize serialization behavior. For comprehensive guidance on System.Text.Json serialization, attributes, and advanced configuration options, see JSON serialization and deserialization in .NET.
The following example shows how you can use JSON attributes to control serialization:
public class ClipboardFriendlyType
{
// Include a field that normally isn't serialized
[JsonInclude]
private int _privateData;
// Public properties are always serialized
public string Name { get; set; }
// Exclude sensitive or non-essential data
[JsonIgnore]
public string InternalId { get; set; }
// Handle property name differences for compatibility
[JsonPropertyName("display_text")]
public string DisplayText { get; set; }
// Control null value handling
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string OptionalField { get; set; }
}
Public Class ClipboardFriendlyType
' Include a field that normally isn't serialized
<JsonInclude>
Private _privateData As Integer
' Public properties are always serialized
Public Property Name As String
' Exclude sensitive or non-essential data
<JsonIgnore>
Public Property InternalId As String
' Handle property name differences for compatibility
<JsonPropertyName("display_text")>
Public Property DisplayText As String
' Control null value handling
<JsonIgnore(Condition:=JsonIgnoreCondition.WhenWritingNull)>
Public Property OptionalField As String
End Class
Example: Clipboard operations with custom types
public static void CustomTypesClipboardOperationsExample()
{
var data = new ClipboardFriendlyType
{
Name = "Sample",
DisplayText = "Sample Display Text",
InternalId = "internal-123" // This property isn't serialized due to [JsonIgnore]
};
Clipboard.SetDataAsJson("MyAppData", data);
if (Clipboard.TryGetData("MyAppData", out ClipboardFriendlyType retrieved))
{
Console.WriteLine($"Retrieved: {retrieved.Name}");
// retrieved.InternalId is null because of [JsonIgnore]
}
}
Public Shared Sub CustomTypesClipboardOperationsExample()
Dim data As New ClipboardFriendlyType With {
.Name = "Sample",
.DisplayText = "Sample Display Text",
.InternalId = "internal-123" ' This property isn't serialized due to <JsonIgnore>
}
Clipboard.SetDataAsJson("MyAppData", data)
Dim retrieved As ClipboardFriendlyType = Nothing
If Clipboard.TryGetData("MyAppData", retrieved) Then
Console.WriteLine($"Retrieved: {retrieved.Name}")
' retrieved.InternalId is null because of <JsonIgnore>
End If
End Sub
Enable BinaryFormatter support (not recommended)
Caution
BinaryFormatter support is not recommended. Use it only as a temporary migration bridge for legacy applications that can't immediately migrate to the new type-safe APIs.
If you must continue using BinaryFormatter for clipboard operations in .NET 10, enable limited support through explicit configuration. This approach carries significant security risks and requires several steps.
For complete step-by-step instructions, see Enable BinaryFormatter clipboard support (not recommended). For general migration guidance, see the BinaryFormatter migration guide.
Security warnings and risks
BinaryFormatter is inherently insecure and deprecated for these reasons:
- Arbitrary code execution vulnerabilities: Attackers can execute malicious code during deserialization, exposing your application to remote attacks.
- Denial of service attacks: Malicious clipboard data can consume excessive memory or CPU resources, causing crashes or instability.
- Information disclosure risks: Attackers might extract sensitive data from memory.
- No security boundaries: The format is fundamentally unsafe, and configuration settings can't secure it.
Only enable this support as a temporary bridge while you update your application to use the new type-safe APIs.
For detailed security guidelines and configuration steps, see Security warnings and risks in the how-to guide.
Implement security-focused type resolvers
Even with BinaryFormatter enabled, you must implement type resolvers to restrict deserialization to explicitly approved types. Follow these guidelines:
- Use explicit allow-lists. Reject any type not explicitly approved.
- Validate type names. Ensure type names exactly match expected values.
- Limit to essential types. Include only types required for your clipboard functionality.
- Throw exceptions for unknown types. Clearly reject unauthorized types.
- Review regularly. Audit and update the allowed list as needed.
For complete implementation examples and code samples, see Implement security-focused type resolvers in the how-to guide.
Use AI to migrate clipboard code
Migrating clipboard operations from .NET 8 to .NET 10 involves systematic code changes across multiple files and classes. AI tools like GitHub Copilot can help accelerate your migration by identifying legacy patterns, suggesting modern replacements, and creating test scenarios. Instead of manually searching through your codebase and converting each clipboard operation individually, you can use AI to handle repetitive tasks while you focus on validating results and handling edge cases.
The following sections show specific prompt strategies for different aspects of clipboard migration, from finding problematic code patterns to creating robust JSON-serializable types and comprehensive test suites.
Use AI to identify legacy clipboard patterns
Use Copilot to scan your codebase and locate clipboard operations that need migration. This helps you understand the scope of changes required before starting the actual migration work.
Find all clipboard operations in my codebase that use GetData(), SetData() with custom objects, DataObject.GetData(), or IDataObject.GetData(). Show me the file paths and line numbers where these patterns occur.
Copilot is powered by AI, so surprises and mistakes are possible. For more information, see Copilot general use FAQs.
Use AI to convert GetData() to TryGetData<T>()
Use Copilot to convert obsolete GetData() calls to the new type-safe TryGetData<T>() pattern. This conversion includes proper error handling and eliminates unsafe casting.
Convert this GetData() clipboard code to use the new TryGetData<T>() method with proper error handling:
[paste your existing GetData() code here]
Make sure to eliminate casting and add appropriate error handling for when the data isn't available.
Copilot is powered by AI, so surprises and mistakes are possible. For more information, see Copilot general use FAQs.
Use AI to migrate SetData() to SetDataAsJson<T>()
Use Copilot to convert custom object storage from the obsolete SetData() method to the new SetDataAsJson<T>() approach. This ensures your custom objects are properly serialized to the clipboard.
Take this SetData() clipboard code that stores custom objects:
[paste your existing SetData() code here]
Convert it to use SetDataAsJson<T>() and make the custom types JSON-serializable. Add any necessary System.Text.Json attributes if the types have complex properties.
Copilot is powered by AI, so surprises and mistakes are possible. For more information, see Copilot general use FAQs.
Use AI to create JSON-serializable data models
Use Copilot to design custom types that work seamlessly with SetDataAsJson<T>() and TryGetData<T>(). This includes adding appropriate attributes for properties that need special handling.
Create a JSON-serializable version of this class for clipboard operations:
[paste your existing class definition here]
Make it work with System.Text.Json, add JsonIgnore for sensitive properties, JsonInclude for private fields that should serialize, and JsonPropertyName for any properties that need different names in JSON.
Copilot is powered by AI, so surprises and mistakes are possible. For more information, see Copilot general use FAQs.
Use AI to generate type-safe wrapper methods
Use Copilot to create wrapper methods that encapsulate the new clipboard APIs and provide clean interfaces for your application's specific data types.
Create a type-safe clipboard wrapper class that provides methods for storing and retrieving these custom types:
[list your custom types here]
Use SetDataAsJson<T>() and TryGetData<T>() internally, include proper error handling, and add methods like SavePersonToClipboard() and TryGetPersonFromClipboard().
Copilot is powered by AI, so surprises and mistakes are possible. For more information, see Copilot general use FAQs.
Use AI to create comprehensive tests
Use Copilot to generate test suites that verify your clipboard migration works correctly, including round-trip serialization tests and error handling scenarios.
Generate comprehensive unit tests for this clipboard code:
[paste your migrated clipboard code here]
Include tests for successful round-trip serialization, handling of null values, error cases when data isn't available, and verification that the migrated code produces the same results as the original for valid scenarios.
Copilot is powered by AI, so surprises and mistakes are possible. For more information, see Copilot general use FAQs.
Use AI to validate migration results
Use Copilot to review your migrated code and identify potential issues or areas where the migration might not be complete.
Review this migrated clipboard code for potential issues:
[paste your migrated code here]
Check for: missing error handling, types that might not serialize properly to JSON, performance concerns with large objects, security issues, and any remaining uses of obsolete methods.
Copilot is powered by AI, so surprises and mistakes are possible. For more information, see Copilot general use FAQs.
Related content
.NET Desktop feedback