.NET 5부터 개체 BinaryFormatter 직렬화 또는 역직렬화가 발생하는 시기를 확인할 수 있는 기본 제공 EventSource 이 포함되어 있습니다. 앱은 EventListener 파생 형식을 사용하여 이러한 알림을 수신하고 기록할 수 있습니다.
이 기능은 SerializationBinder 또는 ISerializationSurrogate를 대체하지 않으며, 직렬화되거나 역직렬화되는 데이터를 수정하는 데 사용할 수 없습니다. 대신 이 이벤트 시스템은 직렬화 또는 역직렬화되는 형식에 대한 인사이트를 제공하기 위한 것입니다. 타사 라이브러리 코드에서 발생하는 호출 같이 BinaryFormatter 인프라에 대한 의도하지 않은 호출을 검색하는 데도 사용할 수 있습니다.
이벤트 설명
BinaryFormatter 이벤트 원본에는 잘 알려진 이름 System.Runtime.Serialization.Formatters.Binary.BinaryFormatterEventSource가 있습니다. 수신기는 6개의 이벤트를 구독할 수 있습니다.
SerializationStart 이벤트(id = 10)
BinaryFormatter.Serialize가 호출되고 직렬화 프로세스를 시작한 경우 발생합니다. 이 이벤트는 SerializationEnd 이벤트와 쌍을 이룹니다. 개체가 자체 직렬화 루틴 내에서 BinaryFormatter.Serialize를 호출하는 경우 SerializationStart 이벤트를 재귀적으로 호출할 수 있습니다.
이 이벤트에는 페이로드가 포함되지 않습니다.
SerializationEnd 이벤트(id = 11)
BinaryFormatter.Serialize가 작업을 완료했을 때 발생합니다. SerializationEnd의 각 항목은 짝이 없는 마지막 SerializationStart 이벤트의 완료를 나타냅니다.
이 이벤트에는 페이로드가 포함되지 않습니다.
SerializingObject 이벤트(id = 12)
BinaryFormatter.Serialize가 기본 형식이 아닌 형식을 직렬화하는 동안 발생합니다. BinaryFormatter 인프라는 string 및 int와 같은 특정 형식을 특수 처리하며, 이러한 형식이 발견될 때 이 이벤트를 발생시키지 않습니다. 이 이벤트는 사용자 정의 형식 및 BinaryFormatter가 고유하게 이해하지 못하는 다른 형식의 경우에 발생합니다.
이 이벤트는 SerializationStart 이벤트와 SerializationEnd 이벤트 사이에서 0번 이상 발생할 수 있습니다.
이 이벤트에는 인수가 하나 있는 페이로드가 포함되어 있습니다.
typeName(string): 직렬화되는 형식의 정규화된 어셈블리 이름(Type.AssemblyQualifiedName 참조)입니다.
DeserializationStart 이벤트(id = 20)
BinaryFormatter.Deserialize가 호출되고 역직렬화 프로세스를 시작한 경우 발생합니다. 이 이벤트는 DeserializationEnd 이벤트와 쌍을 이룹니다. 개체가 자체 역직렬화 루틴 내에서 BinaryFormatter.Deserialize를 호출하는 경우 DeserializationStart 이벤트를 재귀적으로 호출할 수 있습니다.
이 이벤트에는 페이로드가 포함되지 않습니다.
DeserializationEnd 이벤트(id = 21)
BinaryFormatter.Deserialize가 작업을 완료했을 때 발생합니다. DeserializationEnd의 각 항목은 짝이 없는 마지막 DeserializationStart 이벤트의 완료를 나타냅니다.
이 이벤트에는 페이로드가 포함되지 않습니다.
DeserializingObject 이벤트(id = 22)
BinaryFormatter.Deserialize가 기본 형식이 아닌 형식을 역직렬화하는 동안 발생합니다. BinaryFormatter 인프라는 string 및 int와 같은 특정 형식을 특수 처리하며, 이러한 형식이 발견될 때 이 이벤트를 발생시키지 않습니다. 이 이벤트는 사용자 정의 형식 및 BinaryFormatter가 고유하게 이해하지 못하는 다른 형식의 경우에 발생합니다.
이 이벤트는 DeserializationStart 이벤트와 DeserializationEnd 이벤트 사이에서 0번 이상 발생할 수 있습니다.
이 이벤트에는 인수가 하나 있는 페이로드가 포함되어 있습니다.
typeName(string): 역직렬화되는 형식의 정규화된 어셈블리 이름(Type.AssemblyQualifiedName 참조)입니다.
[고급] 알림 하위 집합 구독
알림 하위 집합만 구독하려는 수신기는 사용할 키워드를 선택할 수 있습니다.
Serialization=(EventKeywords)1:SerializationStart,SerializationEnd및SerializingObject이벤트를 발생시킵니다.Deserialization=(EventKeywords)2:DeserializationStart,DeserializationEnd및DeserializingObject이벤트를 발생시킵니다.
EventListener 등록 중에 키워드 필터를 제공하지 않으면 모든 이벤트가 발생합니다.
자세한 내용은 System.Diagnostics.Tracing.EventKeywords를 참조하세요.
예제 코드
코드는 다음과 같습니다.
System.Console에 쓰는EventListener파생 형식을 만듭니다.- 해당 수신기가
BinaryFormatter에서 생성된 알림을 구독합니다. BinaryFormatter를 사용하여 단순 개체 그래프를 직렬화 및 역직렬화합니다.- 발생한 이벤트를 분석합니다.
using System;
using System.Diagnostics.Tracing;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace BinaryFormatterEventSample
{
class Program
{
static EventListener? _globalListener = null;
static void Main(string[] args)
{
// First, set up the event listener.
// Note: We assign it to a static field so that it doesn't get GCed.
// We also provide a callback that subscribes this listener to all
// events produced by the well-known BinaryFormatter source.
_globalListener = new ConsoleEventListener();
_globalListener.EventSourceCreated += (sender, args) =>
{
if (args.EventSource?.Name ==
"System.Runtime.Serialization.Formatters.Binary.BinaryFormatterEventSource")
{
((EventListener?)sender)?
.EnableEvents(args.EventSource, EventLevel.LogAlways);
}
};
// Next, create the Person object and serialize it.
Person originalPerson = new Person()
{
FirstName = "Logan",
LastName = "Edwards",
FavoriteBook = new Book()
{
Title = "A Tale of Two Cities",
Author = "Charles Dickens",
Price = 10.25m
}
};
byte[] serializedPerson = SerializePerson(originalPerson);
// Finally, deserialize the Person object.
Person rehydratedPerson = DeserializePerson(serializedPerson);
Console.WriteLine
($"Rehydrated person {rehydratedPerson.FirstName} {rehydratedPerson.LastName}");
Console.Write
($"Favorite book: {rehydratedPerson.FavoriteBook?.Title} ");
Console.Write
($"by {rehydratedPerson.FavoriteBook?.Author}, ");
Console.WriteLine
($"list price {rehydratedPerson.FavoriteBook?.Price}");
}
private static byte[] SerializePerson(Person p)
{
MemoryStream memStream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
#pragma warning disable SYSLIB0011 // BinaryFormatter.Serialize is obsolete
formatter.Serialize(memStream, p);
#pragma warning restore SYSLIB0011
return memStream.ToArray();
}
private static Person DeserializePerson(byte[] serializedData)
{
MemoryStream memStream = new MemoryStream(serializedData);
BinaryFormatter formatter = new BinaryFormatter();
#pragma warning disable SYSLIB0011 // Danger: BinaryFormatter.Deserialize is insecure for untrusted input
return (Person)formatter.Deserialize(memStream);
#pragma warning restore SYSLIB0011
}
}
[Serializable]
public class Person
{
public string? FirstName;
public string? LastName;
public Book? FavoriteBook;
}
[Serializable]
public class Book
{
public string? Title;
public string? Author;
public decimal? Price;
}
// A sample EventListener that writes data to System.Console.
public class ConsoleEventListener : EventListener
{
protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
base.OnEventWritten(eventData);
Console.WriteLine($"Event {eventData.EventName} (id={eventData.EventId}) received.");
if (eventData.PayloadNames != null)
{
for (int i = 0; i < eventData.PayloadNames.Count; i++)
{
Console.WriteLine($"{eventData.PayloadNames[i]} = {eventData.Payload?[i]}");
}
}
}
}
}
위 코드의 출력은 다음 예제와 유사합니다.
Event SerializationStart (id=10) received.
Event SerializingObject (id=12) received.
typeName = BinaryFormatterEventSample.Person, BinaryFormatterEventSample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Event SerializingObject (id=12) received.
typeName = BinaryFormatterEventSample.Book, BinaryFormatterEventSample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Event SerializationStop (id=11) received.
Event DeserializationStart (id=20) received.
Event DeserializingObject (id=22) received.
typeName = BinaryFormatterEventSample.Person, BinaryFormatterEventSample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Event DeserializingObject (id=22) received.
typeName = BinaryFormatterEventSample.Book, BinaryFormatterEventSample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Event DeserializationStop (id=21) received.
Rehydrated person Logan Edwards
Favorite book: A Tale of Two Cities by Charles Dickens, list price 10.25
이 샘플에서 콘솔 기반 EventListener는 직렬화가 시작되고, Person 및 Book의 인스턴스가 직렬화된 다음 직렬화가 완료됨을 기록합니다. 마찬가지로 역직렬화가 시작되면 Person 및 Book 인스턴스가 역직렬화된 다음 역직렬화가 완료됩니다.
그런 다음 앱은 역직렬화된 Person에 포함된 값을 출력하여 실제로 개체가 올바로 직렬화 및 역직렬화되었음을 보여 줍니다.
참고 항목
EventListener를 사용하여 EventSource 기반 알림을 수신하는 방법에 대한 자세한 내용은 EventListener 클래스를 참조하세요.
.NET