Skip to main content

BinaryFormatter serialization and deserialization are disabled within this application

Knowing that the support for .NET 6 will end soon (I’m writing this post August 2024, support ends in November 2024), I’m helping my customers move to .NET 8.

UPDATE: After writing this article, Microsoft created a blog post with more details about the removal of the Binary Formatter in .NET 9. 

Although Microsoft does a lot of effort to guarantee backwards compatibility, we still encountered some problems. In one (older) application where we were using (Fluent)NHibernate, we got the following error after upgrading:

FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.

---> System.NotSupportedException: BinaryFormatter serialization and deserialization are disabled within this application. See https://aka.ms/binaryformatter for more information.
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)
   at FluentNHibernate.Utils.Extensions.DeepClone[T](T obj)
   at FluentNHibernate.Mapping.SubclassMap`1.FluentNHibernate.Mapping.Providers.IIndeterminateSubclassMappingProvider.GetSubclassMapping(SubclassType type)
   at FluentNHibernate.Visitors.SeparateSubclassVisitor.ProcessClass(ClassMapping mapping)
   at FluentNHibernate.MappingModel.ClassBased.ClassMapping.AcceptVisitor(IMappingModelVisitor visitor)
   at FluentNHibernate.Visitors.DefaultMappingModelVisitor.Visit(ClassMapping classMapping)
   at FluentNHibernate.MappingModel.HibernateMapping.AcceptVisitor(IMappingModelVisitor visitor)
   at FluentNHibernate.Visitors.DefaultMappingModelVisitor.<Visit>b__10_0(HibernateMapping x)
   at FluentNHibernate.Utils.CollectionExtensions.Each[T](IEnumerable`1 enumerable, Action`1 each)
   at FluentNHibernate.Visitors.DefaultMappingModelVisitor.Visit(IEnumerable`1 mappings)
   at FluentNHibernate.PersistenceModel.ApplyVisitors(IEnumerable`1 mappings)
   at FluentNHibernate.PersistenceModel.BuildMappings()
   at FluentNHibernate.PersistenceModel.EnsureMappingsBuilt()
   at FluentNHibernate.PersistenceModel.Configure(Configuration cfg)
   at FluentNHibernate.Cfg.MappingConfiguration.Apply(Configuration cfg)
   at FluentNHibernate.Cfg.FluentConfiguration.BuildConfiguration()
   --- End of inner exception stack trace ---
   at FluentNHibernate.Cfg.FluentConfiguration.BuildConfiguration()
   at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory()

This error happens for a good reason as usage of the BinaryFormatter is considered dangerous as it is a possible attack vector due to deserialization vulnerabilities.

From the documentation:

Deserialization vulnerabilities are a threat category where request payloads are processed insecurely. An attacker who successfully leverages these vulnerabilities against an app can cause denial of service (DoS), information disclosure, or remote code execution inside the target app.

In .NET, the biggest risk target is apps that use the BinaryFormatter type to deserialize data. BinaryFormatter is widely used throughout the .NET ecosystem because of its power and its ease of use. However, this same power gives attackers the ability to influence control flow within the target app. Successful attacks can result in the attacker being able to run code within the context of the target process.

If you don’t want to replace the BinaryFormatter,  in .NET 8 you can still allow BinaryFormatter usage by setting the following flag:

However be aware that in .NET 9, this flag is ignored and the BinaryFormatter implementation always throws exceptions on use.

So the way forward is clear, replace the BinaryFormatter by an alternative(more about this below). However if you are really stubborn and want to keep using the BinaryFormatter, you can switch to the unsupported(!) compatibility package:

Replacing the BinaryFormatter

So the recommended way is to replace the BinaryFormatter. To help you, the .NET team recommends any of the following options depending on your needs:

Important to notice is that none of these option are an in-place replacement for the BinaryFormatter, so development work and thorough testing will be needed to avoid introducing bugs.

Here is an overview that compares the different options:

Good lucking replacing the BinaryFormatter! 

More information

Popular posts from this blog

Podman– Command execution failed with exit code 125

After updating WSL on one of the developer machines, Podman failed to work. When we took a look through Podman Desktop, we noticed that Podman had stopped running and returned the following error message: Error: Command execution failed with exit code 125 Here are the steps we tried to fix the issue: We started by running podman info to get some extra details on what could be wrong: >podman info OS: windows/amd64 provider: wsl version: 5.3.1 Cannot connect to Podman. Please verify your connection to the Linux system using `podman system connection list`, or try `podman machine init` and `podman machine start` to manage a new Linux VM Error: unable to connect to Podman socket: failed to connect: dial tcp 127.0.0.1:2655: connectex: No connection could be made because the target machine actively refused it. That makes sense as the podman VM was not running. Let’s check the VM: >podman machine list NAME         ...

Azure DevOps/ GitHub emoji

I’m really bad at remembering emoji’s. So here is cheat sheet with all emoji’s that can be used in tools that support the github emoji markdown markup: All credits go to rcaviers who created this list.

Cache stampede: when our cache turned against us

While investigating some performance issues, we ran into an ASP.NET Core API that cached a fairly expensive aggregation query for 60 seconds. Under normal load, that was fine: one request rebuilds the cache, everyone else reads from it. Under peak load, dozens of requests would arrive in that same expiry window, all see a cache miss, and all fire the same expensive query in parallel. The database didn't like that. That was the moment when our caching layer stopped helping and started hurting. A burst of requests comes in at the same time, all miss the cache, and all go hammer the database or the downstream API at once. That's a cache stampede . The cache was supposed to protect our backend, and for a few hundred milliseconds it did the opposite. Why this happens IMemoryCache.GetOrCreate (and its async sibling) looks like it protects you, but it doesn't add any locking on its own. Look at the naive version: public async Task<Report> GetReportAsync(string key) ...