COmpletato modifica x dati utente in cache redis
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>WebDoorCreator - Egalware</i>
|
||||
<h4>Version: 0.9.2305.2910</h4>
|
||||
<h4>Version: 0.9.2305.2916</h4>
|
||||
<br /> Release note:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.9.2305.2910
|
||||
0.9.2305.2916
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>0.9.2305.2910</version>
|
||||
<version>0.9.2305.2916</version>
|
||||
<url>http://nexus.steamware.net/repository/SWS/WDC/stable/WDC.UI.zip</url>
|
||||
<changelog>http://nexus.steamware.net/repository/SWS/WDC/stable/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
@@ -50,8 +50,8 @@ namespace WebDoorCreator.Core
|
||||
public const string rKeyRoles = $"{redisBaseAddr}:Cache:Roles";
|
||||
public const string rKeyUsers = $"{redisBaseAddr}:Cache:Users";
|
||||
public const string rKeyUsersAll = $"{redisBaseAddr}:Cache:UsersAll";
|
||||
public const string rKeyUsersDataId = $"{redisBaseAddr}:Cache:UsersData:Id";
|
||||
public const string rKeyUsersDataSearch = $"{redisBaseAddr}:Cache:UsersData:Search";
|
||||
public const string rKeyUsersData = $"{redisBaseAddr}:Cache:UsersData";
|
||||
public const string rKeyUsersDataSearch = $"{rKeyUsersData}:Search";
|
||||
public const string rKeyUsersView = $"{redisBaseAddr}:Cache:UsersView";
|
||||
public const string rKeyVocLemma = $"{redisBaseAddr}:Cache:VocLemma";
|
||||
public const string rKeyLanguage = $"{redisBaseAddr}:Cache:Languages";
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WebDoorCreator.Data.User
|
||||
{
|
||||
public class ClaimConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return (objectType == typeof(System.Security.Claims.Claim));
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
JObject jo = JObject.Load(reader);
|
||||
string type = (string)jo["Type"];
|
||||
string value = (string)jo["Value"];
|
||||
string valueType = (string)jo["ValueType"];
|
||||
string issuer = (string)jo["Issuer"];
|
||||
string originalIssuer = (string)jo["OriginalIssuer"];
|
||||
return new Claim(type, value, valueType, issuer, originalIssuer);
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Newtonsoft.Json;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace WebDoorCreator.Data.User
|
||||
@@ -10,7 +11,6 @@ namespace WebDoorCreator.Data.User
|
||||
public class UserData
|
||||
{
|
||||
#region Public Properties
|
||||
|
||||
public List<Claim> Claims { get; set; } = new List<Claim>();
|
||||
|
||||
public IdentityUser Identity { get; set; } = null!;
|
||||
|
||||
@@ -4,6 +4,7 @@ using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using StackExchange.Redis;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Claims;
|
||||
using WebDoorCreator.Core;
|
||||
using WebDoorCreator.Data.User;
|
||||
|
||||
@@ -118,6 +119,27 @@ namespace WebDoorCreator.UI.Data
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Effettua reset dati utente...
|
||||
/// </summary>
|
||||
/// <param name="resetAll">Indica reset completo (anche dati elenco di base)</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> ResetUserDataCache(bool resetAll)
|
||||
{
|
||||
bool fatto = false;
|
||||
RedisValue pattern = new RedisValue($"{Constants.rKeyUsersAll}");
|
||||
if (resetAll)
|
||||
{
|
||||
fatto = await ExecFlushRedisPattern(pattern);
|
||||
}
|
||||
// ora resetto il resto
|
||||
pattern = new RedisValue($"{Constants.rKeyUsersData}:*");
|
||||
fatto = fatto && await ExecFlushRedisPattern(pattern);
|
||||
//pattern = new RedisValue($"{Constants.rKeyUsersDataSearch}:*");
|
||||
//fatto = fatto && await ExecFlushRedisPattern(pattern);
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dati utente (TUTTI) da REDIS o DB
|
||||
/// </summary>
|
||||
@@ -161,66 +183,37 @@ namespace WebDoorCreator.UI.Data
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dati utente (singolo x UserId)
|
||||
/// Dati utente (singolo x searchVal)
|
||||
/// </summary>
|
||||
/// <param name="UserId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<UserData> UserDataGetById(string UserId)
|
||||
{
|
||||
string source = "DB";
|
||||
string source = "FULL";
|
||||
UserData dataResult = new UserData();
|
||||
// cerco da cache
|
||||
string currKey = $"{Constants.rKeyUsersDataId}:{UserId}";
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
string? rawData = "";// await redisDb.StringGetAsync(currKey);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
// uso metodi helper protected di base...
|
||||
var userRaw = await UserIdentityById(UserId);
|
||||
var userIdent = new IdentityUser
|
||||
{
|
||||
source = "REDIS";
|
||||
var tempResult = JsonConvert.DeserializeObject<UserData>(rawData);
|
||||
if (tempResult == null)
|
||||
{
|
||||
dataResult = new UserData();
|
||||
}
|
||||
else
|
||||
{
|
||||
dataResult = tempResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
Id = userRaw.Id,
|
||||
UserName = userRaw.UserName,
|
||||
Email = userRaw.Email,
|
||||
PhoneNumber = userRaw.PhoneNumber,
|
||||
PasswordHash = "*****",
|
||||
EmailConfirmed = userRaw.EmailConfirmed
|
||||
};
|
||||
// cerco ruoli & claims
|
||||
var UserRoles = await UserRolesById(userIdent);
|
||||
var UserClaims = await UserClaimsById(userIdent);
|
||||
// compongo output
|
||||
dataResult = new UserData()
|
||||
{
|
||||
// Collezione dati raw
|
||||
var userRaw = await _userManager.FindByIdAsync(UserId);
|
||||
if (userRaw != null)
|
||||
{
|
||||
var userIdent = new IdentityUser
|
||||
{
|
||||
Id = userRaw.Id,
|
||||
UserName = userRaw.UserName,
|
||||
Email = userRaw.Email,
|
||||
PhoneNumber = userRaw.PhoneNumber,
|
||||
PasswordHash = "*****",
|
||||
EmailConfirmed = userRaw.EmailConfirmed
|
||||
};
|
||||
// cerco ruoli & claims
|
||||
var UserRoles = await _userManager.GetRolesAsync(userIdent);
|
||||
var UserClaims = await _userManager.GetClaimsAsync(userIdent);
|
||||
// compongo output
|
||||
dataResult = new UserData()
|
||||
{
|
||||
Identity = userIdent,
|
||||
Roles = UserRoles.ToList(),
|
||||
Claims = UserClaims.ToList()
|
||||
};
|
||||
|
||||
rawData = JsonConvert.SerializeObject(dataResult, JSSettings);
|
||||
await redisDb.StringSetAsync(currKey, rawData, FastCache);
|
||||
}
|
||||
}
|
||||
if (dataResult == null)
|
||||
{
|
||||
dataResult = new UserData();
|
||||
}
|
||||
Identity = userIdent,
|
||||
Roles = UserRoles,
|
||||
Claims = UserClaims
|
||||
};
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"UserDataGetById | {source} in: {ts.TotalMilliseconds} ms");
|
||||
@@ -228,75 +221,41 @@ namespace WebDoorCreator.UI.Data
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dati utente (filtrati da UserId)
|
||||
/// Dati utente (filtrati da searchVal)
|
||||
/// </summary>
|
||||
/// <param name="searchVal"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<UserData>> UserDataGetFilt(string searchVal)
|
||||
{
|
||||
string source = "DB";
|
||||
string source = "FULL";
|
||||
List<UserData> dataResult = new List<UserData>();
|
||||
// cerco da cache
|
||||
string currKey = $"{Constants.rKeyUsersDataSearch}:{searchVal}";
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
string? rawData = "";// await redisDb.StringGetAsync(currKey);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
// uso metodi helper protected di base...
|
||||
List<IdentityUser> RawList = await UserIdentityBySearch(searchVal);
|
||||
// conversione
|
||||
var user = RawList.Select(x => new IdentityUser
|
||||
{
|
||||
source = "REDIS";
|
||||
var tempResult = JsonConvert.DeserializeObject<List<UserData>>(rawData);
|
||||
if (tempResult == null)
|
||||
{
|
||||
dataResult = new List<UserData>();
|
||||
}
|
||||
else
|
||||
{
|
||||
dataResult = tempResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
Id = x.Id,
|
||||
UserName = x.UserName,
|
||||
Email = x.Email,
|
||||
PhoneNumber = x.PhoneNumber,
|
||||
PasswordHash = "*****",
|
||||
EmailConfirmed = x.EmailConfirmed
|
||||
}).ToList();
|
||||
foreach (var item in user)
|
||||
{
|
||||
// Collezione dati raw
|
||||
List<IdentityUser> RawList = new List<IdentityUser>();
|
||||
//List<UserData> UsersList = new List<UserData>();
|
||||
var allData = await UserDataGetAll();
|
||||
if (!string.IsNullOrEmpty(searchVal))
|
||||
{
|
||||
RawList = allData.Where(x => x.NormalizedEmail.Contains(searchVal.ToUpper()) || x.NormalizedUserName.Contains(searchVal.ToUpper())).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
RawList = allData;
|
||||
}
|
||||
var user = RawList.Select(x => new IdentityUser
|
||||
{
|
||||
Id = x.Id,
|
||||
UserName = x.UserName,
|
||||
Email = x.Email,
|
||||
PhoneNumber = x.PhoneNumber,
|
||||
PasswordHash = "*****",
|
||||
EmailConfirmed = x.EmailConfirmed
|
||||
}).ToList();
|
||||
// cerco ruoli & claims
|
||||
var UserRoles = await UserRolesById(item);
|
||||
var UserClaims = await UserClaimsById(item);
|
||||
|
||||
foreach (var item in user)
|
||||
var newItem = new UserData()
|
||||
{
|
||||
var UserRoles = await _userManager.GetRolesAsync(item);
|
||||
var UserClaims = await _userManager.GetClaimsAsync(item);
|
||||
|
||||
var newItem = new UserData()
|
||||
{
|
||||
Identity = item,
|
||||
Roles = UserRoles.ToList(),
|
||||
Claims = UserClaims.ToList()
|
||||
};
|
||||
dataResult.Add(newItem);
|
||||
}
|
||||
rawData = JsonConvert.SerializeObject(dataResult, JSSettings);
|
||||
await redisDb.StringSetAsync(currKey, rawData, FastCache);
|
||||
}
|
||||
if (dataResult == null)
|
||||
{
|
||||
dataResult = new List<UserData>();
|
||||
Identity = item,
|
||||
Roles = UserRoles,
|
||||
Claims = UserClaims
|
||||
};
|
||||
dataResult.Add(newItem);
|
||||
}
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
@@ -304,27 +263,6 @@ namespace WebDoorCreator.UI.Data
|
||||
return dataResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua reset dati utente...
|
||||
/// </summary>
|
||||
/// <param name="resetAll">Indica reset completo (anche dati elenco di base)</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> ResetUserDataCache(bool resetAll)
|
||||
{
|
||||
bool fatto = false;
|
||||
RedisValue pattern = new RedisValue($"{Constants.rKeyUsersAll}");
|
||||
if (resetAll)
|
||||
{
|
||||
fatto = await ExecFlushRedisPattern(pattern);
|
||||
}
|
||||
// ora resetto il resto
|
||||
pattern = new RedisValue($"{Constants.rKeyUsersDataId}:*");
|
||||
fatto = fatto && await ExecFlushRedisPattern(pattern);
|
||||
pattern = new RedisValue($"{Constants.rKeyUsersDataSearch}:*");
|
||||
fatto = fatto && await ExecFlushRedisPattern(pattern);
|
||||
return fatto;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Methods
|
||||
@@ -369,6 +307,169 @@ namespace WebDoorCreator.UI.Data
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dati utente CLAIMS da REDIS o DB
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected async Task<List<Claim>> UserClaimsById(IdentityUser UserIdent)
|
||||
{
|
||||
string source = "DB";
|
||||
List<Claim> dataResult = new List<Claim>();
|
||||
// cerco da cache
|
||||
string currKey = $"{Constants.rKeyUsersData}:Claims:{UserIdent.Id}";
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
string? rawData = await redisDb.StringGetAsync(currKey);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
source = "REDIS";
|
||||
var tempResult = JsonConvert.DeserializeObject<List<Claim>>(rawData, new ClaimConverter());
|
||||
if (tempResult != null)
|
||||
{
|
||||
dataResult = tempResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var rawResult = await _userManager.GetClaimsAsync(UserIdent);
|
||||
dataResult = rawResult.ToList();
|
||||
rawData = JsonConvert.SerializeObject(dataResult, JSSettings);
|
||||
await redisDb.StringSetAsync(currKey, rawData, LongCache);
|
||||
}
|
||||
if (dataResult == null)
|
||||
{
|
||||
dataResult = new List<Claim>();
|
||||
}
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"UserClaimsById | {source} in: {ts.TotalMilliseconds} ms");
|
||||
return dataResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dati utente IDENTITY da REDIS o DB
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected async Task<IdentityUser> UserIdentityById(string UserId)
|
||||
{
|
||||
string source = "DB";
|
||||
IdentityUser dataResult = new IdentityUser();
|
||||
// cerco da cache
|
||||
string currKey = $"{Constants.rKeyUsersData}:Identity:{UserId}";
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
string? rawData = await redisDb.StringGetAsync(currKey);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
source = "REDIS";
|
||||
var tempResult = JsonConvert.DeserializeObject<IdentityUser>(rawData);
|
||||
if (tempResult != null)
|
||||
{
|
||||
dataResult = tempResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataResult = await _userManager.FindByIdAsync(UserId);
|
||||
rawData = JsonConvert.SerializeObject(dataResult, JSSettings);
|
||||
await redisDb.StringSetAsync(currKey, rawData, LongCache);
|
||||
}
|
||||
if (dataResult == null)
|
||||
{
|
||||
dataResult = new IdentityUser();
|
||||
}
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"UserIdentityById | {source} in: {ts.TotalMilliseconds} ms");
|
||||
return dataResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dati utente IDENTITY in modalità SEARCH da REDIS o DB
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected async Task<List<IdentityUser>> UserIdentityBySearch(string searchVal)
|
||||
{
|
||||
string source = "DB";
|
||||
List<IdentityUser> dataResult = new List<IdentityUser>();
|
||||
// cerco da cache
|
||||
string currKey = $"{Constants.rKeyUsersDataSearch}:{searchVal}";
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
string? rawData = await redisDb.StringGetAsync(currKey);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
source = "REDIS";
|
||||
var tempResult = JsonConvert.DeserializeObject<List<IdentityUser>>(rawData);
|
||||
if (tempResult != null)
|
||||
{
|
||||
dataResult = tempResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var allData = await UserDataGetAll();
|
||||
if (!string.IsNullOrEmpty(searchVal))
|
||||
{
|
||||
dataResult = allData
|
||||
.Where(x => x.NormalizedEmail.Contains(searchVal.ToUpper()) || x.NormalizedUserName.Contains(searchVal.ToUpper())).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
dataResult = allData;
|
||||
}
|
||||
rawData = JsonConvert.SerializeObject(dataResult, JSSettings);
|
||||
await redisDb.StringSetAsync(currKey, rawData, LongCache);
|
||||
}
|
||||
if (dataResult == null)
|
||||
{
|
||||
dataResult = new List<IdentityUser>();
|
||||
}
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"UserIdentityBySearch | {source} in: {ts.TotalMilliseconds} ms");
|
||||
return dataResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dati utente ROLES da REDIS o DB
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected async Task<List<string>> UserRolesById(IdentityUser UserIdent)
|
||||
{
|
||||
string source = "DB";
|
||||
List<string> dataResult = new List<string>();
|
||||
// cerco da cache
|
||||
string currKey = $"{Constants.rKeyUsersData}:Roles:{UserIdent.Id}";
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
string? rawData = await redisDb.StringGetAsync(currKey);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
source = "REDIS";
|
||||
var tempResult = JsonConvert.DeserializeObject<List<string>>(rawData);
|
||||
if (tempResult != null)
|
||||
{
|
||||
dataResult = tempResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var rawResult = await _userManager.GetRolesAsync(UserIdent);
|
||||
dataResult = rawResult.ToList();
|
||||
rawData = JsonConvert.SerializeObject(dataResult, JSSettings);
|
||||
await redisDb.StringSetAsync(currKey, rawData, LongCache);
|
||||
}
|
||||
if (dataResult == null)
|
||||
{
|
||||
dataResult = new List<string>();
|
||||
}
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"UserRolesById | {source} in: {ts.TotalMilliseconds} ms");
|
||||
return dataResult;
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
@@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.JSInterop;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using WebDoorCreator.Data.DbModels;
|
||||
using WebDoorCreator.Data.Services;
|
||||
using WebDoorCreator.Data.User;
|
||||
@@ -57,7 +58,7 @@ namespace WebDoorCreator.UI.Pages
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public List<string> ConvertClaim(List<System.Security.Claims.Claim> ClaimList)
|
||||
public List<string> ConvertClaim(List<Claim> ClaimList)
|
||||
{
|
||||
List<string> answ = new List<string>();
|
||||
|
||||
@@ -164,7 +165,6 @@ namespace WebDoorCreator.UI.Pages
|
||||
// filtro visualizzazione x Company, SE richeisto
|
||||
if (FiltCompany != "0")
|
||||
{
|
||||
System.Security.Claims.Claim cClaim = new System.Security.Claims.Claim("CompanyId", $"{FiltCompany}");
|
||||
UsersAll = UsersAll
|
||||
.Where(x => x.Claims.Any(c => c.Type == "CompanyId" && c.Value == $"{FiltCompany}"))
|
||||
.ToList();
|
||||
@@ -180,7 +180,7 @@ namespace WebDoorCreator.UI.Pages
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public string ShowClaims(List<System.Security.Claims.Claim> ClaimList)
|
||||
public string ShowClaims(List<Claim> ClaimList)
|
||||
{
|
||||
string answ = string.Join(",", ConvertClaim(ClaimList));
|
||||
return answ;
|
||||
@@ -321,9 +321,9 @@ namespace WebDoorCreator.UI.Pages
|
||||
[Inject]
|
||||
private IConfiguration Configuration { get; set; } = null!;
|
||||
|
||||
private System.Security.Claims.Claim CurrentUserClaim
|
||||
private Claim CurrentUserClaim
|
||||
{
|
||||
get => new System.Security.Claims.Claim(CurrentUserClaimType, CurrentUserClaimVal);
|
||||
get => new Claim(CurrentUserClaimType, CurrentUserClaimVal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>0.9.2305.2910</Version>
|
||||
<Version>0.9.2305.2916</Version>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UserSecretsId>aspnet-WebDoorCreator.UI-dfe95fed-1398-4144-bd43-8b3a765d6608</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
Reference in New Issue
Block a user