Overview
This article shares with .NET developers a lightweight, open-source encryption tool library that encodes numbers into string (short ID generation)—Hashids.net.
Whether in frontend or backend development, there are scenarios where the system needs to automatically generate some codes or IDs, and the generated codes or IDs must be non-repetitive (with extremely low repetition rates).
In frontend development, commonly used tools include nanoid. In backend development, common techniques include: auto-increment IDs, Snowflake IDs, GUIDs, etc. Among them, auto-increment IDs are commonly used in small and medium-sized systems. They occupy relatively small storage space and have relatively fast retrieval speed, but they are not suitable for distributed system construction. Snowflake IDs and GUIDs occupy more bytes, take up larger storage space, and have relatively slower retrieval speed, but the latter two are suitable for distributed system construction.
Additionally, there are scenarios where, to hide the real backend ID, the real ID is encrypted when displayed to the client, turning the real number into a short string. For example, the video URL of the well-known foreign video site YouTube is similar to https://www.yt.com/watch?v=yVd7vbeFj-g, where the parameter v with the value yVd7vbeFj-g is an encrypted string.
In .NET, .NET Core, .NET 5\6\7\8 and other program development, if you also want to generate similar encrypted strings, this article recommends for .NET developers the open-source short ID generation (encryption) library Hashids.net.
Hashids.net Features and Characteristics
Hashids.net can convert numbers into strings, for example, convert 347 into yr8, or the number array [27, 986] into 3kTMd. Of course, you can also convert the resulting string back into numbers or number arrays. This is very useful for bundling multiple parameters into one, hiding actual IDs, or simply using them as short string IDs.
Hashids.net has the following main features:
- Convert integers into unique short IDs (only supports positive integers including zero)
- Generate non-sequential IDs that are not predictable for auto-increment IDs
- Support single numbers or number arrays
- Allow custom alphabet and salt
- Allow specifying minimum hash length
Installation of Hashids.net
Hashid.net is published as a NuGet package, so there are the following installation methods:
1. NuGet Command Line
Install-Package Hashids.net
2. NuGet Package Manager
Right-click Dependencies in the project, as shown:

Then, in the opened NuGet package management interface, enter the keyword Hashids.net, select the Hashids.net library component from the search results, and install it, as shown:

Usage of Hashids.net
Import Hashids.net Namespace
using HashidsNet;
Encoding a Single Number
When instantiating the Hashids object, you can pass a unique salt value so that your hash differs from others. Here, this is my salt is used as an example.
var Hashids = new Hashids("this is my salt");
var hash = hashids.Encode(12345);
Result: NkK9
If you need to convert an Int64 number, use the EncodeLong() method as follows:
var hashids = new Hashids("this is my salt");
var hash = hashids.EncodeLong(666555444333222L);
Result: KVO9yy1oO5j
Decoding
Hashids.net provides the ability to reverse-decode an encoded string, but the same salt used for encoding must be provided for decoding:
var hashids = new Hashids("this is my salt");
numbers = hashids.Decode("NkK9");
Result: [ 12345 ]
var hashids = new Hashids("this is my salt");
numbers = hashids.DecodeLong("KVO9yy1oO5j");
Result: [ 666555444333222L ]
Decoding with Different Salt
If the salt used during decoding differs from the one used during encoding, decoding will fail:
var hashids = new Hashids("this is my pepper");
numbers = hashids.Decode("NkK9");
Result: []
Encoding Multiple Numbers
var hashids = new Hashids("this is my salt");
var hash = hashids.Encode(683, 94108, 123, 5);
Result: aBMswoO2UB3Sj
Decoding After Encoding Multiple Numbers
var hashids = new Hashids("this is my salt");
var numbers = hashids.Decode("aBMswoO2UB3Sj")
Result: [ 683, 94108, 123, 5 ]
Specifying Minimum Hash Length After Encoding
The following example encodes the integer 1 and sets the minimum hash length to 8 (default is 0—meaning the hash will be the shortest possible length).
var hashids = new Hashids("this is my salt", 8);
var hash = hashids.Encode(1);
Result: gB0NV05e
Decoding
var hashids = new Hashids("this is my salt", 8);
var numbers = hashids.Decode("gB0NV05e");
Result: [ 1 ]
Custom Hash Alphabet
The following example specifies a custom hash alphabet abcdefghijkABCDEFGHIJK12345:
var hashids = new Hashids("this is my salt", 0, "abcdefghijkABCDEFGHIJK12345")
var hash = hashids.Encode(1, 2, 3, 4, 5)
Result: Ec4iEHeF3
Randomness of Hashids.net
The main purpose of Hashids.net is to obfuscate IDs; additionally, it can make regular numbers unpredictable and unguessable.
Encoding Repeated Numbers
var hashids = new Hashids("this is my salt");
var hash = hashids.Encode(5, 5, 5, 5);
After encoding, you won't see any repeating pattern indicating that there are 4 identical numbers in the hash. The result is: 1Wc8cwcE.
Encoding Sequential Numbers
var hashids = new Hashids("this is my salt");
var hash = hashids.Encode(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Result: kRHnurhptKcjIDTWC3sx
Encoding Incremental Numbers
var hashids = new Hashids("this is my salt");
hashids.Encode(1); // => NV
hashids.Encode(2); // => 6m
hashids.Encode(3); // => yD
hashids.Encode(4); // => 2l
hashids.Encode(5); // => rD
Encoding Hexadecimal
var hashids = new Hashids("this is my salt");
var hash = hashids.EncodeHex("DEADBEEF");
Result: kRNrpKlJ
Decoding Hexadecimal
var hashids = new Hashids("this is my salt");
var hex = hashids.DecodeHex("kRNrpKlJ");
Result: DEADBEEF
How to Encrypt Strings to Generate Short Strings?
The following is an extension method introduced by the site administrator for converting long strings to short strings.
It is actually very simple: use the original string to be encrypted as the salt, and encrypt a fixed number. This achieves the goal simply:
public static string GetHashids(this string sourceStr, int number = 9)
{
var hashids = new Hashids(sourceStr);
return hashids.Encode(number);
}
A unit test example: encrypt the alias of this article Is-it-possible-to-use-it-as-a-short-link-generator-Hashidsnet
[TestClass]
public class HashHelperUnitTest
{
[TestMethod]
public void Hashids_Success()
{
var blogPostSlugStr = "Is-it-possible-to-use-it-as-a-short-link-generator-Hashidsnet";
var encodeStr1 = blogPostSlugStr.GetHashids();
var encodeStr2 = blogPostSlugStr.GetHashids();
Assert.AreEqual(encodeStr1, encodeStr2);
}
}
The alias is encrypted to: 6Q. You can open the browser and try the short link of this article: https://dotnet9.com/6Q .
Note: Using it this way is not the original intention of this library, but it is indeed a good idea to convert long strings into short strings. Haha, remember this is irreversible.
Little Knowledge
There are multiple methods to convert a long string into a short string. Common practices include:
- Use a database to store the short string and the original string. The short string can follow custom rules, e.g., start from 1, and each time a value is retrieved, query the database to get the long string from the short string or vice versa.
Advantages: One-to-one correspondence between short and long strings, enabling two-way conversion without duplicate short strings.
Disadvantages: Requires frequent database reads and writes, impacting database performance.
- Use an algorithm to convert the long string into a short string. Some algorithms are reversible, some are irreversible.
No database storage needed, but the resulting length may be slightly longer.
- Example of a reversible algorithm (C#):
public static string ShortenString(string longString)
{
byte[] bytes = Encoding.UTF8.GetBytes(longString);
string shortString = Convert.ToBase64String(bytes);
return shortString;
}
public static string RestoreString(string shortString)
{
byte[] bytes = Convert.FromBase64String(shortString);
string longString = Encoding.UTF8.GetString(bytes);
return longString;
}
- Example of an irreversible algorithm (C#):
public static string ShortenString(string longString)
{
using (SHA256 sha256 = SHA256.Create())
{
byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(longString));
string shortString = Convert.ToBase64String(hashBytes);
return shortString;
}
}
- Differences:
- Reversible algorithms can restore the original string from the short string, while irreversible algorithms cannot.
- Reversible algorithms produce longer short strings, while irreversible algorithms produce shorter ones.
- Using an algorithm to automatically generate short strings does not require frequent database reads/writes and has better performance, but there may be a risk of short string collisions—different long strings could generate the same short string.
Finally, the complete unit test is listed for your reference:
using HashidsNet;
using System.Security.Cryptography;
using System.Text;
namespace Dotnet9.Commons.Test;
[TestClass]
public class HashHelperUnitTest
{
public static string GetHashids(string sourceStr, int number = 9)
{
var hashids = new Hashids(sourceStr);
return hashids.Encode(number);
}
[TestMethod]
public void Hashids_Success()
{
var blogPostSlugStr = "Is-it-possible-to-use-it-as-a-short-link-generator-Hashidsnet";
var encodeStr1 = GetHashids(blogPostSlugStr);
var encodeStr2 = GetHashids(blogPostSlugStr);
Assert.AreEqual(encodeStr1, encodeStr2);
}
[TestMethod]
public void Hashids_Best_Success()
{
var blogPostSlugStr = "Is-it-possible-to-use-it-as-a-short-link-generator-Hashidsnet";
var encodeStr1 = blogPostSlugStr.GetHashids();
var encodeStr2 = ShortenString(blogPostSlugStr);
var encodeStr3 = ShortenString2(blogPostSlugStr);
Assert.IsTrue(encodeStr1.Length < encodeStr2.Length, "The short string generated by Hashids is shorter than Base64");
Assert.IsTrue(encodeStr1.Length < encodeStr3.Length, "The short string generated by Hashids is still a bit shorter");
}
public static string ShortenString(string longString)
{
byte[] bytes = Encoding.UTF8.GetBytes(longString);
string shortString = Convert.ToBase64String(bytes);
return shortString;
}
public static string RestoreString(string shortString)
{
byte[] bytes = Convert.FromBase64String(shortString);
string longString = Encoding.UTF8.GetString(bytes);
return longString;
}
public static string ShortenString2(string longString)
{
using (SHA256 sha256 = SHA256.Create())
{
byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(longString));
string shortString = Convert.ToBase64String(hashBytes);
return shortString;
}
}
}
Most of this article references the original Zhihu article:
Original title: Share .NET/.NET 5 lightweight open-source tool library for encoding numbers into encrypted strings (short ID generation) -- hashids.net
Original link: https://codedefault.com/p/lightweight-open-source-project-hashids-net-for-generating-short-ids-from-numbers