-
-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #104 from hydrostack/cookie-store
Cookie store
- Loading branch information
Showing
5 changed files
with
210 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
--- | ||
outline: deep | ||
--- | ||
|
||
# Cookies | ||
|
||
Hydro components provide a simple way to work with cookies in your application. You can read, write, and delete cookies using the `CookieStorage` property on the `HydroComponent` class: | ||
|
||
```c# | ||
// ThemeSwitcher.cshtml.cs | ||
public class ThemeSwitcher : HydroComponent | ||
{ | ||
public string Theme { get; set; } | ||
|
||
public override void Mount() | ||
{ | ||
Theme = CookieStorage.Get<string>("theme", defaultValue: "light"); | ||
} | ||
|
||
public void Switch(string theme) | ||
{ | ||
Theme = theme; | ||
CookieStorage.Set("theme", theme); | ||
} | ||
} | ||
``` | ||
|
||
## Complex objects | ||
|
||
You can also store complex objects in cookies. Hydro will serialize and deserialize them for you: | ||
|
||
```c# | ||
// UserSettings.cshtml.cs | ||
public class UserSettings : HydroComponent | ||
{ | ||
public UserSettingsStorage Storage { get; set; } | ||
|
||
public override void Mount() | ||
{ | ||
Storage = CookieStorage.Get("settings", defaultValue: new UserSettingsStorage()); | ||
} | ||
|
||
public void SwitchTheme(string theme) | ||
{ | ||
Storage.Theme = theme; | ||
CookieStorage.Set("settings", Storage); | ||
} | ||
|
||
public class UserSettingsStorage | ||
{ | ||
public string StartupPage { get; set; } | ||
public string Theme { get; set; } | ||
} | ||
} | ||
``` | ||
|
||
## Customizing cookies | ||
|
||
Default expiration date is 30 days, but can be customized with expiration parameter: | ||
|
||
```c# | ||
CookieStorage.Set("theme", "light", expiration: TimeSpan.FromDays(7)); | ||
``` | ||
|
||
You can further customize the cookie settings by passing an instance of `CookieOptions` to the `Set` method: | ||
|
||
```c# | ||
CookieStorage.Set("theme", "light", encrypt: false, new CookieOptions { Secure = true }); | ||
``` | ||
|
||
## Encryption | ||
|
||
It's possible to encrypt the cookie value by setting the `encryption` parameter to `true`: | ||
|
||
```c# | ||
CookieStorage.Set("theme", "light", encryption: true); | ||
``` | ||
|
||
```c# | ||
CookieStorage.Get<string>("theme", encryption: true); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
using Microsoft.AspNetCore.Http; | ||
using Newtonsoft.Json; | ||
|
||
namespace Hydro.Services; | ||
|
||
/// <summary> | ||
/// Provides a standard implementation for ICookieManager interface, allowing to store/read complex objects in cookies | ||
/// </summary> | ||
public class CookieStorage | ||
{ | ||
private readonly HttpContext _httpContext; | ||
private readonly IPersistentState _persistentState; | ||
|
||
/// <summary> | ||
/// Returns a value type or a specific class stored in cookies | ||
/// </summary> | ||
public T Get<T>(string key, bool encryption = false, T defaultValue = default) | ||
{ | ||
try | ||
{ | ||
_httpContext.Request.Cookies.TryGetValue(key, out var storage); | ||
|
||
if (storage != null) | ||
{ | ||
var json = encryption | ||
? _persistentState.Unprotect(storage) | ||
: storage; | ||
|
||
return JsonConvert.DeserializeObject<T>(json); | ||
} | ||
} | ||
catch | ||
{ | ||
//ignored | ||
} | ||
|
||
return defaultValue; | ||
} | ||
|
||
/// <summary> | ||
/// Default expiration time for cookies | ||
/// </summary> | ||
public static TimeSpan DefaultExpirationTime = TimeSpan.FromDays(30); | ||
|
||
/// <summary> | ||
/// Customizable default JsonSerializerSettings used for complex objects | ||
/// </summary> | ||
public static JsonSerializerSettings JsonSettings = new() | ||
{ | ||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore | ||
}; | ||
|
||
internal CookieStorage(HttpContext httpContext, IPersistentState persistentState) | ||
{ | ||
_httpContext = httpContext; | ||
_persistentState = persistentState; | ||
} | ||
|
||
/// <summary> | ||
/// Stores provided `value` in cookies | ||
/// </summary> | ||
public void Set<T>(string key, T value, bool encryption = false, TimeSpan? expiration = null) | ||
{ | ||
var options = new CookieOptions | ||
{ | ||
MaxAge = expiration ?? DefaultExpirationTime, | ||
}; | ||
|
||
Set(key, value, encryption, options); | ||
} | ||
|
||
/// <summary> | ||
/// Stores in cookies a value type or a specific class with exact options to be used. Will also be encrypted if `secure` is enabled in options. | ||
/// </summary> | ||
public void Set<T>(string key, T value, bool encryption, CookieOptions options) | ||
{ | ||
var response = _httpContext.Response; | ||
|
||
if (value != null) | ||
{ | ||
var serializedValue = JsonConvert.SerializeObject(value, JsonSettings); | ||
var finalValue = encryption | ||
? _persistentState.Protect(serializedValue) | ||
: serializedValue; | ||
|
||
response.Cookies.Append(key, finalValue, options); | ||
} | ||
else | ||
{ | ||
response.Cookies.Delete(key); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Deletes a cookie record | ||
/// </summary> | ||
public void Delete(string key) | ||
{ | ||
var response = _httpContext.Response; | ||
response.Cookies.Delete(key); | ||
} | ||
} |