> For the complete documentation index, see [llms.txt](https://docs.licensespring.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.licensespring.com/sdks/tutorials/advanced-usage/custom-license-storage.md).

# Custom License Storage

While a default location is predefined for the local license file, the flexibility to modify its location exists within LicenseSpring's C++ and .NET SDK.

This versatility allows for storing the license file in various alternative locations, including databases, Windows registries, or remote servers.

{% hint style="info" %}
Note: This guide operates under the assumption that SQLite3 is properly installed on the reader's device, and a fundamental understanding of SQL is present.

If you require more information about SQLite, it's recommended to refer to their [**official documentation**](https://www.sqlite.org/docs.html) for comprehensive insights.
{% endhint %}

### Prerequisites

{% stepper %}
{% step %}

### Completed the Getting Started tutorial

You should have completed the [**Getting Started**](/sdks/tutorials/getting-started.md) tutorial, specifically:

* Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
* Created a `LicenseID` using either `LicenseID::fromKey` or `LicenseID::fromUser` function, depending on the activation method you prefer.
* Implemented basic license management, including license activations, deactivations, and both online and local license checks.
  {% endstep %}
  {% endstepper %}

### Default License File Encryption

In the `LicenseStorage` interface, the encryption and decryption of the license file are executed by invoking basic functions within the C++ and .NET SDK.

Encryption takes place during the activation and initial storage of the license, utilizing the `activateLicense()` method on the `LicenseManager` object.

Decryption of the license file is done automatically when the SDK automatically reloads the license file, or when either `reloadLicense()` or `getCurrentLicense()` are called on the `LicenseManager` object.

{% hint style="info" %}
Note: The methods `loadLicense()` and `saveLicense()` present in `LicenseFileStorage` are responsible for reading and writing the license file, without involving encryption or decryption. Encryption is exclusively carried out during license activation and retrieval processes.
{% endhint %}

{% hint style="info" %}
In the .NET SDK (v8.0.0+), the local license file is encrypted with AES-256-GCM using the LSLF format by default. See [Security and Cryptographic Providers](https://docs.licensespring.com/sdks/tutorials/advanced-usage/security-and-cryptographic-providers) for details.
{% endhint %}

### Adding License File to a Database

Once you've established the derived class and successfully implemented the `loadLicense()`, `saveLicense()`, and `clear()` methods, the next step involves customizing the default file location.

To accomplish this, when instantiating the `LicenseManager` object, you should provide a second parameter. This additional parameter allows you to specify a different storage location for the local license.

By default, the local license is stored in a file. To check this default location, see [**Local License File**](/sdks/tutorials/best-practices/local-license-file.md).

{% tabs %}
{% tab title="C++" %}

```cpp
licenseManager->create(configuration, storage);
```

{% endtab %}

{% tab title="C#" %}
In the .NET SDK, custom storage is supplied by implementing the ILicenseStorage interface and passing an instance to Initialize. The interface has three methods — SaveLicense(string), LoadLicense(), and Clear() — that receive and return the already-encrypted license data string, so your code only handles persistence, never cryptography.

{% code overflow="wrap" %}

```csharp
using LicenseSpring;

 public class DatabaseLicenseStorage : ILicenseStorage
 {
     // Save the encrypted license data string to your store (DB, registry, remote, etc.)
     public void SaveLicense(string licenseData)
     {
         MyDatabase.Insert(licenseData);
     }

     // Return the previously saved string, or null if none exists.
     public string LoadLicense()
     {
         return MyDatabase.Get(); // null if not found
     }

     // Remove the stored license data.
     public void Clear()
     {
         MyDatabase.Delete();
     }
 }
```

{% endcode %}

Pass your storage to the manager when initializing:

```csharp
var licenseManager = LicenseManager.GetInstance();
licenseManager.Initialize(configuration, new DatabaseLicenseStorage());
```

Any exception thrown from these methods is wrapped in a LocalLicenseException and propagated.

Just changing the file location? You don't need a custom class. The default LicenseFileStorage lets you change the location of the file:

{% code overflow="wrap" %}

```csharp
licenseManager.DataLocation = @"C:\MyApp\Licenses";
licenseManager.LicenseFileName = "app.key";
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}

```java
licenseManager.initialize(configuration, repository);
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Reminder: Encryption operations are conducted independently of the `loadLicense()` and `saveLicense()` methods. These methods do not require encryption or decryption procedures.
{% endhint %}

### License File Terminology

#### LicenseFileStorageBase

`LicenseFileStorageBase` serves as the foundational class responsible for storing licenses in a file and implementing the `LicenseStorage` interface. It is important to note that this class does not incorporate any mechanisms for ensuring synchronized access to files, rendering it unsuitable for concurrent multi-threaded operations.

#### LicenseFileStorage

Derived from `LicenseFileStorageBase`, the `LicenseFileStorage` class inherits its characteristics and functionality, but with the added feature of thread-safe file operations. This class stands as the default choice for license storage, as it guarantees safe file handling even in multi-threaded scenarios.

#### LicenseFileStorageEx (deprecated in v8.0.0)

A further specialization of the `LicenseFileStorageBase` class is `LicenseFileStorageEx`. This advanced license file storage variant is specifically designed for interprocess applications. It employs a synchronization mechanism using a mutex provided by the Boost library, ensuring both thread and process safety. This class is ideal for scenarios where concurrent access from multiple threads and processes is required while maintaining the integrity of file operations.

LicenseFileStorageEx is deprecated in v8.0.0 because thread-safety is now built into LicenseFileStorage and optional process-safety is implemented in the SDK transaction layer (see Process Safety below). If you were using LicenseFileStorageEx to coordinate license access between multiple processes, you must explicitly enable process safety.

#### C# / .NET storage types

<table><thead><tr><th width="201">Type</th><th width="528">Role</th></tr></thead><tbody><tr><td><code>ILicenseStorage</code></td><td>Interface for custom storage (<code>SaveLicense</code> / <code>LoadLicense</code> / <code>Clear</code>).</td></tr><tr><td><code>LicenseFileStorage</code></td><td>Default. Stores the encrypted license in a file. Thread-safe.</td></tr><tr><td><code>LicenseMemoryStorage</code></td><td>Keeps the license in memory only. This is the default when <code>ExtendedOptions.WebServiceMode</code> is set.</td></tr><tr><td><code>LicenseFileStorageEx</code></td><td>Obsolete. Superseded by <code>ExtendedOptions.EnableProcessSafety</code> on the default <code>LicenseFileStorage</code>.</td></tr></tbody></table>

### Process Safety

Starting in C++ SDK v8.0.0, the SDK can serialize license file reads and writes across multiple processes. This is **disabled by default** because most applications only access the license file from a single process, and the locking adds I/O overhead on every read and write.

Enable it through `ExtendedOptions`:

{% tabs %}
{% tab title="C++" %}

```cpp
ExtendedOptions options;
options.enableProcessSafety(true);
```

{% endtab %}

{% tab title="C#" %}

```csharp
var options = new LicenseSpring.ExtendedOptions
{
    EnableProcessSafety = true   // default is false
};
var configuration = new LicenseSpring.Configuration(
    apiKey:        "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    sharedKey:     "XXXXXXXXX-XXXXX-XXXXXXXXXXXXX_XXXXXX_XXXXXX",
    productCode:   "XXXXXX",
    appName:       "NAME",
    appVersion:    "VERSION",
    extendedOptions: options );

var licenseManager = LicenseManager.GetInstance();
licenseManager.Initialize( configuration );
```

When EnableProcessSafety is enabled, the SDK serializes cross-process reads and writes using a companion \<license\_file>.lock file (FileShare.None on Windows, flock on Unix) and performs an atomic read-modify-write — it re-reads the latest file contents under the lock before applying each change, avoiding lost updates. When disabled (the default), the SDK assumes a single writer and serves reads from an in-memory cache for performance.

{% hint style="info" %}
EnableProcessSafety replaces the obsolete LicenseFileStorageEx. Do not use both at once — that would guard the same file with two uncoordinated locking mechanisms. If you previously used LicenseFileStorageEx, remove it and enable EnableProcessSafety with the default LicenseFileStorage instead.
{% endhint %}
{% endtab %}
{% endtabs %}

When enabled, the SDK acquires an exclusive OS-level lock on `<license_file>.lock` (e.g. `License.key.lock`) for the duration of every read-modify-write transaction, and re-reads the license file on every access to detect changes made by other processes. The lock file is created next to the license file the first time it is needed and doesn't get deleted later on. The kernel releases the file lock automatically if a process exits or crashes while holding it.

#### When to enable it

* You run multiple processes that all activate, check and use the same license file.
* You share the license file across two different LicenseSpring SDKs (e.g. C++ and .NET) on the same machine.

#### When to leave it disabled (the default)

* A single process accesses the license file.
* You implement a custom `LicenseStorage` that has its own concurrency control (e.g. a database).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.licensespring.com/sdks/tutorials/advanced-usage/custom-license-storage.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
