{"id":13578283,"url":"https://github.com/akkadotnet/Hyperion","last_synced_at":"2025-04-05T16:32:08.957Z","repository":{"id":37898531,"uuid":"76280580","full_name":"akkadotnet/Hyperion","owner":"akkadotnet","description":"Polymorphic serialization for .NET","archived":false,"fork":false,"pushed_at":"2024-10-23T18:32:47.000Z","size":7633,"stargazers_count":277,"open_issues_count":65,"forks_count":62,"subscribers_count":20,"default_branch":"dev","last_synced_at":"2024-11-11T09:05:00.829Z","etag":null,"topics":["dotnet","dotnet-core","hyperion","serialization","serializer"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/akkadotnet.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-12-12T17:43:18.000Z","updated_at":"2024-10-23T15:58:35.000Z","dependencies_parsed_at":"2024-11-18T13:26:46.289Z","dependency_job_id":"4f9aac7a-8d8c-4281-93ed-43be259db7bc","html_url":"https://github.com/akkadotnet/Hyperion","commit_stats":{"total_commits":547,"total_committers":46,"mean_commits":"11.891304347826088","dds":"0.40585009140767825","last_synced_commit":"0648eb9589cfa4ab81bece5c7872b49867c2878d"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akkadotnet%2FHyperion","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akkadotnet%2FHyperion/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akkadotnet%2FHyperion/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akkadotnet%2FHyperion/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/akkadotnet","download_url":"https://codeload.github.com/akkadotnet/Hyperion/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247092382,"owners_count":20882218,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dotnet","dotnet-core","hyperion","serialization","serializer"],"created_at":"2024-08-01T15:01:29.087Z","updated_at":"2025-04-05T16:32:08.952Z","avatar_url":"https://github.com/akkadotnet.png","language":"C#","funding_links":[],"categories":["C# #","Serialization","序列化","Identifiers"],"sub_categories":["GUI - other"],"readme":"# Hyperion\n\n[![Join the chat at https://gitter.im/akkadotnet/Hyperion](https://badges.gitter.im/akkadotnet/Hyperion.svg)](https://gitter.im/akkadotnet/Hyperion?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\nA high performance polymorphic serializer for the .NET framework.\n\nCurrent status: **BETA** (v0.9.14).\n\n## License\nLicensed under Apache 2.0, see [LICENSE](LICENSE) for the full text.\n\n## Polymorphic serializations\n\nHyperion was designed to safely transfer messages in distributed systems, for example service bus or actor model based systems.\nIn message based systems, it is common to receive different types of messages and apply pattern matching over those messages.\nIf the messages does not carry over all the relevant type information to the receiveing side, the message might no longer match exactly what your system expect.\n\nConsider the following case:\n\n```csharp\npublic class Envelope\n{\n     //untyped property\n     public object Payload {get;set;}\n     //other properties..\n     ...\n}\n\n...\n\nvar envelope = new Envelope { Payload = (float)1.2 };\n```\n\nIf you for example are using a Json based serializer, it is very likely that the value `1.2` will be deserialized as a `double` as Json has no way to describe the type of the decimal value.\nWhile if you use some sort of binary serializer like Google Protobuf, all messages needs to be designed with a strict contract up front.\nHyperion solves this by encoding a manifest for each value - a single byte prefix for primitive values, and fully qualified assembly names for complex types.\n\n## Surrogates\n\nSometimes, you might have objects that simply can't be serialized in a safe way, the object might be contextual in some way.\nHyperion can solve those problems using \"Surrogates\", surrogates are a way to translate an object from and back to the context bound representation.\n\n```csharp\nvar surrogate = Surrogate.Create\u003cIMyContextualInterface,IMySurrogate\u003e(original =\u003e original.ToSurrogate(), surrogate =\u003e surrogate.Restore(someContext));\nvar options = new SerializerOptions(surrogates: new [] { surrogate });\nvar serializer = new Serializer(options);\n```\n\nThis is essential for frameworks like Akka.NET where we need to be able to resolve live Actor References in the deserializing system.\n\n## Whitelisting Types On Deserialization\n\nSometimes we need to limit the types that are allowed to be deserialized for security reasons. For this reason, you can either pass a class instance that implements the `ITypeFilter` interface into the `SerializerOptions` or use the `TypeFilterBuilder` class to build a `TypeFilter` that Hyperion can use to filter out any possibly harmful injection attack during deserialization.\n\nusing the `ITypeFilter` interface:\n\n```c#\npublic sealed class TypeFilter : ITypeFilter\n{\n    public ImmutableHashSet\u003cstring\u003e FilteredTypes { get; }\n\n    internal TypeFilter(IEnumerable\u003cType\u003e types)\n    {\n        FilteredTypes = types.Select(t =\u003e t.GetShortAssemblyQualifiedName()).ToImmutableHashSet();\n    }\n    \n    public bool IsAllowed(string typeName)\n        =\u003e FilteredTypes.Any(t =\u003e t == typeName);\n}\n```\n\nusing the `TypeFilterBuilder` convenience builder:\n\n```c#\nvar typeFilter = TypeFilterBuilder.Create()\n    .Include\u003cAllowedClassA\u003e()\n    .Include\u003cAllowedClassB\u003e()\n    .Build();\n\nvar options = SerializerOptions.Default\n    .WithTypeFilter(typeFilter);\n\nvar serializer = new Serializer(options);\n```\n\n### Convert Whitelist To Blacklist\n\nTo do blacklisting instead of whitelisting a list of types, you will need to do a slight modification to the TypeFilter class.\n\n```c#\npublic sealed class TypeFilter : ITypeFilter\n{\n    public ImmutableHashSet\u003cstring\u003e FilteredTypes { get; }\n\n    internal TypeFilter(IEnumerable\u003cType\u003e types)\n    {\n        FilteredTypes = types.Select(t =\u003e t.GetShortAssemblyQualifiedName()).ToImmutableHashSet();\n    }\n    \n    public bool IsAllowed(string typeName)\n        =\u003e FilteredTypes.All(t =\u003e t != typeName);\n}\n```\n\n## Version Tolerance\n\nHyperion has been designed to work in multiple modes in terms of version tolerance vs. performance.\n\n1. Pre Register Types, when using \"Pre registered types\", Hyperion will only emit a type ID in the output stream.\nThis results in the best performance, but is also fragile if different clients have different versions of the contract types.\n2. Non Versioned, this is largely the same as the above, but the serializer does not need to know about your types up front. it will embed the fully qualified typename\nin the output stream. this results in a larger payload and some performance overhead.\n3. Versioned, in this mode, Hyperion will emit both type names and field information in the output stream.\nThis allows systems to have slightly different versions of the contract types where some fields may have been added or removed.\n\nHyperion has been designed as a wire format, point to point for soft realtime scenarios.\nIf you need a format that is durable for persistence over time.\ne.g. EventSourcing or for message queues, then Protobuf or MS Bond is probably a better choice as those formats have been designed for true version tolerance.\n\n## Performance\n\nHyperion has been designed with a performance first mindset.\nIt is not _the_ most important aspect of Hyperion, Surrogates and polymorphism is more critical for what we want to solve.\nBut even with its rich featureset, Hyperion performs extremely well.\n\n```text\nHyperion - preregister types\n   Serialize                      312 ms\n   Deserialize                    261 ms\n   Size                           38 bytes\n   Total                          573 ms\nHyperion - no version data\n   Serialize                      327 ms\n   Deserialize                    354 ms\n   Size                           73 bytes\n   Total                          681 ms\nHyperion - preserve object refs\n   Serialize                      400 ms\n   Deserialize                    369 ms\n   Size                           73 bytes\n   Total                          769 ms\nMS Bond\n   Serialize                      429 ms\n   Deserialize                    404 ms\n   Size                           50 bytes\n   Total                          833 ms\nHyperion - version tolerant\n   Serialize                      423 ms\n   Deserialize                    674 ms\n   Size                           195 bytes\n   Total                          1097 ms\nProtobuf.NET\n   Serialize                      638 ms\n   Deserialize                    721 ms\n   Size                           42 bytes\n   Total                          1359 ms\nJil\n   Serialize                      1448 ms\n   Deserialize                    714 ms\n   Size                           123 bytes\n   Total                          2162 ms\nNet Serializer\n   Serialize                      1289 ms\n   Deserialize                    1113 ms\n   Size                           39 bytes\n   Total                          2402 ms\nJson.NET\n   Serialize                      3767 ms\n   Deserialize                    5936 ms\n   Size                           187 bytes\n   Total                          9703 ms\nBinary formatter\n   Serialize                      10784 ms\n   Deserialize                    11374 ms\n   Size                           362 bytes\n   Total                          22158 ms\n```\n\nThis test was run using the following object definition:\n\n```\npublic class Poco\n{\n    public string StringProp { get; set; }      //using the text \"hello\"\n    public int IntProp { get; set; }            //123\n    public Guid GuidProp { get; set; }          //Guid.NewGuid()\n    public DateTime DateProp { get; set; }      //DateTime.Now\n}\n```\n\n\u003e Big disclaimer: The above results change drastically depending on your contracts, e.g. using smaller messages favor both NetSerializer and Jil.\nThere is no \"best\" or \"fastest\" serializer, it all depends on context and requirements.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakkadotnet%2FHyperion","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakkadotnet%2FHyperion","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakkadotnet%2FHyperion/lists"}