Skip to content

Commit

Permalink
Update walkthrough to use JSON serialization instead of binary serial…
Browse files Browse the repository at this point in the history
…ization (#33276)
  • Loading branch information
gewarren committed Jan 4, 2023
1 parent 6071bb5 commit 73f343d
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 111 deletions.
Original file line number Diff line number Diff line change
@@ -1,101 +1,88 @@
---
title: "Walkthrough: Persisting an Object using C#"
description: This example creates a basic Loan object in C# and persist its data to a file, then creates a new object with data from the file.
ms.date: 04/26/2018
description: This example creates a basic Loan object in C# and persists its data to a file, then creates a new object with data from the file.
ms.date: 12/30/2022
---
# Walkthrough: Persisting an object using C\#
# Walkthrough: Persist an object using C\#

You can use binary serialization to persist an object's data between instances, which enables you to store values and retrieve them the next time that the object is instantiated.
You can use JSON serialization to persist an object's data between instances, which enables you to store values and retrieve them the next time that the object is instantiated.

In this walkthrough, you will create a basic `Loan` object and persist its data to a file. You will then retrieve the data from the file when you re-create the object.
In this walkthrough, you'll create a basic `Loan` object and persist its data to a JSON file. You'll then retrieve the data from the file when you re-create the object.

> [!IMPORTANT]
> This example creates a new file if the file does not already exist. If an application must create a file, that application must have `Create` permission for the folder. Permissions are set by using access control lists. If the file already exists, the application needs only `Write` permission, a lesser permission. Where possible, it's more secure to create the file during deployment and only grant `Read` permissions to a single file (instead of Create permissions for a folder). Also, it's more secure to write data to user folders than to the root folder or the Program Files folder.
> This example creates a new file if the file does not already exist. If an application must create a file, that application must have `Create` permission for the folder. Permissions are set by using access control lists. If the file already exists, the application needs only `Write` permission, a lesser permission. Where possible, it's more secure to create the file during deployment and only grant `Read` permissions to a single file (instead of `Create` permissions for a folder). Also, it's more secure to write data to user folders than to the root folder or the *Program Files* folder.
> [!IMPORTANT]
> This example stores data in a binary format file. These formats should not be used for sensitive data, such as passwords or credit-card information.
[!INCLUDE [binary-serialization-warning](~/includes/binary-serialization-warning.md)]
> This example stores data in a JSON file. You should not store sensitive data, such as passwords or credit-card information, in a JSON file.
## Prerequisites

- To build and run, install the [.NET SDK](https://dotnet.microsoft.com/download).

- Install your favorite code editor, if you haven't already.

> [!TIP]
> Need to install a code editor? Try [Visual Studio](https://visualstudio.com/downloads)!
> [!TIP]
> Need to install a code editor? Try [Visual Studio](https://visualstudio.com/downloads)!
You can examine the sample code online [at the .NET samples GitHub repository](https://github.com/dotnet/samples/tree/main/csharp/serialization).

## Create the loan object
## Define the loan type

The first step is to create a `Loan` class and a console application that uses the class:

1. Create a new application. Type `dotnet new console -o serialization` to
create a new console application in a subdirectory named `serialization`.
1. Create a new application. At a command prompt, enter `dotnet new console -o serialization` to create a new console application in a subdirectory named `serialization`.
1. Open the application in your editor, and add a new class named `Loan.cs`.
1. Add the following code to your `Loan` class:

[!code-csharp[Loan class definition](../../../../../samples/snippets/csharp/serialization/Loan.cs#1)]
[!code-csharp[Loan class definition](../../../../../samples/snippets/csharp/serialization/Loan.cs#1)]

You'll also have to create an application that uses the `Loan` class.
## Instantiate a loan object

## Serialize the loan object
1. Open *Program.cs* and add the following code:

1. Open `Program.cs`. Add the following code:
[!code-csharp[Create a loan object](../../../../../samples/snippets/csharp/serialization/Program.cs#1)]

[!code-csharp[Create a loan object](../../../../../samples/snippets/csharp/serialization/Program.cs#1)]
2. Add an event handler for the `PropertyChanged` event, and a few lines to modify the `Loan` object and display the changes. You can see the additions in the following code:

Add an event handler for the `PropertyChanged` event, and a few lines to modify the `Loan` object and display the changes. You can see the additions in the following code:
[!code-csharp[Listening for the PropertyChanged event](../../../../../samples/snippets/csharp/serialization/Program.cs#2)]

[!code-csharp[Listening for the PropertyChanged event](../../../../../samples/snippets/csharp/serialization/Program.cs#2)]

At this point, you can run the code, and see the current output:
At this point, you can run the code and see the current output:

```console
New customer value: Henry Clay
7.5
7.1
```

Running this application repeatedly always writes the same values. A new `Loan` object is created every time you run the program. In the real world, interest rates change periodically, but not necessarily every time that the application is run. Serialization code means you preserve the most recent interest rate between instances of the application. In the next step, you will do just that by adding serialization to the `Loan` class.

## Using Serialization to Persist the Object

In order to persist the values for the Loan class using binary serialization, you must first mark the class with the `Serializable` attribute. Add the following code above the `Loan` class definition:

[!code-csharp[Loan class definition](../../../../../samples/snippets/csharp/serialization/Loan.cs#2)]

The <xref:System.SerializableAttribute> tells the compiler that everything in the class can be persisted to a file using binary serialization. Because the `PropertyChanged` event does not represent part of the object graph that should be stored, it should not be serialized. Doing so would serialize all objects that are attached to that event. You can add the <xref:System.NonSerializedAttribute> to the field declaration for the `PropertyChanged` event handler.
Running this application repeatedly always writes the same values. A new `Loan` object is created every time you run the program. In the real world, interest rates change periodically, but not necessarily every time that the application is run. Serialization code means you preserve the most recent interest rate between instances of the application. In the next step, you'll do just that by adding serialization to the `Loan` class.

[!code-csharp[Disable serialization for the event handler](../../../../../samples/snippets/csharp/serialization/Loan.cs#3)]
## Use serialization to persist the object

You can attach attributes to the backing field of an auto-implemented property using the `field` target value. The following code adds a `TimeLastLoaded` property and marks it as not serializable:
To serialize an object using <xref:System.Text.Json?displayProperty=fullName> serialization, you don't need to add any special attributes to the type. By default, all public properties are serialized and all fields are ignored. However, you can annotate properties to ignore or specify that fields should be included.

[!code-csharp[Disable serialization for an auto-implemented property](../../../../../samples/snippets/csharp/serialization/Loan.cs#4)]
The following code adds a `TimeLastLoaded` property and marks it with the <xref:System.Text.Json.Serialization.JsonIgnoreAttribute> attribute to exclude it from serialization:

The next step is to add the serialization code to the LoanApp application. In order to serialize the class and write it to a file, you use the <xref:System.IO> and <xref:System.Runtime.Serialization.Formatters.Binary> namespaces. To avoid typing the fully qualified names, you can add references to the necessary namespaces as shown in the following code:
[!code-csharp[Disable serialization for an auto-implemented property](../../../../../samples/snippets/csharp/serialization/Loan.cs#2)]

[!code-csharp[Adding namespaces for serialization](../../../../../samples/snippets/csharp/serialization/Program.cs#3)]
1. To serialize the class and write it to a file, you use the <xref:System.IO?displayProperty=fullName> and <xref:System.Text.Json?displayProperty=fullName> namespaces. To avoid typing the fully qualified names, you can add references to the necessary namespaces as shown in the following code:

The next step is to add code to deserialize the object from the file when the object is created. Add a constant to the class for the serialized data's file name as shown in the following code:
[!code-csharp[Adding namespaces for serialization](../../../../../samples/snippets/csharp/serialization/Program.cs#3)]

[!code-csharp[Define the name of the saved file](../../../../../samples/snippets/csharp/serialization/Program.cs#4)]
2. Add code to deserialize the object from the file when the object is created. Add a constant to the class for the serialized data's file name as shown in the following code:

Next, add the following code after the line that creates the `TestLoan` object:
[!code-csharp[Define the name of the saved file](../../../../../samples/snippets/csharp/serialization/Program.cs#4)]

[!code-csharp[Read from a file if it exists](../../../../../samples/snippets/csharp/serialization/Program.cs#5)]
Next, add the following code after the line that creates the `TestLoan` object. This code first checks that the file exists. If it exists, it reads the text from the file, and then deserialize it using the <xref:System.Text.Json.JsonSerializer.Deserialize%60%601(System.String,System.Text.Json.JsonSerializerOptions)?displayProperty=nameWithType> method.

You first must check that the file exists. If it exists, create a <xref:System.IO.Stream> class to read the binary file and a <xref:System.Runtime.Serialization.Formatters.Binary.BinaryFormatter> class to translate the file. You also need to convert from the stream type to the Loan object type.
[!code-csharp[Read from a file if it exists](../../../../../samples/snippets/csharp/serialization/Program.cs#5)]

Next you must add code to serialize the class to a file. Add the following code after the existing code in the `Main` method:
3. Next, add code to serialize the class to a file using the <xref:System.Text.Json.JsonSerializer.Serialize%60%601(%60%600,System.Text.Json.JsonSerializerOptions)?displayProperty=nameWithType> method. Add the following code to the end of the file:

[!code-csharp[Save the existing Loan object](../../../../../samples/snippets/csharp/serialization/Program.cs#6)]
[!code-csharp[Save the existing Loan object](../../../../../samples/snippets/csharp/serialization/Program.cs#6)]

At this point, you can again build and run the application. The first time it runs, notice that the interest rates starts at 7.5, and then changes to 7.1. Close the application and then run it again. Now, the application prints the message that it has read the saved file, and the interest rate is 7.1 even before the code that changes it.

## See also

- [Serialization (C#)](index.md)
- [C# Programming Guide](../../index.md)
- [How to serialize and deserialize JSON in .NET](../../../../standard/serialization/system-text-json/how-to.md)
38 changes: 15 additions & 23 deletions samples/snippets/csharp/serialization/Loan.cs
Original file line number Diff line number Diff line change
@@ -1,52 +1,44 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.ComponentModel;
using System.Text.Json.Serialization;

namespace serialization
{
// <Snippet2>
[Serializable()]
// </Snippet2>
// <Snippet1>
public class Loan : INotifyPropertyChanged
public class Loan : INotifyPropertyChanged
{
public double LoanAmount { get; set; }
public double InterestRatePercent { get; set; }
public double InterestRate { get; set; }

// <Snippet4>
[field:NonSerialized()]
// <Snippet2>
[JsonIgnore]
public DateTime TimeLastLoaded { get; set; }
// </Snippet4>
// </Snippet2>

public int Term { get; set; }

private string customer;
private string _customer;
public string Customer
{
get { return customer; }
get { return _customer; }
set
{
customer = value;
_customer = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(Customer)));
}
}

// <Snippet3>
[field: NonSerialized()]
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
// </Snippet3>
public event PropertyChangedEventHandler? PropertyChanged;

public Loan(double loanAmount,
double interestRate,
int term,
string customer)
{
this.LoanAmount = loanAmount;
this.InterestRatePercent = interestRate;
this.Term = term;
this.customer = customer;
LoanAmount = loanAmount;
InterestRate = interestRate;
Term = term;
_customer = customer;
}
}
// </Snippet1>
Expand Down
70 changes: 29 additions & 41 deletions samples/snippets/csharp/serialization/Program.cs
Original file line number Diff line number Diff line change
@@ -1,50 +1,38 @@
using System;
using serialization;
// <Snippet3>
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text.Json;
// </Snippet3>

namespace serialization
{
class Program
{
static void Main(string[] args)
{
// <Snippet4>
const string FileName = @"../../../SavedLoan.bin";
// </Snippet4>
// <Snippet4>
const string fileName = @"../../../SavedLoan.json";
// </Snippet4>

// <Snippet1>
Loan TestLoan = new Loan(10000.0, 7.5, 36, "Neil Black");
// </Snippet1>
// <Snippet1>
Loan testLoan = new(10_000.0, 7.5, 36, "Neil Black");
// </Snippet1>

// <Snippet5>
if (File.Exists(FileName))
{
Console.WriteLine("Reading saved file");
Stream openFileStream = File.OpenRead(FileName);
BinaryFormatter deserializer = new BinaryFormatter();
TestLoan = (Loan)deserializer.Deserialize(openFileStream);
TestLoan.TimeLastLoaded = DateTime.Now;
openFileStream.Close();
}
// </Snippet5>
// <Snippet5>
if (File.Exists(fileName))
{
Console.WriteLine("Reading saved file");
string jsonFromFile = File.ReadAllText(fileName);
testLoan = JsonSerializer.Deserialize<Loan>(jsonFromFile);
testLoan.TimeLastLoaded = DateTime.Now;
}
// </Snippet5>

// <Snippet2>
TestLoan.PropertyChanged += (_, __) => Console.WriteLine($"New customer value: {TestLoan.Customer}");
// <Snippet2>
testLoan.PropertyChanged += (_, __) => Console.WriteLine($"New customer value: {testLoan.Customer}");

TestLoan.Customer = "Henry Clay";
Console.WriteLine(TestLoan.InterestRatePercent);
TestLoan.InterestRatePercent = 7.1;
Console.WriteLine(TestLoan.InterestRatePercent);
// </Snippet2>
testLoan.Customer = "Henry Clay";
Console.WriteLine(testLoan.InterestRate);
testLoan.InterestRate = 7.1;
Console.WriteLine(testLoan.InterestRate);
// </Snippet2>

// <Snippet6>
Stream SaveFileStream = File.Create(FileName);
BinaryFormatter serializer = new BinaryFormatter();
serializer.Serialize(SaveFileStream, TestLoan);
SaveFileStream.Close();
// </Snippet6>
}
}
}
// <Snippet6>
// Serialize it.
string json = JsonSerializer.Serialize(testLoan);
File.WriteAllText(fileName, json);
// </Snippet6>
Binary file removed samples/snippets/csharp/serialization/SavedLoan.bin
Binary file not shown.
5 changes: 3 additions & 2 deletions samples/snippets/csharp/serialization/serialization.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>7.3</LangVersion>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>

0 comments on commit 73f343d

Please sign in to comment.