Merge branch 'feature/backend-refactor' into feature/asc-elasticsearch-refactor

This commit is contained in:
Maksim Chegulov 2022-02-14 19:03:56 +03:00
commit b67d3cc11c
610 changed files with 13175 additions and 13208 deletions

2
.gitignore vendored
View File

@ -10,7 +10,7 @@
/build/deploy
*.log
/products/ASC.People/Data/
Data/
/Data
Logs/
**/.DS_Store
.eslintcache

View File

@ -1,107 +1,111 @@
using SecurityContext = ASC.Core.SecurityContext;
namespace ASC.Api.Core.Auth
namespace ASC.Api.Core.Auth;
[Scope(Additional = typeof(ConfirmAuthHandlerExtension))]
public class ConfirmAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
[Scope(Additional = typeof(ConfirmAuthHandlerExtension))]
public class ConfirmAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
private readonly SecurityContext _securityContext;
private readonly UserManager _userManager;
private readonly IServiceScopeFactory _serviceScopeFactory;
public ConfirmAuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock) :
base(options, logger, encoder, clock)
{ }
public ConfirmAuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
SecurityContext securityContext,
UserManager userManager,
IServiceScopeFactory serviceScopeFactory) :
base(options, logger, encoder, clock)
{
public ConfirmAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
_securityContext = securityContext;
_userManager = userManager;
_serviceScopeFactory = serviceScopeFactory;
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
using var scope = _serviceScopeFactory.CreateScope();
var emailValidationKeyHelper = scope.ServiceProvider.GetService<EmailValidationKeyModelHelper>();
var emailValidationKeyModel = emailValidationKeyHelper.GetModel();
if (!emailValidationKeyModel.Type.HasValue)
{
}
public ConfirmAuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
SecurityContext securityContext,
UserManager userManager,
IServiceProvider serviceProvider) :
base(options, logger, encoder, clock)
{
SecurityContext = securityContext;
UserManager = userManager;
ServiceProvider = serviceProvider;
return _securityContext.IsAuthenticated
? Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(Context.User, new AuthenticationProperties(), Scheme.Name)))
: Task.FromResult(AuthenticateResult.Fail(new AuthenticationException(nameof(HttpStatusCode.Unauthorized))));
}
private SecurityContext SecurityContext { get; }
private UserManager UserManager { get; }
private IServiceProvider ServiceProvider { get; }
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
EmailValidationKeyProvider.ValidationResult checkKeyResult;
try
{
using var scope = ServiceProvider.CreateScope();
checkKeyResult = emailValidationKeyHelper.Validate(emailValidationKeyModel);
}
catch (ArgumentNullException)
{
checkKeyResult = EmailValidationKeyProvider.ValidationResult.Invalid;
}
var emailValidationKeyHelper = scope.ServiceProvider.GetService<EmailValidationKeyModelHelper>();
var emailValidationKeyModel = emailValidationKeyHelper.GetModel();
if (!emailValidationKeyModel.Type.HasValue)
{
return SecurityContext.IsAuthenticated
? Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(Context.User, new AuthenticationProperties(), Scheme.Name)))
: Task.FromResult(AuthenticateResult.Fail(new AuthenticationException(HttpStatusCode.Unauthorized.ToString())));
}
EmailValidationKeyProvider.ValidationResult checkKeyResult;
try
{
checkKeyResult = emailValidationKeyHelper.Validate(emailValidationKeyModel);
}
catch (ArgumentNullException)
{
checkKeyResult = EmailValidationKeyProvider.ValidationResult.Invalid;
}
var claims = new List<Claim>()
{
var claims = new List<Claim>()
{
new Claim(ClaimTypes.Role, emailValidationKeyModel.Type.ToString())
};
};
if (checkKeyResult == EmailValidationKeyProvider.ValidationResult.Ok)
if (checkKeyResult == EmailValidationKeyProvider.ValidationResult.Ok)
{
Guid userId;
if (!_securityContext.IsAuthenticated)
{
Guid userId;
if (!SecurityContext.IsAuthenticated)
if (emailValidationKeyModel.UiD.HasValue && !emailValidationKeyModel.UiD.Equals(Guid.Empty))
{
if (emailValidationKeyModel.UiD.HasValue && !emailValidationKeyModel.UiD.Equals(Guid.Empty))
{
userId = emailValidationKeyModel.UiD.Value;
}
else
{
if(emailValidationKeyModel.Type == Web.Studio.Utility.ConfirmType.EmailActivation ||
emailValidationKeyModel.Type == Web.Studio.Utility.ConfirmType.EmpInvite ||
emailValidationKeyModel.Type == Web.Studio.Utility.ConfirmType.LinkInvite)
{
userId = ASC.Core.Configuration.Constants.CoreSystem.ID;
}
else
{
userId = UserManager.GetUserByEmail(emailValidationKeyModel.Email).ID;
}
}
userId = emailValidationKeyModel.UiD.Value;
}
else
{
userId = SecurityContext.CurrentAccount.ID;
if (emailValidationKeyModel.Type == ConfirmType.EmailActivation
|| emailValidationKeyModel.Type == ConfirmType.EmpInvite
|| emailValidationKeyModel.Type == ConfirmType.LinkInvite)
{
userId = ASC.Core.Configuration.Constants.CoreSystem.ID;
}
else
{
userId = _userManager.GetUserByEmail(emailValidationKeyModel.Email).ID;
}
}
SecurityContext.AuthenticateMeWithoutCookie(userId, claims);
}
else
{
userId = _securityContext.CurrentAccount.ID;
}
var result = checkKeyResult switch
{
EmailValidationKeyProvider.ValidationResult.Ok => AuthenticateResult.Success(new AuthenticationTicket(Context.User, new AuthenticationProperties(), Scheme.Name)),
_ => AuthenticateResult.Fail(new AuthenticationException(HttpStatusCode.Unauthorized.ToString()))
};
return Task.FromResult(result);
_securityContext.AuthenticateMeWithoutCookie(userId, claims);
}
}
public class ConfirmAuthHandlerExtension
{
public static void Register(DIHelper services)
var result = checkKeyResult switch
{
services.TryAdd<EmailValidationKeyModelHelper>();
}
EmailValidationKeyProvider.ValidationResult.Ok => AuthenticateResult.Success(new AuthenticationTicket(Context.User, new AuthenticationProperties(), Scheme.Name)),
_ => AuthenticateResult.Fail(new AuthenticationException(nameof(HttpStatusCode.Unauthorized)))
};
return Task.FromResult(result);
}
}
public static class ConfirmAuthHandlerExtension
{
public static void Register(DIHelper services)
{
services.TryAdd<EmailValidationKeyModelHelper>();
}
}

View File

@ -1,45 +1,46 @@
using SecurityContext = ASC.Core.SecurityContext;
namespace ASC.Api.Core.Auth
namespace ASC.Api.Core.Auth;
[Scope]
public class CookieAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
[Scope]
public class CookieAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
private readonly AuthorizationHelper _authorizationHelper;
private readonly SecurityContext _securityContext;
private readonly CookiesManager _cookiesManager;
public CookieAuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock)
: base(options, logger, encoder, clock) { }
public CookieAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock,
AuthorizationHelper authorizationHelper,
SecurityContext securityContext,
CookiesManager cookiesManager)
: this(options, logger, encoder, clock)
{
private AuthorizationHelper AuthorizationHelper { get; }
private SecurityContext SecurityContext { get; }
private CookiesManager CookiesManager { get; }
public CookieAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
}
//
public CookieAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock,
AuthorizationHelper authorizationHelper,
SecurityContext securityContext,
CookiesManager cookiesManager)
: this(options, logger, encoder, clock)
{
AuthorizationHelper = authorizationHelper;
SecurityContext = securityContext;
CookiesManager = cookiesManager;
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var result = AuthorizationHelper.ProcessBasicAuthorization(out _);
if (!result)
{
SecurityContext.Logout();
CookiesManager.ClearCookies(CookiesType.AuthKey);
CookiesManager.ClearCookies(CookiesType.SocketIO);
}
return Task.FromResult(
result ?
AuthenticateResult.Success(new AuthenticationTicket(Context.User, new AuthenticationProperties(), Scheme.Name)) :
AuthenticateResult.Fail(new AuthenticationException(HttpStatusCode.Unauthorized.ToString()))
);
}
_authorizationHelper = authorizationHelper;
_securityContext = securityContext;
_cookiesManager = cookiesManager;
}
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var result = _authorizationHelper.ProcessBasicAuthorization(out _);
if (!result)
{
_securityContext.Logout();
_cookiesManager.ClearCookies(CookiesType.AuthKey);
_cookiesManager.ClearCookies(CookiesType.SocketIO);
}
return Task.FromResult(
result ?
AuthenticateResult.Success(new AuthenticationTicket(Context.User, new AuthenticationProperties(), Scheme.Name)) :
AuthenticateResult.Fail(new AuthenticationException(nameof(HttpStatusCode.Unauthorized))));
}
}

View File

@ -1,25 +1,24 @@
namespace ASC.Api.Core.Convention
namespace ASC.Api.Core.Convention;
[AttributeUsage(AttributeTargets.Class)]
public class ControllerNameAttribute : Attribute
{
[AttributeUsage(AttributeTargets.Class)]
public class ControllerNameAttribute : Attribute
{
public string Name { get; }
public string Name { get; }
public ControllerNameAttribute(string name)
{
Name = name;
}
}
public class ControllerNameAttributeConvention : IControllerModelConvention
public ControllerNameAttribute(string name)
{
public void Apply(ControllerModel controller)
{
var controllerNameAttribute = controller.Attributes.OfType<ControllerNameAttribute>().SingleOrDefault();
if (controllerNameAttribute != null)
{
controller.ControllerName = controllerNameAttribute.Name;
}
}
Name = name;
}
}
public class ControllerNameAttributeConvention : IControllerModelConvention
{
public void Apply(ControllerModel controller)
{
var controllerNameAttribute = controller.Attributes.OfType<ControllerNameAttribute>().SingleOrDefault();
if (controllerNameAttribute != null)
{
controller.ControllerName = controllerNameAttribute.Name;
}
}
}

View File

@ -25,239 +25,245 @@
using SecurityContext = ASC.Core.SecurityContext;
namespace ASC.Api.Core
namespace ASC.Api.Core;
[Scope]
public class ApiContext : ICloneable
{
[Scope]
public class ApiContext : ICloneable
public IHttpContextAccessor HttpContextAccessor { get; set; }
public string[] Fields { get; set; }
public string[] FilterValues { get; set; }
public bool FromCache { get; set; }
public Tenant Tenant => _tenant ??= _tenantManager.GetCurrentTenant(HttpContextAccessor?.HttpContext);
public long? TotalCount
{
private static int MaxCount = 1000;
public IHttpContextAccessor HttpContextAccessor { get; set; }
public Tenant tenant;
public Tenant Tenant { get { return tenant ??= TenantManager.GetCurrentTenant(HttpContextAccessor?.HttpContext); } }
public ApiContext(IHttpContextAccessor httpContextAccessor, SecurityContext securityContext, TenantManager tenantManager)
set
{
SecurityContext = securityContext;
TenantManager = tenantManager;
HttpContextAccessor = httpContextAccessor;
if (httpContextAccessor.HttpContext == null) return;
Count = MaxCount;
var query = HttpContextAccessor.HttpContext.Request.Query;
//Try parse values
var count = query.GetRequestValue("count");
if (!string.IsNullOrEmpty(count) && ulong.TryParse(count, out var countParsed))
if (HttpContextAccessor.HttpContext.Items.ContainsKey(nameof(TotalCount)))
{
//Count specified and valid
Count = Math.Min((long)countParsed, MaxCount);
HttpContextAccessor.HttpContext.Items[nameof(TotalCount)] = value;
}
var startIndex = query.GetRequestValue("startIndex");
if (startIndex != null && long.TryParse(startIndex, out var startIndexParsed))
else
{
StartIndex = Math.Max(0, startIndexParsed);
SpecifiedStartIndex = StartIndex;
}
var sortOrder = query.GetRequestValue("sortOrder");
if ("descending".Equals(sortOrder))
{
SortDescending = true;
}
FilterToType = query.GetRequestValue("type");
SortBy = query.GetRequestValue("sortBy");
FilterBy = query.GetRequestValue("filterBy");
FilterOp = query.GetRequestValue("filterOp");
FilterValue = query.GetRequestValue("filterValue");
FilterValues = query.GetRequestArray("filterValue");
Fields = query.GetRequestArray("fields");
var updatedSince = query.GetRequestValue("updatedSince");
if (updatedSince != null)
{
UpdatedSince = Convert.ToDateTime(updatedSince);
}
}
public string[] Fields { get; set; }
public string[] FilterValues { get; set; }
/// <summary>
/// Filters responce to specific type from request parameter "type"
/// </summary>
/// <remarks>
/// The type name is retrieved from [DataContractAttribute] name
/// </remarks>
public string FilterToType { get; set; }
/// <summary>
/// Gets count to get item from collection. Request parameter "count"
/// </summary>
/// <remarks>
/// Don't forget to call _context.SetDataPaginated() to prevent SmartList from filtering response if you fetch data from DB with TOP & COUNT
/// </remarks>
public long Count { get; set; }
/// <summary>
/// Gets start index to get item from collection. Request parameter "startIndex"
/// </summary>
/// <remarks>
/// Don't forget to call _context.SetDataPaginated() to prevent SmartList from filtering response if you fetch data from DB with TOP & COUNT
/// </remarks>
public long StartIndex { get; set; }
internal long SpecifiedStartIndex { get; set; }
/// <summary>
/// Gets field to sort by from request parameter "sortBy"
/// </summary>
public string SortBy { get; set; }
/// <summary>
/// Gets field to filter from request parameter "filterBy"
/// </summary>
public string FilterBy { get; set; }
/// <summary>
/// Gets filter operation from request parameter "filterOp"
/// can be one of the following:"contains","equals","startsWith","present"
/// </summary>
public string FilterOp { get; set; }
/// <summary>
/// Gets value to filter from request parameter "filterValue"
/// </summary>
public string FilterValue { get; set; }
/// <summary>
/// Sort direction. From request parameter "sortOrder" can be "descending" or "ascending"
/// Like ...&sortOrder=descending&...
/// </summary>
public bool SortDescending { get; set; }
/// <summary>
/// Gets value to filter from request parameter "updatedSince"
/// </summary>
public DateTime UpdatedSince { get; set; }
public bool FromCache { get; set; }
internal long SpecifiedCount { get; private set; }
/// <summary>
/// Set mark that data is already paginated and additional filtering is not needed
/// </summary>
public ApiContext SetDataPaginated()
{
//Count = 0;//We always ask for +1 count so smart list should cut it
StartIndex = 0;
return this;
}
public ApiContext SetDataSorted()
{
SortBy = string.Empty;
return this;
}
public ApiContext SetDataFiltered()
{
FilterBy = string.Empty;
FilterOp = string.Empty;
FilterValue = string.Empty;
return this;
}
public ApiContext SetTotalCount(long totalCollectionCount)
{
TotalCount = totalCollectionCount;
return this;
}
public long? TotalCount
{
set
{
if (HttpContextAccessor.HttpContext.Items.ContainsKey(nameof(TotalCount)))
{
HttpContextAccessor.HttpContext.Items[nameof(TotalCount)] = value;
}
else
{
HttpContextAccessor.HttpContext.Items.Add(nameof(TotalCount), value);
}
}
}
private SecurityContext SecurityContext { get; }
private TenantManager TenantManager { get; }
public ApiContext SetCount(int count)
{
HttpContextAccessor.HttpContext.Items[nameof(Count)] = count;
return this;
}
public object Clone()
{
return MemberwiseClone();
}
public override string ToString()
{
return string.Format("C:{0},S:{1},So:{2},Sd:{3},Fb;{4},Fo:{5},Fv:{6},Us:{7},Ftt:{8}", Count, StartIndex,
SortBy, SortDescending, FilterBy, FilterOp, FilterValue, UpdatedSince.Ticks, FilterToType);
}
public void AuthByClaim()
{
var id = HttpContextAccessor.HttpContext.User.Claims.FirstOrDefault(r => r.Type == ClaimTypes.Sid);
if (Guid.TryParse(id?.Value, out var userId))
{
SecurityContext.AuthenticateMeWithoutCookie(userId);
HttpContextAccessor.HttpContext.Items.Add(nameof(TotalCount), value);
}
}
}
public static class QueryExtension
{
internal static string[] GetRequestArray(this IQueryCollection query, string key)
{
if (query != null)
{
var values = query[key + "[]"];
if (values.Count > 0)
return values;
/// <summary>
/// Filters responce to specific type from request parameter "type"
/// </summary>
/// <remarks>
/// The type name is retrieved from [DataContractAttribute] name
/// </remarks>
public string FilterToType { get; set; }
values = query[key];
if (values.Count > 0)
{
if (values.Count == 1) //If it's only one element
{
//Try split
if (!string.IsNullOrEmpty(values[0]))
return values[0].Split(',');
}
return values;
}
}
return null;
/// <summary>
/// Gets count to get item from collection. Request parameter "count"
/// </summary>
/// <remarks>
/// Don't forget to call _context.SetDataPaginated() to prevent SmartList from filtering response if you fetch data from DB with TOP & COUNT
/// </remarks>
public long Count { get; set; }
/// <summary>
/// Gets start index to get item from collection. Request parameter "startIndex"
/// </summary>
/// <remarks>
/// Don't forget to call _context.SetDataPaginated() to prevent SmartList from filtering response if you fetch data from DB with TOP & COUNT
/// </remarks>
public long StartIndex { get; set; }
/// <summary>
/// Gets field to sort by from request parameter "sortBy"
/// </summary>
public string SortBy { get; set; }
/// <summary>
/// Gets field to filter from request parameter "filterBy"
/// </summary>
public string FilterBy { get; set; }
/// <summary>
/// Gets filter operation from request parameter "filterOp"
/// can be one of the following:"contains","equals","startsWith","present"
/// </summary>
public string FilterOp { get; set; }
/// <summary>
/// Gets value to filter from request parameter "filterValue"
/// </summary>
public string FilterValue { get; set; }
/// <summary>
/// Sort direction. From request parameter "sortOrder" can be "descending" or "ascending"
/// Like ...&sortOrder=descending&...
/// </summary>
public bool SortDescending { get; set; }
/// <summary>
/// Gets value to filter from request parameter "updatedSince"
/// </summary>
public DateTime UpdatedSince { get; set; }
internal long SpecifiedCount { get; private set; }
internal long SpecifiedStartIndex { get; set; }
private Tenant _tenant;
private static int _maxCount = 1000;
private readonly SecurityContext _securityContext;
private readonly TenantManager _tenantManager;
public ApiContext(IHttpContextAccessor httpContextAccessor, SecurityContext securityContext, TenantManager tenantManager)
{
_securityContext = securityContext;
_tenantManager = tenantManager;
HttpContextAccessor = httpContextAccessor;
if (httpContextAccessor.HttpContext == null)
{
return;
}
public static string GetRequestValue(this IQueryCollection query, string key)
Count = _maxCount;
var query = HttpContextAccessor.HttpContext.Request.Query;
//Try parse values
var count = query.GetRequestValue("count");
if (!string.IsNullOrEmpty(count) && ulong.TryParse(count, out var countParsed))
{
var reqArray = query.GetRequestArray(key);
return reqArray?.FirstOrDefault();
//Count specified and valid
Count = Math.Min((long)countParsed, _maxCount);
}
var startIndex = query.GetRequestValue("startIndex");
if (startIndex != null && long.TryParse(startIndex, out var startIndexParsed))
{
StartIndex = Math.Max(0, startIndexParsed);
SpecifiedStartIndex = StartIndex;
}
var sortOrder = query.GetRequestValue("sortOrder");
if ("descending".Equals(sortOrder))
{
SortDescending = true;
}
FilterToType = query.GetRequestValue("type");
SortBy = query.GetRequestValue("sortBy");
FilterBy = query.GetRequestValue("filterBy");
FilterOp = query.GetRequestValue("filterOp");
FilterValue = query.GetRequestValue("filterValue");
FilterValues = query.GetRequestArray("filterValue");
Fields = query.GetRequestArray("fields");
var updatedSince = query.GetRequestValue("updatedSince");
if (updatedSince != null)
{
UpdatedSince = Convert.ToDateTime(updatedSince);
}
}
public static class ApiContextExtension
/// <summary>
/// Set mark that data is already paginated and additional filtering is not needed
/// </summary>
public ApiContext SetDataPaginated()
{
public static bool Check(this ApiContext context, string field)
//Count = 0;//We always ask for +1 count so smart list should cut it
StartIndex = 0;
return this;
}
public ApiContext SetDataSorted()
{
SortBy = string.Empty;
return this;
}
public ApiContext SetDataFiltered()
{
FilterBy = string.Empty;
FilterOp = string.Empty;
FilterValue = string.Empty;
return this;
}
public ApiContext SetTotalCount(long totalCollectionCount)
{
TotalCount = totalCollectionCount;
return this;
}
public ApiContext SetCount(int count)
{
HttpContextAccessor.HttpContext.Items[nameof(Count)] = count;
return this;
}
public object Clone()
{
return MemberwiseClone();
}
public override string ToString()
{
return string.Format("C:{0},S:{1},So:{2},Sd:{3},Fb;{4},Fo:{5},Fv:{6},Us:{7},Ftt:{8}", Count, StartIndex,
SortBy, SortDescending, FilterBy, FilterOp, FilterValue, UpdatedSince.Ticks, FilterToType);
}
public void AuthByClaim()
{
var id = HttpContextAccessor.HttpContext.User.Claims.FirstOrDefault(r => r.Type == ClaimTypes.Sid);
if (Guid.TryParse(id?.Value, out var userId))
{
return context?.Fields == null || (context.Fields != null && context.Fields.Contains(field, StringComparer.InvariantCultureIgnoreCase));
_securityContext.AuthenticateMeWithoutCookie(userId);
}
}
}
public static class QueryExtension
{
internal static string[] GetRequestArray(this IQueryCollection query, string key)
{
if (query != null)
{
var values = query[key + "[]"];
if (values.Count > 0) return values;
values = query[key];
if (values.Count > 0)
{
if (values.Count == 1) //If it's only one element
{
//Try split
if (!string.IsNullOrEmpty(values[0]))
return values[0].Split(',');
}
return values;
}
}
return null;
}
public static string GetRequestValue(this IQueryCollection query, string key)
{
var reqArray = query.GetRequestArray(key);
return reqArray?.FirstOrDefault();
}
}
public static class ApiContextExtension
{
public static bool Check(this ApiContext context, string field)
{
return context?.Fields == null
|| (context.Fields != null
&& context.Fields.Contains(field, StringComparer.InvariantCultureIgnoreCase));
}
}

View File

@ -23,335 +23,384 @@
*
*/
namespace ASC.Api.Core
namespace ASC.Api.Core;
[TypeConverter(typeof(ApiDateTimeTypeConverter))]
public sealed class ApiDateTime : IComparable<ApiDateTime>, IComparable
{
[TypeConverter(typeof(ApiDateTimeTypeConverter))]
public class ApiDateTime : IComparable<ApiDateTime>, IComparable
public DateTime UtcTime { get; private set; }
public TimeSpan TimeZoneOffset { get; private set; }
internal static readonly string[] Formats = new[]
{
internal static readonly string[] Formats = new[]
{
"o",
"yyyy'-'MM'-'dd'T'HH'-'mm'-'ss'.'fffffffK",
"yyyy'-'MM'-'dd'T'HH'-'mm'-'ss'.'fffK",
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK",
"yyyy'-'MM'-'dd'T'HH'-'mm'-'ssK",
"yyyy'-'MM'-'dd'T'HH':'mm':'ssK",
"yyyy'-'MM'-'dd"
};
"o",
"yyyy'-'MM'-'dd'T'HH'-'mm'-'ss'.'fffffffK",
"yyyy'-'MM'-'dd'T'HH'-'mm'-'ss'.'fffK",
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK",
"yyyy'-'MM'-'dd'T'HH'-'mm'-'ssK",
"yyyy'-'MM'-'dd'T'HH':'mm':'ssK",
"yyyy'-'MM'-'dd"
};
public ApiDateTime()
: this(null, null, null)
private readonly TenantManager _tenantManager;
private readonly TimeZoneConverter _timeZoneConverter;
public ApiDateTime() : this(null, null, null) { }
public ApiDateTime(
TenantManager tenantManager,
TimeZoneConverter timeZoneConverter,
DateTime? dateTime)
: this(tenantManager, dateTime, null, timeZoneConverter) { }
public ApiDateTime(
TenantManager tenantManager,
DateTime? dateTime,
TimeZoneInfo timeZone,
TimeZoneConverter timeZoneConverter)
{
if (dateTime.HasValue && dateTime.Value > DateTime.MinValue && dateTime.Value < DateTime.MaxValue)
{
_tenantManager = tenantManager;
_timeZoneConverter = timeZoneConverter;
SetDate(dateTime.Value, timeZone);
}
public ApiDateTime(TenantManager tenantManager, TimeZoneConverter timeZoneConverter, DateTime? dateTime)
: this(tenantManager, dateTime, null, timeZoneConverter)
else
{
}
public ApiDateTime(TenantManager tenantManager, DateTime? dateTime, TimeZoneInfo timeZone, TimeZoneConverter timeZoneConverter)
{
if (dateTime.HasValue && dateTime.Value > DateTime.MinValue && dateTime.Value < DateTime.MaxValue)
{
TenantManager = tenantManager;
TimeZoneConverter = timeZoneConverter;
SetDate(dateTime.Value, timeZone);
}
else
{
UtcTime = DateTime.MinValue;
TimeZoneOffset = TimeSpan.Zero;
}
}
public ApiDateTime(DateTime utcTime, TimeSpan offset)
{
UtcTime = new DateTime(utcTime.Ticks, DateTimeKind.Utc);
TimeZoneOffset = offset;
}
public static ApiDateTime Parse(string data, TenantManager tenantManager, TimeZoneConverter timeZoneConverter)
{
return Parse(data, null, tenantManager, timeZoneConverter);
}
public static ApiDateTime Parse(string data, TimeZoneInfo tz, TenantManager tenantManager, TimeZoneConverter timeZoneConverter)
{
if (string.IsNullOrEmpty(data)) throw new ArgumentNullException("data");
if (data.Length < 7) throw new ArgumentException("invalid date time format");
var offsetPart = data.Substring(data.Length - 6, 6);
if (DateTime.TryParseExact(data, Formats, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out var dateTime))
{
//Parse time
var tzOffset = TimeSpan.Zero;
if (offsetPart.Contains(":") && TimeSpan.TryParse(offsetPart.TrimStart('+'), out tzOffset))
{
return new ApiDateTime(dateTime, tzOffset);
}
if (!data.EndsWith("Z", true, CultureInfo.InvariantCulture))
{
if (tz == null)
{
tz = GetTimeZoneInfo(tenantManager, timeZoneConverter);
}
tzOffset = tz.GetUtcOffset(dateTime);
dateTime = dateTime.Subtract(tzOffset);
}
return new ApiDateTime(dateTime, tzOffset);
}
throw new ArgumentException("invalid date time format: " + data);
}
private void SetDate(DateTime value, TimeZoneInfo timeZone)
{
TimeZoneOffset = TimeSpan.Zero;
UtcTime = DateTime.MinValue;
if (timeZone == null)
{
timeZone = GetTimeZoneInfo(TenantManager, TimeZoneConverter);
}
//Hack
if (timeZone.IsInvalidTime(new DateTime(value.Ticks, DateTimeKind.Unspecified)))
{
value = value.AddHours(1);
}
if (value.Kind == DateTimeKind.Local)
{
value = TimeZoneInfo.ConvertTimeToUtc(new DateTime(value.Ticks, DateTimeKind.Unspecified), timeZone);
}
if (value.Kind == DateTimeKind.Unspecified)
{
//Assume it's utc
value = new DateTime(value.Ticks, DateTimeKind.Utc);
}
if (value.Kind == DateTimeKind.Utc)
{
UtcTime = value; //Set UTC time
TimeZoneOffset = timeZone.GetUtcOffset(value);
}
TimeZoneOffset = TimeSpan.Zero;
}
}
private static TimeZoneInfo GetTimeZoneInfo(TenantManager tenantManager, TimeZoneConverter timeZoneConverter)
public ApiDateTime(DateTime utcTime, TimeSpan offset)
{
UtcTime = new DateTime(utcTime.Ticks, DateTimeKind.Utc);
TimeZoneOffset = offset;
}
public static ApiDateTime Parse(string data, TenantManager tenantManager, TimeZoneConverter timeZoneConverter)
{
return Parse(data, null, tenantManager, timeZoneConverter);
}
public static ApiDateTime Parse(string data, TimeZoneInfo tz, TenantManager tenantManager, TimeZoneConverter timeZoneConverter)
{
if (string.IsNullOrEmpty(data)) throw new ArgumentNullException(nameof(data));
var offsetPart = data.Substring(data.Length - 6, 6);
if (DateTime.TryParseExact(data, Formats, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out var dateTime))
{
var timeZone = TimeZoneInfo.Local;
try
//Parse time
var tzOffset = TimeSpan.Zero;
if (offsetPart.Contains(':') && TimeSpan.TryParse(offsetPart.TrimStart('+'), out tzOffset))
{
timeZone = timeZoneConverter.GetTimeZone(tenantManager.GetCurrentTenant().TimeZone);
return new ApiDateTime(dateTime, tzOffset);
}
catch (Exception)
if (!data.EndsWith("Z", true, CultureInfo.InvariantCulture))
{
//Tenant failed
if (tz == null)
{
tz = GetTimeZoneInfo(tenantManager, timeZoneConverter);
}
tzOffset = tz.GetUtcOffset(dateTime);
dateTime = dateTime.Subtract(tzOffset);
}
return timeZone;
return new ApiDateTime(dateTime, tzOffset);
}
private string ToRoundTripString(DateTime date, TimeSpan offset)
throw new ArgumentException("invalid date time format: " + data);
}
private void SetDate(DateTime value, TimeZoneInfo timeZone)
{
TimeZoneOffset = TimeSpan.Zero;
UtcTime = DateTime.MinValue;
if (timeZone == null)
{
var dateString = date.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffff", CultureInfo.InvariantCulture);
var offsetString = offset.Ticks == 0 ? "Z" : ((offset < TimeSpan.Zero) ? "-" : "+") + offset.ToString("hh\\:mm", CultureInfo.InvariantCulture);
return dateString + offsetString;
timeZone = GetTimeZoneInfo(_tenantManager, _timeZoneConverter);
}
public static ApiDateTime FromDate(TenantManager tenantManager, TimeZoneConverter timeZoneConverter, DateTime d)
//Hack
if (timeZone.IsInvalidTime(new DateTime(value.Ticks, DateTimeKind.Unspecified)))
{
value = value.AddHours(1);
}
if (value.Kind == DateTimeKind.Local)
{
value = TimeZoneInfo.ConvertTimeToUtc(new DateTime(value.Ticks, DateTimeKind.Unspecified), timeZone);
}
if (value.Kind == DateTimeKind.Unspecified)
{
value = new DateTime(value.Ticks, DateTimeKind.Utc); //Assume it's utc
}
if (value.Kind == DateTimeKind.Utc)
{
UtcTime = value; //Set UTC time
TimeZoneOffset = timeZone.GetUtcOffset(value);
}
}
private static TimeZoneInfo GetTimeZoneInfo(TenantManager tenantManager, TimeZoneConverter timeZoneConverter)
{
var timeZone = TimeZoneInfo.Local;
try
{
timeZone = timeZoneConverter.GetTimeZone(tenantManager.GetCurrentTenant().TimeZone);
}
catch (Exception)
{
//Tenant failed
}
return timeZone;
}
private string ToRoundTripString(DateTime date, TimeSpan offset)
{
var dateString = date.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffff", CultureInfo.InvariantCulture);
var offsetString = offset.Ticks == 0
? "Z" : ((offset < TimeSpan.Zero)
? "-" : "+") + offset.ToString("hh\\:mm", CultureInfo.InvariantCulture);
return dateString + offsetString;
}
public static ApiDateTime FromDate(TenantManager tenantManager, TimeZoneConverter timeZoneConverter, DateTime d)
{
var date = new ApiDateTime(tenantManager, timeZoneConverter, d);
return date;
}
public static ApiDateTime FromDate(TenantManager tenantManager, TimeZoneConverter timeZoneConverter, DateTime? d)
{
if (d.HasValue)
{
var date = new ApiDateTime(tenantManager, timeZoneConverter, d);
return date;
}
public static ApiDateTime FromDate(TenantManager tenantManager, TimeZoneConverter timeZoneConverter, DateTime? d)
return null;
}
public static bool operator >(ApiDateTime left, ApiDateTime right)
{
if (ReferenceEquals(left, right))
{
return false;
}
if (left == null)
{
return false;
}
return left.CompareTo(right) > 0;
}
public static bool operator >=(ApiDateTime left, ApiDateTime right)
{
if (ReferenceEquals(left, right))
{
return false;
}
if (left == null)
{
return false;
}
return left.CompareTo(right) >= 0;
}
public static bool operator <=(ApiDateTime left, ApiDateTime right)
{
return !(left >= right);
}
public static bool operator <(ApiDateTime left, ApiDateTime right)
{
return !(left > right);
}
public static bool operator ==(ApiDateTime left, ApiDateTime right)
{
return Equals(left, right);
}
public static bool operator !=(ApiDateTime left, ApiDateTime right)
{
return !(left == right);
}
public static implicit operator DateTime(ApiDateTime d)
{
if (d == null)
{
return DateTime.MinValue;
}
return d.UtcTime;
}
public static implicit operator DateTime?(ApiDateTime d)
{
if (d == null)
{
if (d.HasValue)
{
var date = new ApiDateTime(tenantManager, timeZoneConverter, d);
return date;
}
return null;
}
return d.UtcTime;
}
public static bool operator >(ApiDateTime left, ApiDateTime right)
public int CompareTo(DateTime other)
{
return CompareTo(new ApiDateTime(_tenantManager, _timeZoneConverter, other));
}
public int CompareTo(ApiDateTime other)
{
if (other == null)
{
if (ReferenceEquals(left, right)) return false;
if (left == null) return false;
return left.CompareTo(right) > 0;
}
public static bool operator >=(ApiDateTime left, ApiDateTime right)
{
if (ReferenceEquals(left, right)) return false;
if (left == null) return false;
return left.CompareTo(right) >= 0;
return 1;
}
public static bool operator <=(ApiDateTime left, ApiDateTime right)
{
return !(left >= right);
}
return UtcTime.CompareTo(other.UtcTime);
}
public static bool operator <(ApiDateTime left, ApiDateTime right)
{
return !(left > right);
}
public static bool operator ==(ApiDateTime left, ApiDateTime right)
{
return Equals(left, right);
}
public static bool operator !=(ApiDateTime left, ApiDateTime right)
{
return !(left == right);
}
public static implicit operator DateTime(ApiDateTime d)
{
if (d == null) return DateTime.MinValue;
return d.UtcTime;
}
public static implicit operator DateTime?(ApiDateTime d)
{
if (d == null) return null;
return d.UtcTime;
}
public int CompareTo(DateTime other)
{
return CompareTo(new ApiDateTime(TenantManager, TimeZoneConverter, other));
}
public int CompareTo(ApiDateTime other)
{
if (other == null) return 1;
return UtcTime.CompareTo(other.UtcTime);
}
public override bool Equals(object obj)
{
public override bool Equals(object obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != typeof(ApiDateTime)) return false;
return Equals((ApiDateTime)obj);
if (!(obj is ApiDateTime)) return false;
return Equals((ApiDateTime)obj);
}
public bool Equals(ApiDateTime other)
{
if (other is null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
public bool Equals(ApiDateTime other)
return UtcTime.Equals(other.UtcTime) && TimeZoneOffset.Equals(other.TimeZoneOffset);
}
public override int GetHashCode()
{
unchecked
{
if (other is null) return false;
if (ReferenceEquals(this, other)) return true;
return UtcTime.Equals(other.UtcTime) && TimeZoneOffset.Equals(other.TimeZoneOffset);
}
public override int GetHashCode()
{
unchecked
{
return UtcTime.GetHashCode() * 397 + TimeZoneOffset.GetHashCode();
}
}
public int CompareTo(object obj)
{
if (obj is DateTime dateTime)
return CompareTo(dateTime);
return obj is ApiDateTime apiDateTime ? CompareTo(apiDateTime) : 0;
}
public override string ToString()
{
var localUtcTime = UtcTime;
if (!UtcTime.Equals(DateTime.MinValue))
localUtcTime = UtcTime.Add(TimeZoneOffset);
return ToRoundTripString(localUtcTime, TimeZoneOffset);
}
public DateTime UtcTime { get; private set; }
public TimeSpan TimeZoneOffset { get; private set; }
private TenantManager TenantManager { get; }
private TimeZoneConverter TimeZoneConverter { get; }
public static ApiDateTime GetSample()
{
return new ApiDateTime(DateTime.UtcNow, TimeSpan.Zero);
return UtcTime.GetHashCode() * 397 + TimeZoneOffset.GetHashCode();
}
}
public class ApiDateTimeTypeConverter : DateTimeConverter
public int CompareTo(object obj)
{
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
if (obj is DateTime dateTime)
{
if (destinationType == typeof(string))
return value.ToString();
return base.ConvertTo(context, culture, value, destinationType);
return CompareTo(dateTime);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string @string)
{
return ApiDateTime.Parse(@string, null, null);
}
if (value is DateTime time)
{
return new ApiDateTime(null, null, time);
}
return base.ConvertFrom(context, culture, value);
}
return obj is ApiDateTime apiDateTime ? CompareTo(apiDateTime) : 0;
}
public class ApiDateTimeConverter : System.Text.Json.Serialization.JsonConverter<ApiDateTime>
public override string ToString()
{
public override ApiDateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
var localUtcTime = UtcTime;
if (!UtcTime.Equals(DateTime.MinValue))
{
if (reader.TryGetDateTime(out var result))
localUtcTime = UtcTime.Add(TimeZoneOffset);
}
return ToRoundTripString(localUtcTime, TimeZoneOffset);
}
public static ApiDateTime GetSample()
{
return new ApiDateTime(DateTime.UtcNow, TimeSpan.Zero);
}
}
public class ApiDateTimeTypeConverter : DateTimeConverter
{
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
return value.ToString();
}
return base.ConvertTo(context, culture, value, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string @string)
{
return ApiDateTime.Parse(@string, null, null);
}
if (value is DateTime time)
{
return new ApiDateTime(null, null, time);
}
return base.ConvertFrom(context, culture, value);
}
}
public class ApiDateTimeConverter : System.Text.Json.Serialization.JsonConverter<ApiDateTime>
{
public override ApiDateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TryGetDateTime(out var result))
{
return new ApiDateTime(result, TimeSpan.Zero);
}
else
{
if (DateTime.TryParseExact(reader.GetString(), ApiDateTime.Formats,
CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var dateTime))
{
return new ApiDateTime(result, TimeSpan.Zero);
return new ApiDateTime(dateTime, TimeSpan.Zero);
}
else
{
if (DateTime.TryParseExact(reader.GetString(), ApiDateTime.Formats, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var dateTime))
{
return new ApiDateTime(dateTime, TimeSpan.Zero);
}
else
{
return new ApiDateTime();
}
}
}
public override void Write(Utf8JsonWriter writer, ApiDateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
return new ApiDateTime();
}
}
}
[Scope]
public class ApiDateTimeHelper
public override void Write(Utf8JsonWriter writer, ApiDateTime value, JsonSerializerOptions options)
{
private TenantManager TenantManager { get; }
private TimeZoneConverter TimeZoneConverter { get; }
writer.WriteStringValue(value.ToString());
}
}
public ApiDateTimeHelper(TenantManager tenantManager, TimeZoneConverter timeZoneConverter)
{
TenantManager = tenantManager;
TimeZoneConverter = timeZoneConverter;
}
[Scope]
public class ApiDateTimeHelper
{
private readonly TenantManager _tenantManager;
private readonly TimeZoneConverter _timeZoneConverter;
public ApiDateTime Get(DateTime? from)
{
return ApiDateTime.FromDate(TenantManager, TimeZoneConverter, from);
}
public ApiDateTimeHelper(TenantManager tenantManager, TimeZoneConverter timeZoneConverter)
{
_tenantManager = tenantManager;
_timeZoneConverter = timeZoneConverter;
}
public ApiDateTime Get(DateTime? from)
{
return ApiDateTime.FromDate(_tenantManager, _timeZoneConverter, from);
}
}

View File

@ -1,24 +1,25 @@
using JsonConverter = System.Text.Json.Serialization.JsonConverter;
namespace ASC.Api.Core
namespace ASC.Api.Core;
public abstract class BaseStartup
{
public abstract class BaseStartup
{
public IConfiguration Configuration { get; }
public IHostEnvironment HostEnvironment { get; }
public virtual JsonConverter[] Converters { get; }
public virtual bool AddControllersAsServices { get; } = false;
public IConfiguration Configuration { get; }
public IHostEnvironment HostEnvironment { get; }
public virtual JsonConverter[] Converters { get; }
public virtual bool AddControllersAsServices { get; } = false;
public virtual bool ConfirmAddScheme { get; } = false;
public virtual bool AddAndUseSession { get; } = false;
protected DIHelper DIHelper { get; }
protected DIHelper DIHelper { get; }
protected bool LoadProducts { get; set; } = true;
protected bool LoadConsumers { get; } = true;
public BaseStartup(IConfiguration configuration, IHostEnvironment hostEnvironment)
{
Configuration = configuration;
protected bool LoadConsumers { get; } = true;
public BaseStartup(IConfiguration configuration, IHostEnvironment hostEnvironment)
{
Configuration = configuration;
HostEnvironment = hostEnvironment;
DIHelper = new DIHelper();
DIHelper = new DIHelper();
if (bool.TryParse(Configuration["core:products"], out var loadProducts))
{
LoadProducts = loadProducts;
@ -26,16 +27,19 @@ namespace ASC.Api.Core
}
public virtual void ConfigureServices(IServiceCollection services)
{
{
services.AddCustomHealthCheck(Configuration);
services.AddHttpContextAccessor();
services.AddMemoryCache();
services.AddHttpClient();
if (AddAndUseSession)
{
services.AddSession();
}
DIHelper.Configure(services);
Action<JsonOptions> jsonOptions = options =>
{
options.JsonSerializerOptions.WriteIndented = false;
@ -43,11 +47,11 @@ namespace ASC.Api.Core
options.JsonSerializerOptions.Converters.Add(new ApiDateTimeConverter());
if (Converters != null)
{
{
foreach (var c in Converters)
{
options.JsonSerializerOptions.Converters.Add(c);
}
}
}
};
@ -72,11 +76,11 @@ namespace ASC.Api.Core
if (kafkaConfiguration != null)
{
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(KafkaCache<>));
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(KafkaCacheNotify<>));
}
else if (redisConfiguration != null)
{
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(RedisCache<>));
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(RedisCacheNotify<>));
services.AddStackExchangeRedisExtensions<NewtonsoftSerializer>(redisConfiguration);
}
@ -85,70 +89,71 @@ namespace ASC.Api.Core
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(MemoryCacheNotify<>));
}
DIHelper.TryAdd(typeof(IWebhookPublisher), typeof(WebhookPublisher));
if (LoadProducts)
{
DIHelper.RegisterProducts(Configuration, HostEnvironment.ContentRootPath);
}
services.AddMvcCore(config =>
{
config.Conventions.Add(new ControllerNameAttributeConvention());
var builder = services.AddMvcCore(config =>
{
config.Conventions.Add(new ControllerNameAttributeConvention());
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
config.Filters.Add(new AuthorizeFilter(policy));
config.Filters.Add(new TypeFilterAttribute(typeof(TenantStatusFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(PaymentFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(IpSecurityFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(ProductSecurityFilter)));
config.Filters.Add(new CustomResponseFilterAttribute());
config.Filters.Add(new CustomExceptionFilterAttribute());
config.Filters.Add(new TypeFilterAttribute(typeof(FormatFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(WebhooksGlobalFilterAttribute)));
config.OutputFormatters.RemoveType<XmlSerializerOutputFormatter>();
config.OutputFormatters.Add(new XmlOutputFormatter());
config.Filters.Add(new AuthorizeFilter(policy));
config.Filters.Add(new TypeFilterAttribute(typeof(TenantStatusFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(PaymentFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(IpSecurityFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(ProductSecurityFilter)));
config.Filters.Add(new CustomResponseFilterAttribute());
config.Filters.Add(new CustomExceptionFilterAttribute());
config.Filters.Add(new TypeFilterAttribute(typeof(FormatFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(WebhooksGlobalFilterAttribute)));
config.OutputFormatters.RemoveType<XmlSerializerOutputFormatter>();
config.OutputFormatters.Add(new XmlOutputFormatter());
});
var authBuilder = services.AddAuthentication("cookie")
.AddScheme<AuthenticationSchemeOptions, CookieAuthHandler>("cookie", a => { });
if (ConfirmAddScheme)
if (ConfirmAddScheme)
{
authBuilder.AddScheme<AuthenticationSchemeOptions, ConfirmAuthHandler>("confirm", a => { });
}
services.AddAutoMapper(Assembly.GetAssembly(typeof(MappingProfile)));
authBuilder.AddScheme<AuthenticationSchemeOptions, ConfirmAuthHandler>("confirm", a => { });
}
services.AddAutoMapper(Assembly.GetAssembly(typeof(MappingProfile)));
}
public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseRouting();
app.UseRouting();
if (AddAndUseSession)
{
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
app.UseCultureMiddleware();
app.UseDisposeMiddleware();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapCustom();
}
app.UseAuthentication();
app.UseAuthorization();
app.UseCultureMiddleware();
app.UseDisposeMiddleware();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapCustom();
endpoints.MapHealthChecks("/health", new HealthCheckOptions()
{
@ -158,25 +163,25 @@ namespace ASC.Api.Core
endpoints.MapHealthChecks("/liveness", new HealthCheckOptions
{
Predicate = r => r.Name.Contains("self")
});
});
});
});
}
public void ConfigureContainer(ContainerBuilder builder)
{
builder.Register(Configuration, LoadProducts, LoadConsumers);
}
}
builder.Register(Configuration, LoadProducts, LoadConsumers);
}
}
public static class LogNLogConfigureExtenstion
{
public static class LogNLogConfigureExtenstion
{
public static IHostBuilder ConfigureNLogLogging(this IHostBuilder hostBuilder)
{
return hostBuilder.ConfigureLogging((hostBuildexContext, r) =>
{
_ = new ConfigureLogNLog(hostBuildexContext.Configuration, new ConfigurationExtension(hostBuildexContext.Configuration), hostBuildexContext.HostingEnvironment);
_ = new ConfigureLogNLog(hostBuildexContext.Configuration,
new ConfigurationExtension(hostBuildexContext.Configuration), hostBuildexContext.HostingEnvironment);
r.AddNLog(LogManager.Configuration);
});
}
}
}

View File

@ -1,36 +1,35 @@
namespace ASC.Api.Core
{
public class BaseWorkerStartup
{
public IConfiguration Configuration { get; }
namespace ASC.Api.Core;
public BaseWorkerStartup(IConfiguration configuration)
{
Configuration = configuration;
}
public virtual void ConfigureServices(IServiceCollection services)
public class BaseWorkerStartup
{
public IConfiguration Configuration { get; }
public BaseWorkerStartup(IConfiguration configuration)
{
Configuration = configuration;
}
public virtual void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddCustomHealthCheck(Configuration);
}
public virtual void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
services.AddHttpContextAccessor();
services.AddCustomHealthCheck(Configuration);
}
public virtual void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHealthChecks("/health", new HealthCheckOptions()
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
endpoints.MapHealthChecks("/liveness", new HealthCheckOptions
{
Predicate = r => r.Name.Contains("self")
});
});
}
}
endpoints.MapHealthChecks("/health", new HealthCheckOptions()
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
endpoints.MapHealthChecks("/liveness", new HealthCheckOptions
{
Predicate = r => r.Name.Contains("self")
});
});
}
}

View File

@ -1,49 +1,50 @@
namespace ASC.Api.Core.Core
namespace ASC.Api.Core.Core;
public class CustomEndpointDataSource : EndpointDataSource
{
public class CustomEndpointDataSource : EndpointDataSource
public EndpointDataSource Source { get; }
public override IReadOnlyList<Endpoint> Endpoints { get; }
public CustomEndpointDataSource(EndpointDataSource source)
{
public EndpointDataSource Source { get; }
Source = source;
var endpoints = Source.Endpoints.Cast<RouteEndpoint>();
Endpoints = endpoints
.SelectMany(r =>
{
var endpoints = new List<RouteEndpoint>();
public override IReadOnlyList<Endpoint> Endpoints { get; }
public CustomEndpointDataSource(EndpointDataSource source)
{
Source = source;
var endpoints = Source.Endpoints.Cast<RouteEndpoint>();
Endpoints = endpoints
.SelectMany(r =>
var attr = r.Metadata.OfType<CustomHttpMethodAttribute>().FirstOrDefault();
var enableFormat = attr == null || !attr.DisableFormat;
if (enableFormat)
{
var endpoints = new List<RouteEndpoint>();
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText
+ ".{format}"), r.Order, r.Metadata, r.DisplayName));
}
else
{
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".json"), r.Order - 1, r.Metadata, r.DisplayName));
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".xml"), r.Order - 1, r.Metadata, r.DisplayName));
}
return endpoints;
var attr = r.Metadata.OfType<CustomHttpMethodAttribute>().FirstOrDefault();
var enableFormat = attr == null || !attr.DisableFormat;
if (enableFormat)
{
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".{format}"), r.Order, r.Metadata, r.DisplayName));
}
else
{
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".json"), r.Order - 1, r.Metadata, r.DisplayName));
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".xml"), r.Order - 1, r.Metadata, r.DisplayName));
}
return endpoints;
})
.ToList();
}
public override IChangeToken GetChangeToken()
{
return Source.GetChangeToken();
}
}).ToList();
}
public static class EndpointExtension
public override IChangeToken GetChangeToken()
{
public static IEndpointRouteBuilder MapCustom(this IEndpointRouteBuilder endpoints)
{
endpoints.DataSources.Add(new CustomEndpointDataSource(endpoints.DataSources.First()));
return endpoints;
}
return Source.GetChangeToken();
}
}
public static class EndpointExtension
{
public static IEndpointRouteBuilder MapCustom(this IEndpointRouteBuilder endpoints)
{
endpoints.DataSources.Add(new CustomEndpointDataSource(endpoints.DataSources.First()));
return endpoints;
}
}

View File

@ -1,64 +1,58 @@
namespace ASC.Api.Core.Core
namespace ASC.Api.Core.Core;
public static class CustomHealthCheck
{
public static class CustomHealthCheck
public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration)
{
public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration)
var hcBuilder = services.AddHealthChecks();
hcBuilder.AddCheck("self", () => HealthCheckResult.Healthy());
var configurationExtension = new ConfigurationExtension(configuration);
var connectionString = configurationExtension.GetConnectionStrings("default");
if (string.Equals(connectionString.ProviderName, "MySql.Data.MySqlClient"))
{
hcBuilder.AddMySql(connectionString.ConnectionString,
name: "mysqldb",
tags: new string[] { "mysqldb" });
}
if (string.Equals(connectionString.ProviderName, "Npgsql"))
{
hcBuilder.AddNpgSql(connectionString.ConnectionString,
name: "postgredb",
tags: new string[] { "postgredb" });
}
var kafkaSettings = configurationExtension.GetSetting<KafkaSettings>("kafka");
if (kafkaSettings != null && !string.IsNullOrEmpty(kafkaSettings.BootstrapServers))
{
var hcBuilder = services.AddHealthChecks();
var clientConfig = new ClientConfig { BootstrapServers = kafkaSettings.BootstrapServers };
hcBuilder.AddCheck("self", () => HealthCheckResult.Healthy());
hcBuilder.AddKafka(new ProducerConfig(clientConfig),
name: "kafka",
tags: new string[] { "kafka" });
var configurationExtension = new ConfigurationExtension(configuration);
var connectionString = configurationExtension.GetConnectionStrings("default");
if (String.Compare(connectionString.ProviderName, "MySql.Data.MySqlClient") == 0)
{
hcBuilder.AddMySql(connectionString.ConnectionString,
name: "mysqldb",
tags: new string[] { "mysqldb" }
);
}
if (String.Compare(connectionString.ProviderName, "Npgsql") == 0)
{
hcBuilder.AddNpgSql(connectionString.ConnectionString,
name: "postgredb",
tags: new string[] { "postgredb" }
);
}
var kafkaSettings = configurationExtension.GetSetting<KafkaSettings>("kafka");
if (kafkaSettings != null && !string.IsNullOrEmpty(kafkaSettings.BootstrapServers))
{
var clientConfig = new ClientConfig { BootstrapServers = kafkaSettings.BootstrapServers };
hcBuilder.AddKafka(new ProducerConfig(clientConfig),
name: "kafka",
tags: new string[] { "kafka" });
}
var elasticSettings = configuration.GetSection("elastic");
if (elasticSettings != null && elasticSettings.GetChildren().Any())
{
var host = elasticSettings.GetSection("Host").Value ?? "localhost";
var scheme = elasticSettings.GetSection("Scheme").Value ?? "http";
var port = elasticSettings.GetSection("Port").Value ?? "9200";
var elasticSearchUri = $"{scheme}://{host}:{port}";
if (Uri.IsWellFormedUriString(elasticSearchUri, UriKind.Absolute))
{
hcBuilder.AddElasticsearch(elasticSearchUri,
name: "elasticsearch",
tags: new string[] { "elasticsearch" });
}
}
return services;
}
var elasticSettings = configuration.GetSection("elastic");
if (elasticSettings != null && elasticSettings.GetChildren().Any())
{
var host = elasticSettings.GetSection("Host").Value ?? "localhost";
var scheme = elasticSettings.GetSection("Scheme").Value ?? "http";
var port = elasticSettings.GetSection("Port").Value ?? "9200";
var elasticSearchUri = $"{scheme}://{host}:{port}";
if (Uri.IsWellFormedUriString(elasticSearchUri, UriKind.Absolute))
{
hcBuilder.AddElasticsearch(elasticSearchUri,
name: "elasticsearch",
tags: new string[] { "elasticsearch" });
}
}
return services;
}
}

View File

@ -23,18 +23,13 @@
*
*/
namespace ASC.Api.Collections
{
[CollectionDataContract(Name = "hash", Namespace = "", ItemName = "entry", KeyName = "key", ValueName = "value")]
public class ItemDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
public ItemDictionary()
{
}
namespace ASC.Api.Collections;
public ItemDictionary(IDictionary<TKey, TValue> items)
: base(items)
{
}
}
[CollectionDataContract(Name = "hash", Namespace = "", ItemName = "entry", KeyName = "key", ValueName = "value")]
public class ItemDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
public ItemDictionary() { }
public ItemDictionary(IDictionary<TKey, TValue> items)
: base(items) { }
}

View File

@ -23,15 +23,10 @@
*
*/
namespace ASC.Api.Collections
namespace ASC.Api.Collections;
public class ItemKeyValuePair<TKey, TValue>
{
public class ItemKeyValuePair<TKey, TValue>
{
public TKey Key { get; set; }
public TValue Value { get; set; }
}
}
public TKey Key { get; set; }
public TValue Value { get; set; }
}

View File

@ -1,31 +1,27 @@
namespace ASC.Api.Core
{
public class Module
{
public Guid Id { get; set; }
namespace ASC.Api.Core;
public string AppName { get; set; }
public string Title { get; set; }
public string Link { get; set; }
public class Module
{
public Guid Id { get; set; }
public string AppName { get; set; }
public string Title { get; set; }
public string Link { get; set; }
public string IconUrl { get; set; }
public string ImageUrl { get; set; }
public string HelpUrl { get; set; }
public string Description { get; set; }
public bool IsPrimary { get; set; }
public string IconUrl { get; set; }
public string ImageUrl { get; set; }
public string HelpUrl { get; set; }
public string Description { get; set; }
public bool IsPrimary { get; set; }
public Module(Product product)
{
Id = product.ProductID;
AppName = product.ProductClassName;
Title = product.Name;
Description = product.Description;
IconUrl = product.Context.IconFileName;
ImageUrl = product.Context.LargeIconFileName;
Link = product.StartURL;
IsPrimary = product.IsPrimary;
HelpUrl = product.HelpURL;
}
}
}
public Module(Product product)
{
Id = product.ProductID;
AppName = product.ProductClassName;
Title = product.Name;
Description = product.Description;
IconUrl = product.Context.IconFileName;
ImageUrl = product.Context.LargeIconFileName;
Link = product.StartURL;
IsPrimary = product.IsPrimary;
HelpUrl = product.HelpURL;
}
}

View File

@ -24,28 +24,23 @@
*/
namespace ASC.Api.Utils
namespace ASC.Api.Utils;
public static class Update
{
public static class Update
public static T IfNotEquals<T>(T current, T @new)
{
public static T IfNotEquals<T>(T current, T @new)
{
if (!Equals(current, @new))
{
return @new;
}
return current;
}
if (!Equals(current, @new)) return @new;
public static T IfNotEmptyAndNotEquals<T>(T current, T @new)
{
if (Equals(@new, default(T))) return current;
return current;
}
if (!Equals(current, @new))
{
return @new;
}
return current;
}
public static T IfNotEmptyAndNotEquals<T>(T current, T @new)
{
if (Equals(@new, default(T))) return current;
if (!Equals(current, @new)) return @new;
return current;
}
}

View File

@ -23,38 +23,37 @@
*
*/
namespace ASC.Api.Utils
namespace ASC.Api.Utils;
public static class Validate
{
public static class Validate
public static T If<T>(this T item, Func<T, bool> @if, Func<T> then) where T : class
{
public static T If<T>(this T item, Func<T, bool> @if, Func<T> then) where T : class
{
return @if(item) ? then() : item;
}
return @if(item) ? then() : item;
}
public static T IfNull<T>(this T item, Func<T> func) where T : class
{
return item.If((x) => x == default(T), func);
}
public static T IfNull<T>(this T item, Func<T> func) where T : class
{
return item.If((x) => x == default(T), func);
}
public static T ThrowIfNull<T>(this T item, Exception e) where T : class
{
return item.IfNull(() => { throw e; });
}
public static T ThrowIfNull<T>(this T item, Exception e) where T : class
{
return item.IfNull(() => { throw e; });
}
public static T NotFoundIfNull<T>(this T item) where T : class
{
return NotFoundIfNull(item, "Item not found");
}
public static T NotFoundIfNull<T>(this T item) where T : class
{
return NotFoundIfNull(item, "Item not found");
}
public static T NotFoundIfNull<T>(this T item, string message) where T : class
{
return item.IfNull(() => { throw new ItemNotFoundException(message); });
}
public static T NotFoundIfNull<T>(this T item, string message) where T : class
{
return item.IfNull(() => { throw new ItemNotFoundException(message); });
}
public static T? NullIfDefault<T>(this T item) where T : struct
{
return EqualityComparer<T>.Default.Equals(item, default(T)) ? default(T?) : item;
}
public static T? NullIfDefault<T>(this T item) where T : struct
{
return EqualityComparer<T>.Default.Equals(item, default(T)) ? default(T?) : item;
}
}

View File

@ -1,23 +1,23 @@
namespace ASC.Api.Core.Core
namespace ASC.Api.Core.Core;
public class XmlOutputFormatter : IOutputFormatter
{
public class XmlOutputFormatter : IOutputFormatter
public bool CanWriteResult(OutputFormatterCanWriteContext context)
{
public bool CanWriteResult(OutputFormatterCanWriteContext context)
{
return context.ContentType == MimeMapping.GetMimeMapping(".xml");
}
public Task WriteAsync(OutputFormatterWriteContext context)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
DateParseHandling = DateParseHandling.None
};
var responseJson = JsonConvert.SerializeObject(context.Object, Formatting.Indented, settings);
responseJson = JsonConvert.DeserializeObject<XDocument>("{\"result\":" + responseJson + "}", settings).ToString(SaveOptions.None);
return context.HttpContext.Response.WriteAsync(responseJson);
}
return context.ContentType == MimeMapping.GetMimeMapping(".xml");
}
}
public Task WriteAsync(OutputFormatterWriteContext context)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
DateParseHandling = DateParseHandling.None
};
var responseJson = JsonConvert.SerializeObject(context.Object, Formatting.Indented, settings);
responseJson = JsonConvert.DeserializeObject<XDocument>("{\"result\":" + responseJson + "}", settings).ToString(SaveOptions.None);
return context.HttpContext.Response.WriteAsync(responseJson);
}
}

View File

@ -18,7 +18,7 @@ global using System.Threading;
global using System.Threading.Tasks;
global using System.Web;
global using System.Xml.Linq;
global using StackExchange.Redis.Extensions.Newtonsoft;
global using ASC.Api.Core;
global using ASC.Api.Core.Auth;
global using ASC.Api.Core.Convention;
@ -36,7 +36,6 @@ global using ASC.Core;
global using ASC.Core.Common.EF;
global using ASC.Core.Tenants;
global using ASC.Core.Users;
global using ASC.IPSecurity;
global using ASC.Security.Cryptography;
global using ASC.Web.Api.Routing;
global using ASC.Web.Core;
@ -82,3 +81,4 @@ global using NLog;
global using NLog.Extensions.Logging;
global using StackExchange.Redis.Extensions.Core.Configuration;
global using StackExchange.Redis.Extensions.Newtonsoft;

View File

@ -1,97 +1,91 @@
namespace ASC.Api.Core.Middleware
namespace ASC.Api.Core.Middleware;
public abstract class CommonApiResponse
{
public abstract class CommonApiResponse
public int Status { get; set; }
public HttpStatusCode StatusCode { get; set; }
protected CommonApiResponse(HttpStatusCode statusCode)
{
public int Status { get; set; }
StatusCode = statusCode;
public HttpStatusCode StatusCode { get; set; }
protected CommonApiResponse(HttpStatusCode statusCode)
{
StatusCode = statusCode;
}
public static SuccessApiResponse Create(HttpStatusCode statusCode, object response)
{
return new SuccessApiResponse(statusCode, response);
}
public static ErrorApiResponse CreateError(HttpStatusCode statusCode, Exception error)
{
return new ErrorApiResponse(statusCode, error);
}
}
public class ErrorApiResponse : CommonApiResponse
public static SuccessApiResponse Create(HttpStatusCode statusCode, object response)
{
public CommonApiError Error { get; set; }
protected internal ErrorApiResponse(HttpStatusCode statusCode, Exception error, string message = null) : base(statusCode)
{
Status = 1;
Error = CommonApiError.FromException(error, message);
}
return new SuccessApiResponse(statusCode, response);
}
public class SuccessApiResponse : CommonApiResponse
public static ErrorApiResponse CreateError(HttpStatusCode statusCode, Exception error)
{
public int? Count { get; set; }
return new ErrorApiResponse(statusCode, error);
}
}
public long? Total { get; set; }
public class ErrorApiResponse : CommonApiResponse
{
public CommonApiError Error { get; set; }
public object Response { get; set; }
protected internal ErrorApiResponse(HttpStatusCode statusCode, Exception error, string message = null) : base(statusCode)
{
Status = 1;
Error = CommonApiError.FromException(error, message);
}
}
protected internal SuccessApiResponse(HttpStatusCode statusCode, object response, long? total = null, int? count = null) : base(statusCode)
public class SuccessApiResponse : CommonApiResponse
{
public int? Count { get; set; }
public long? Total { get; set; }
public object Response { get; set; }
protected internal SuccessApiResponse(HttpStatusCode statusCode, object response, long? total = null, int? count = null) : base(statusCode)
{
Status = 0;
Response = response;
Total = total;
if (count.HasValue)
{
Status = 0;
Response = response;
Total = total;
if (count.HasValue)
Count = count;
}
else
{
if (response is List<object> list)
{
Count = count;
Count = list.Count;
}
else if (response is IEnumerable<object> collection)
{
Count = collection.Count();
}
else if (response == null)
{
Count = 0;
}
else
{
if (response is List<object> list)
{
Count = list.Count;
}
else if (response is IEnumerable<object> collection)
{
Count = collection.Count();
}
else if (response == null)
{
Count = 0;
}
else
{
Count = 1;
}
Count = 1;
}
}
}
public class CommonApiError
{
public string Message { get; set; }
public string Type { get; set; }
public string Stack { get; set; }
public int Hresult { get; set; }
public static CommonApiError FromException(Exception exception, string message = null)
{
return new CommonApiError()
{
Message = message ?? exception.Message,
Type = exception.GetType().ToString(),
Stack = exception.StackTrace,
Hresult = exception.HResult
};
}
}
}
public class CommonApiError
{
public string Message { get; set; }
public string Type { get; set; }
public string Stack { get; set; }
public int Hresult { get; set; }
public static CommonApiError FromException(Exception exception, string message = null)
{
return new CommonApiError()
{
Message = message ?? exception.Message,
Type = exception.GetType().ToString(),
Stack = exception.StackTrace,
Hresult = exception.HResult
};
}
}

View File

@ -1,45 +1,44 @@
namespace ASC.Api.Core.Middleware
namespace ASC.Api.Core.Middleware;
public class CultureMiddleware
{
public class CultureMiddleware
private readonly RequestDelegate _next;
public CultureMiddleware(RequestDelegate next)
{
private readonly RequestDelegate next;
public CultureMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context, UserManager userManager, TenantManager tenantManager, AuthContext authContext)
{
CultureInfo culture = null;
if (authContext.IsAuthenticated)
{
var user = userManager.GetUsers(authContext.CurrentAccount.ID);
if (!string.IsNullOrEmpty(user.CultureName))
{
culture = user.GetCulture();
}
}
if (culture == null)
{
culture = tenantManager.GetCurrentTenant().GetCulture();
}
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
await next.Invoke(context);
}
_next = next;
}
public static class CultureMiddlewareExtensions
public async Task Invoke(HttpContext context, UserManager userManager, TenantManager tenantManager, AuthContext authContext)
{
public static IApplicationBuilder UseCultureMiddleware(this IApplicationBuilder builder)
CultureInfo culture = null;
if (authContext.IsAuthenticated)
{
return builder.UseMiddleware<CultureMiddleware>();
var user = userManager.GetUsers(authContext.CurrentAccount.ID);
if (!string.IsNullOrEmpty(user.CultureName))
{
culture = user.GetCulture();
}
}
if (culture == null)
{
culture = tenantManager.GetCurrentTenant().GetCulture();
}
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
await _next.Invoke(context);
}
}
public static class CultureMiddlewareExtensions
{
public static IApplicationBuilder UseCultureMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CultureMiddleware>();
}
}

View File

@ -1,27 +1,26 @@
namespace ASC.Api.Core.Middleware
namespace ASC.Api.Core.Middleware;
public class DisposeMiddleware
{
public class DisposeMiddleware
private readonly RequestDelegate _next;
public DisposeMiddleware(RequestDelegate next)
{
private readonly RequestDelegate next;
public DisposeMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
context.Response.RegisterForDispose(new DisposableHttpContext(context));
await next.Invoke(context);
}
_next = next;
}
public static class DisposeMiddlewareExtensions
public async Task Invoke(HttpContext context)
{
public static IApplicationBuilder UseDisposeMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<DisposeMiddleware>();
}
context.Response.RegisterForDispose(new DisposableHttpContext(context));
await _next.Invoke(context);
}
}
public static class DisposeMiddlewareExtensions
{
public static IApplicationBuilder UseDisposeMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<DisposeMiddleware>();
}
}

View File

@ -1,36 +1,32 @@
namespace ASC.Api.Core.Middleware
namespace ASC.Api.Core.Middleware;
[Scope]
public class IpSecurityFilter : IResourceFilter
{
[Scope]
public class IpSecurityFilter : IResourceFilter
private readonly AuthContext _authContext;
private readonly IPSecurity.IPSecurity _iPSecurity;
private readonly ILog _logger;
public IpSecurityFilter(
IOptionsMonitor<ILog> options,
AuthContext authContext,
IPSecurity.IPSecurity IPSecurity)
{
private readonly ILog log;
_logger = options.CurrentValue;
_authContext = authContext;
_iPSecurity = IPSecurity;
}
public IpSecurityFilter(
IOptionsMonitor<ILog> options,
AuthContext authContext,
IPSecurity.IPSecurity IPSecurity)
public void OnResourceExecuted(ResourceExecutedContext context) { }
public void OnResourceExecuting(ResourceExecutingContext context)
{
if (_authContext.IsAuthenticated && !_iPSecurity.Verify())
{
log = options.CurrentValue;
AuthContext = authContext;
this.IPSecurity = IPSecurity;
}
context.Result = new StatusCodeResult((int)HttpStatusCode.Forbidden);
_logger.WarnFormat("IPSecurity: user {0}", _authContext.CurrentAccount.ID);
private AuthContext AuthContext { get; }
public IPRestrictionsSettings IPRestrictionsSettings { get; }
private IPSecurity.IPSecurity IPSecurity { get; }
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
public void OnResourceExecuting(ResourceExecutingContext context)
{
if (AuthContext.IsAuthenticated && !IPSecurity.Verify())
{
context.Result = new StatusCodeResult((int)HttpStatusCode.Forbidden);
log.WarnFormat("IPSecurity: user {0}", AuthContext.CurrentAccount.ID);
return;
}
return;
}
}
}
}

View File

@ -1,39 +1,37 @@
namespace ASC.Api.Core.Middleware
namespace ASC.Api.Core.Middleware;
[Scope]
public class PaymentFilter : IResourceFilter
{
[Scope]
public class PaymentFilter : IResourceFilter
private readonly TenantExtra _tenantExtra;
private readonly ILog _logger;
public PaymentFilter(IOptionsMonitor<ILog> options, TenantExtra tenantExtra)
{
private readonly ILog log;
_logger = options.CurrentValue;
_tenantExtra = tenantExtra;
}
public PaymentFilter(IOptionsMonitor<ILog> options, TenantExtra tenantExtra)
public void OnResourceExecuted(ResourceExecutedContext context) { }
public void OnResourceExecuting(ResourceExecutingContext context)
{
if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor
&& !controllerActionDescriptor.EndpointMetadata.OfType<CustomHttpMethodAttribute>().FirstOrDefault().Check)
{
log = options.CurrentValue;
TenantExtra = tenantExtra;
_logger.Debug("Payment is not required");
return;
}
private TenantExtra TenantExtra { get; }
public void OnResourceExecuted(ResourceExecutedContext context)
var header = context.HttpContext.Request.Headers["Payment-Info"];
if (string.IsNullOrEmpty(header) || (bool.TryParse(header, out var flag) && flag))
{
}
public void OnResourceExecuting(ResourceExecutingContext context)
{
if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor && !controllerActionDescriptor.EndpointMetadata.OfType<CustomHttpMethodAttribute>().FirstOrDefault().Check)
if (_tenantExtra.IsNotPaid())
{
log.Debug("Payment is not required");
return;
}
var header = context.HttpContext.Request.Headers["Payment-Info"];
if (string.IsNullOrEmpty(header) || (bool.TryParse(header, out var flag) && flag))
{
if (TenantExtra.IsNotPaid())
{
context.Result = new StatusCodeResult((int)HttpStatusCode.PaymentRequired);
log.WarnFormat("Payment Required {0}.", context.HttpContext.Request.Url());
}
context.Result = new StatusCodeResult((int)HttpStatusCode.PaymentRequired);
_logger.WarnFormat("Payment Required {0}.", context.HttpContext.Request.Url());
}
}
}
}
}

View File

@ -1,24 +1,23 @@
namespace ASC.Api.Core.Middleware
namespace ASC.Api.Core.Middleware;
[Scope]
public class ProductSecurityFilter : IResourceFilter
{
[Scope]
public class ProductSecurityFilter : IResourceFilter
private static readonly IDictionary<string, Guid> _products;
private readonly ILog _logger;
private readonly WebItemSecurity _webItemSecurity;
private readonly AuthContext _authContext;
static ProductSecurityFilter()
{
private static readonly IDictionary<string, Guid> products;
private readonly ILog log;
var blog = new Guid("6a598c74-91ae-437d-a5f4-ad339bd11bb2");
var bookmark = new Guid("28b10049-dd20-4f54-b986-873bc14ccfc7");
var forum = new Guid("853b6eb9-73ee-438d-9b09-8ffeedf36234");
var news = new Guid("3cfd481b-46f2-4a4a-b55c-b8c0c9def02c");
var wiki = new Guid("742cf945-cbbc-4a57-82d6-1600a12cf8ca");
var photo = new Guid("9d51954f-db9b-4aed-94e3-ed70b914e101");
private WebItemSecurity WebItemSecurity { get; }
private AuthContext AuthContext { get; }
static ProductSecurityFilter()
{
var blog = new Guid("6a598c74-91ae-437d-a5f4-ad339bd11bb2");
var bookmark = new Guid("28b10049-dd20-4f54-b986-873bc14ccfc7");
var forum = new Guid("853b6eb9-73ee-438d-9b09-8ffeedf36234");
var news = new Guid("3cfd481b-46f2-4a4a-b55c-b8c0c9def02c");
var wiki = new Guid("742cf945-cbbc-4a57-82d6-1600a12cf8ca");
var photo = new Guid("9d51954f-db9b-4aed-94e3-ed70b914e101");
products = new Dictionary<string, Guid>
_products = new Dictionary<string, Guid>
{
{ "blog", blog },
{ "bookmark", bookmark },
@ -34,70 +33,73 @@
{ "calendar", WebItemManager.CalendarProductID },
{ "mail", WebItemManager.MailProductID },
};
}
public ProductSecurityFilter(
IOptionsMonitor<ILog> options,
WebItemSecurity webItemSecurity,
AuthContext authContext)
{
_logger = options.CurrentValue;
_webItemSecurity = webItemSecurity;
_authContext = authContext;
}
public void OnResourceExecuted(ResourceExecutedContext context) { }
public void OnResourceExecuting(ResourceExecutingContext context)
{
if (!_authContext.IsAuthenticated)
{
return;
}
public ProductSecurityFilter(
IOptionsMonitor<ILog> options,
WebItemSecurity webItemSecurity,
AuthContext authContext)
if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
{
log = options.CurrentValue;
WebItemSecurity = webItemSecurity;
AuthContext = authContext;
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
public void OnResourceExecuting(ResourceExecutingContext context)
{
if (!AuthContext.IsAuthenticated) return;
if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
var pid = FindProduct(controllerActionDescriptor);
if (pid != Guid.Empty)
{
var pid = FindProduct(controllerActionDescriptor);
if (pid != Guid.Empty)
if (CallContext.GetData("asc.web.product_id") == null)
{
if (CallContext.GetData("asc.web.product_id") == null)
{
CallContext.SetData("asc.web.product_id", pid);
}
if (!WebItemSecurity.IsAvailableForMe(pid))
{
context.Result = new StatusCodeResult((int)HttpStatusCode.Forbidden);
log.WarnFormat("Product {0} denied for user {1}", controllerActionDescriptor.ControllerName, AuthContext.CurrentAccount);
}
CallContext.SetData("asc.web.product_id", pid);
}
if (!_webItemSecurity.IsAvailableForMe(pid))
{
context.Result = new StatusCodeResult((int)HttpStatusCode.Forbidden);
_logger.WarnFormat("Product {0} denied for user {1}", controllerActionDescriptor.ControllerName, _authContext.CurrentAccount);
}
}
}
private static Guid FindProduct(ControllerActionDescriptor method)
{
if (method == null || string.IsNullOrEmpty(method.ControllerName))
{
return default;
}
var name = method.ControllerName.ToLower();
if (name == "community")
{
var url = method.MethodInfo.GetCustomAttribute<HttpMethodAttribute>().Template;
if (!string.IsNullOrEmpty(url))
{
var module = url.Split('/')[0];
if (products.ContainsKey(module))
{
return products[module];
}
}
}
if (products.ContainsKey(name))
{
return products[name];
}
return default;
}
}
}
private static Guid FindProduct(ControllerActionDescriptor method)
{
if (method == null || string.IsNullOrEmpty(method.ControllerName))
{
return default;
}
var name = method.ControllerName.ToLower();
if (name == "community")
{
var url = method.MethodInfo.GetCustomAttribute<HttpMethodAttribute>().Template;
if (!string.IsNullOrEmpty(url))
{
var module = url.Split('/')[0];
if (_products.TryGetValue(module, out var communityProduct))
{
return communityProduct;
}
}
}
if (_products.TryGetValue(name, out var product))
{
return product;
}
return default;
}
}

View File

@ -1,57 +1,56 @@
namespace ASC.Api.Core.Middleware
namespace ASC.Api.Core.Middleware;
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
public override void OnException(ExceptionContext context)
{
public override void OnException(ExceptionContext context)
var status = (HttpStatusCode)context.HttpContext.Response.StatusCode;
string message = null;
if (status == HttpStatusCode.OK)
{
var status = (HttpStatusCode)context.HttpContext.Response.StatusCode;
string message = null;
if (status == HttpStatusCode.OK)
{
status = HttpStatusCode.InternalServerError;
}
switch (context.Exception)
{
case ItemNotFoundException:
status = HttpStatusCode.NotFound;
message = "The record could not be found";
break;
case ArgumentException:
status = HttpStatusCode.BadRequest;
message = "Invalid arguments";
break;
case SecurityException:
status = HttpStatusCode.Forbidden;
message = "Access denied";
break;
case InvalidOperationException:
status = HttpStatusCode.Forbidden;
break;
}
var result = new ObjectResult(new ErrorApiResponse(status, context.Exception, message))
{
StatusCode = (int)status
};
context.Result = result;
status = HttpStatusCode.InternalServerError;
}
switch (context.Exception)
{
case ItemNotFoundException:
status = HttpStatusCode.NotFound;
message = "The record could not be found";
break;
case ArgumentException:
status = HttpStatusCode.BadRequest;
message = "Invalid arguments";
break;
case SecurityException:
status = HttpStatusCode.Forbidden;
message = "Access denied";
break;
case InvalidOperationException:
status = HttpStatusCode.Forbidden;
break;
}
var result = new ObjectResult(new ErrorApiResponse(status, context.Exception, message))
{
StatusCode = (int)status
};
context.Result = result;
}
}
public class CustomResponseFilterAttribute : ResultFilterAttribute
public class CustomResponseFilterAttribute : ResultFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
public override void OnResultExecuting(ResultExecutingContext context)
if (context.Result is ObjectResult result)
{
if (context.Result is ObjectResult result)
{
context.HttpContext.Items.TryGetValue("TotalCount", out var total);
context.HttpContext.Items.TryGetValue("Count", out var count);
result.Value = new SuccessApiResponse((HttpStatusCode)context.HttpContext.Response.StatusCode, result.Value, (long?)total, (int?)count);
}
base.OnResultExecuting(context);
context.HttpContext.Items.TryGetValue("TotalCount", out var total);
context.HttpContext.Items.TryGetValue("Count", out var count);
result.Value = new SuccessApiResponse((HttpStatusCode)context.HttpContext.Response.StatusCode, result.Value, (long?)total, (int?)count);
}
base.OnResultExecuting(context);
}
}

View File

@ -1,38 +1,36 @@
namespace ASC.Api.Core.Middleware
namespace ASC.Api.Core.Middleware;
[Scope]
public class TenantStatusFilter : IResourceFilter
{
[Scope]
public class TenantStatusFilter : IResourceFilter
private readonly TenantManager _tenantManager;
private readonly ILog _logger;
public TenantStatusFilter(IOptionsMonitor<ILog> options, TenantManager tenantManager)
{
private readonly ILog log;
_logger = options.CurrentValue;
_tenantManager = tenantManager;
}
public TenantStatusFilter(IOptionsMonitor<ILog> options, TenantManager tenantManager)
public void OnResourceExecuted(ResourceExecutedContext context) { }
public void OnResourceExecuting(ResourceExecutingContext context)
{
var tenant = _tenantManager.GetCurrentTenant(false);
if (tenant == null)
{
log = options.CurrentValue;
TenantManager = tenantManager;
context.Result = new StatusCodeResult((int)HttpStatusCode.NotFound);
_logger.Warn("Current tenant not found");
return;
}
private TenantManager TenantManager { get; }
public void OnResourceExecuted(ResourceExecutedContext context)
if (tenant.Status == TenantStatus.RemovePending || tenant.Status == TenantStatus.Suspended)
{
}
context.Result = new StatusCodeResult((int)HttpStatusCode.NotFound);
_logger.WarnFormat("Tenant {0} is not removed or suspended", tenant.TenantId);
public void OnResourceExecuting(ResourceExecutingContext context)
{
var tenant = TenantManager.GetCurrentTenant(false);
if (tenant == null)
{
context.Result = new StatusCodeResult((int)HttpStatusCode.NotFound);
log.WarnFormat("Tenant {0} not found", tenant.TenantId);
return;
}
if (tenant.Status == TenantStatus.RemovePending || tenant.Status == TenantStatus.Suspended)
{
context.Result = new StatusCodeResult((int)HttpStatusCode.NotFound);
log.WarnFormat("Tenant {0} is not removed or suspended", tenant.TenantId);
return;
}
return;
}
}
}
}

View File

@ -1,50 +1,53 @@
namespace ASC.Api.Core.Middleware
{
[Scope]
public class WebhooksGlobalFilterAttribute : ResultFilterAttribute
{
private IWebhookPublisher WebhookPublisher { get; }
private static List<string> methodList = new List<string> { "POST", "UPDATE", "DELETE" };
private JsonSerializerOptions jsonSerializerOptions;
public WebhooksGlobalFilterAttribute(IWebhookPublisher webhookPublisher, Action<JsonOptions> projectJsonOptions)
{
WebhookPublisher = webhookPublisher;
var jsonOptions = new JsonOptions();
projectJsonOptions.Invoke(jsonOptions);
jsonSerializerOptions = jsonOptions.JsonSerializerOptions;
using JsonSerializer = System.Text.Json.JsonSerializer;
namespace ASC.Api.Core.Middleware;
[Scope]
public class WebhooksGlobalFilterAttribute : ResultFilterAttribute
{
private readonly IWebhookPublisher _webhookPublisher;
private readonly JsonSerializerOptions _jsonSerializerOptions;
private static List<string> _methodList = new List<string> { "POST", "UPDATE", "DELETE" };
public WebhooksGlobalFilterAttribute(IWebhookPublisher webhookPublisher, Action<JsonOptions> projectJsonOptions)
{
_webhookPublisher = webhookPublisher;
var jsonOptions = new JsonOptions();
projectJsonOptions.Invoke(jsonOptions);
_jsonSerializerOptions = jsonOptions.JsonSerializerOptions;
}
public override void OnResultExecuted(ResultExecutedContext context)
{
var method = context.HttpContext.Request.Method;
if (!_methodList.Contains(method) || context.Canceled)
{
base.OnResultExecuted(context);
return;
}
public override void OnResultExecuted(ResultExecutedContext context)
{
var method = context.HttpContext.Request.Method;
if (!methodList.Contains(method) || context.Canceled)
{
base.OnResultExecuted(context);
return;
}
var endpoint = (RouteEndpoint)context.HttpContext.GetEndpoint();
var routePattern = endpoint?.RoutePattern.RawText;
if (routePattern == null)
{
base.OnResultExecuted(context);
return;
}
if (context.Result is ObjectResult objectResult)
{
var resultContent = System.Text.Json.JsonSerializer.Serialize(objectResult.Value, jsonSerializerOptions);
var endpoint = (RouteEndpoint)context.HttpContext.GetEndpoint();
var routePattern = endpoint?.RoutePattern.RawText;
var eventName = $"method: {method}, route: {routePattern}";
if (routePattern == null)
{
base.OnResultExecuted(context);
WebhookPublisher.Publish(eventName, resultContent);
}
base.OnResultExecuted(context);
}
}
}
return;
}
if (context.Result is ObjectResult objectResult)
{
var resultContent = JsonSerializer.Serialize(objectResult.Value, _jsonSerializerOptions);
var eventName = $"method: {method}, route: {routePattern}";
_webhookPublisher.Publish(eventName, resultContent);
}
base.OnResultExecuted(context);
}
}

View File

@ -23,28 +23,24 @@
*
*/
namespace ASC.Web.Api.Models
namespace ASC.Web.Api.Models;
public class Contact
{
public class Contact
public string Type { get; set; }
public string Value { get; set; }
//For binder
public Contact() { }
public Contact(string type, string value)
{
public string Type { get; set; }
Type = type;
Value = value;
}
public string Value { get; set; }
public Contact()
{
//For binder
}
public Contact(string type, string value)
{
Type = type;
Value = value;
}
public static Contact GetSample()
{
return new Contact("GTalk", "my@gmail.com");
}
public static Contact GetSample()
{
return new Contact("GTalk", "my@gmail.com");
}
}

View File

@ -23,95 +23,94 @@
*
*/
namespace ASC.Web.Api.Models
namespace ASC.Web.Api.Models;
public class EmployeeWraper
{
public class EmployeeWraper
public Guid Id { get; set; }
public string DisplayName { get; set; }
public string Title { get; set; }
public string AvatarSmall { get; set; }
public string ProfileUrl { get; set; }
public static EmployeeWraper GetSample()
{
public Guid Id { get; set; }
public string DisplayName { get; set; }
public string Title { get; set; }
public string AvatarSmall { get; set; }
public string ProfileUrl { get; set; }
public static EmployeeWraper GetSample()
return new EmployeeWraper
{
return new EmployeeWraper
{
Id = Guid.Empty,
DisplayName = "Mike Zanyatski",
Title = "Manager",
AvatarSmall = "url to small avatar",
};
Id = Guid.Empty,
DisplayName = "Mike Zanyatski",
Title = "Manager",
AvatarSmall = "url to small avatar",
};
}
}
[Scope]
public class EmployeeWraperHelper
{
protected UserPhotoManager UserPhotoManager { get; }
protected UserManager UserManager { get; }
private readonly ApiContext _httpContext;
private readonly DisplayUserSettingsHelper _displayUserSettingsHelper;
private readonly CommonLinkUtility _commonLinkUtility;
public EmployeeWraperHelper(
ApiContext httpContext,
DisplayUserSettingsHelper displayUserSettingsHelper,
UserPhotoManager userPhotoManager,
CommonLinkUtility commonLinkUtility,
UserManager userManager)
{
UserPhotoManager = userPhotoManager;
UserManager = userManager;
_httpContext = httpContext;
_displayUserSettingsHelper = displayUserSettingsHelper;
_commonLinkUtility = commonLinkUtility;
}
public EmployeeWraper Get(UserInfo userInfo)
{
return Init(new EmployeeWraper(), userInfo);
}
public EmployeeWraper Get(Guid userId)
{
try
{
return Get(UserManager.GetUsers(userId));
}
catch (Exception)
{
return Get(Constants.LostUser);
}
}
[Scope]
public class EmployeeWraperHelper
protected EmployeeWraper Init(EmployeeWraper result, UserInfo userInfo)
{
private ApiContext HttpContext { get; }
private DisplayUserSettingsHelper DisplayUserSettingsHelper { get; }
protected UserPhotoManager UserPhotoManager { get; }
private CommonLinkUtility CommonLinkUtility { get; }
protected UserManager UserManager { get; }
result.Id = userInfo.ID;
result.DisplayName = _displayUserSettingsHelper.GetFullUserName(userInfo);
public EmployeeWraperHelper(
ApiContext httpContext,
DisplayUserSettingsHelper displayUserSettingsHelper,
UserPhotoManager userPhotoManager,
CommonLinkUtility commonLinkUtility,
UserManager userManager)
if (!string.IsNullOrEmpty(userInfo.Title))
{
HttpContext = httpContext;
DisplayUserSettingsHelper = displayUserSettingsHelper;
UserPhotoManager = userPhotoManager;
CommonLinkUtility = commonLinkUtility;
UserManager = userManager;
result.Title = userInfo.Title;
}
public EmployeeWraper Get(UserInfo userInfo)
var userInfoLM = userInfo.LastModified.GetHashCode();
if (_httpContext.Check("avatarSmall"))
{
return Init(new EmployeeWraper(), userInfo);
result.AvatarSmall = UserPhotoManager.GetSmallPhotoURL(userInfo.ID, out var isdef)
+ (isdef ? "" : $"?_={userInfoLM}");
}
if (result.Id != Guid.Empty)
{
var profileUrl = _commonLinkUtility.GetUserProfile(userInfo, false);
result.ProfileUrl = _commonLinkUtility.GetFullAbsolutePath(profileUrl);
}
public EmployeeWraper Get(Guid userId)
{
try
{
return Get(UserManager.GetUsers(userId));
}
catch (Exception)
{
return Get(Constants.LostUser);
}
}
protected EmployeeWraper Init(EmployeeWraper result, UserInfo userInfo)
{
result.Id = userInfo.ID;
result.DisplayName = DisplayUserSettingsHelper.GetFullUserName(userInfo);
if (!string.IsNullOrEmpty(userInfo.Title))
{
result.Title = userInfo.Title;
}
var userInfoLM = userInfo.LastModified.GetHashCode();
if (HttpContext.Check("avatarSmall"))
{
result.AvatarSmall = UserPhotoManager.GetSmallPhotoURL(userInfo.ID, out var isdef) + (isdef ? "" : $"?_={userInfoLM}");
}
if (result.Id != Guid.Empty)
{
var profileUrl = CommonLinkUtility.GetUserProfile(userInfo, false);
result.ProfileUrl = CommonLinkUtility.GetFullAbsolutePath(profileUrl);
}
return result;
}
return result;
}
}

View File

@ -23,254 +23,235 @@
*
*/
namespace ASC.Web.Api.Models
namespace ASC.Web.Api.Models;
public class EmployeeWraperFull : EmployeeWraper
{
public class EmployeeWraperFull : EmployeeWraper
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public List<Contact> Contacts { get; set; }
public ApiDateTime Birthday { get; set; }
public string Sex { get; set; }
public EmployeeStatus Status { get; set; }
public EmployeeActivationStatus ActivationStatus { get; set; }
public ApiDateTime Terminated { get; set; }
public string Department { get; set; }
public ApiDateTime WorkFrom { get; set; }
public List<GroupWrapperSummary> Groups { get; set; }
public string Location { get; set; }
public string Notes { get; set; }
public string AvatarMax { get; set; }
public string AvatarMedium { get; set; }
public string Avatar { get; set; }
public bool IsAdmin { get; set; }
public bool IsLDAP { get; set; }
public List<string> ListAdminModules { get; set; }
public bool IsOwner { get; set; }
public bool IsVisitor { get; set; }
public string CultureName { get; set; }
public string MobilePhone { get; set; }
public MobilePhoneActivationStatus MobilePhoneActivationStatus { get; set; }
public bool IsSSO { get; set; }
public new static EmployeeWraperFull GetSample()
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public List<Contact> Contacts { get; set; }
public ApiDateTime Birthday { get; set; }
public string Sex { get; set; }
public EmployeeStatus Status { get; set; }
public EmployeeActivationStatus ActivationStatus { get; set; }
public ApiDateTime Terminated { get; set; }
public string Department { get; set; }
public ApiDateTime WorkFrom { get; set; }
public List<GroupWrapperSummary> Groups { get; set; }
public string Location { get; set; }
public string Notes { get; set; }
public string AvatarMax { get; set; }
public string AvatarMedium { get; set; }
public string Avatar { get; set; }
public bool IsAdmin { get; set; }
public bool IsLDAP { get; set; }
public List<string> ListAdminModules { get; set; }
public bool IsOwner { get; set; }
public bool IsVisitor { get; set; }
public string CultureName { get; set; }
public string MobilePhone { get; set; }
public MobilePhoneActivationStatus MobilePhoneActivationStatus { get; set; }
public bool IsSSO { get; set; }
public new static EmployeeWraperFull GetSample()
return new EmployeeWraperFull
{
return new EmployeeWraperFull
{
Avatar = "url to big avatar",
AvatarSmall = "url to small avatar",
AvatarMax = "url to max avatar",
Contacts = new List<Contact> { Contact.GetSample() },
Email = "my@gmail.com",
FirstName = "Mike",
Id = Guid.Empty,
IsAdmin = false,
ListAdminModules = new List<string> { "projects", "crm" },
UserName = "Mike.Zanyatski",
LastName = "Zanyatski",
Title = "Manager",
Groups = new List<GroupWrapperSummary> { GroupWrapperSummary.GetSample() },
AvatarMedium = "url to medium avatar",
Birthday = ApiDateTime.GetSample(),
Department = "Marketing",
Location = "Palo Alto",
Notes = "Notes to worker",
Sex = "male",
Status = EmployeeStatus.Active,
WorkFrom = ApiDateTime.GetSample(),
Terminated = ApiDateTime.GetSample(),
CultureName = "en-EN",
IsLDAP = false,
IsSSO = false
};
}
Avatar = "url to big avatar",
AvatarSmall = "url to small avatar",
AvatarMax = "url to max avatar",
Contacts = new List<Contact> { Contact.GetSample() },
Email = "my@gmail.com",
FirstName = "Mike",
Id = Guid.Empty,
IsAdmin = false,
ListAdminModules = new List<string> { "projects", "crm" },
UserName = "Mike.Zanyatski",
LastName = "Zanyatski",
Title = "Manager",
Groups = new List<GroupWrapperSummary> { GroupWrapperSummary.GetSample() },
AvatarMedium = "url to medium avatar",
Birthday = ApiDateTime.GetSample(),
Department = "Marketing",
Location = "Palo Alto",
Notes = "Notes to worker",
Sex = "male",
Status = EmployeeStatus.Active,
WorkFrom = ApiDateTime.GetSample(),
Terminated = ApiDateTime.GetSample(),
CultureName = "en-EN",
IsLDAP = false,
IsSSO = false
};
}
}
[Scope]
public class EmployeeWraperFullHelper : EmployeeWraperHelper
{
private readonly ApiContext _context;
private readonly WebItemSecurity _webItemSecurity;
private readonly ApiDateTimeHelper _apiDateTimeHelper;
public EmployeeWraperFullHelper(
ApiContext context,
UserManager userManager,
UserPhotoManager userPhotoManager,
WebItemSecurity webItemSecurity,
CommonLinkUtility commonLinkUtility,
DisplayUserSettingsHelper displayUserSettingsHelper,
ApiDateTimeHelper apiDateTimeHelper)
: base(context, displayUserSettingsHelper, userPhotoManager, commonLinkUtility, userManager)
{
_context = context;
_webItemSecurity = webItemSecurity;
_apiDateTimeHelper = apiDateTimeHelper;
}
[Scope]
public class EmployeeWraperFullHelper : EmployeeWraperHelper
public static Expression<Func<User, UserInfo>> GetExpression(ApiContext apiContext)
{
private ApiContext Context { get; }
private WebItemSecurity WebItemSecurity { get; }
private ApiDateTimeHelper ApiDateTimeHelper { get; }
public EmployeeWraperFullHelper(
ApiContext context,
UserManager userManager,
UserPhotoManager userPhotoManager,
WebItemSecurity webItemSecurity,
CommonLinkUtility commonLinkUtility,
DisplayUserSettingsHelper displayUserSettingsHelper,
ApiDateTimeHelper apiDateTimeHelper)
: base(context, displayUserSettingsHelper, userPhotoManager, commonLinkUtility, userManager)
if (apiContext?.Fields == null)
{
Context = context;
WebItemSecurity = webItemSecurity;
ApiDateTimeHelper = apiDateTimeHelper;
return null;
}
public static Expression<Func<User, UserInfo>> GetExpression(ApiContext apiContext)
var newExpr = Expression.New(typeof(UserInfo));
//i => new UserInfo { ID = i.id }
var parameter = Expression.Parameter(typeof(User), "i");
var bindExprs = new List<MemberAssignment>();
if (apiContext.Check("Id"))
{
if (apiContext?.Fields == null) return null;
var newExpr = Expression.New(typeof(UserInfo));
//i => new UserInfo { ID = i.id }
var parameter = Expression.Parameter(typeof(User), "i");
var bindExprs = new List<MemberAssignment>();
if (apiContext.Check("Id"))
{
bindExprs.Add(Expression.Bind(typeof(UserInfo).GetProperty("ID"), Expression.Property(parameter, typeof(User).GetProperty("Id"))));
}
var body = Expression.MemberInit(newExpr, bindExprs);
var lambda = Expression.Lambda<Func<User, UserInfo>>(body, parameter);
return lambda;
bindExprs.Add(Expression.Bind(typeof(UserInfo).GetProperty("ID"),
Expression.Property(parameter, typeof(User).GetProperty("Id"))));
}
public EmployeeWraperFull GetFull(UserInfo userInfo)
var body = Expression.MemberInit(newExpr, bindExprs);
var lambda = Expression.Lambda<Func<User, UserInfo>>(body, parameter);
return lambda;
}
public EmployeeWraperFull GetFull(UserInfo userInfo)
{
var result = new EmployeeWraperFull
{
var result = new EmployeeWraperFull
{
UserName = userInfo.UserName,
FirstName = userInfo.FirstName,
LastName = userInfo.LastName,
Birthday = ApiDateTimeHelper.Get(userInfo.BirthDate),
Status = userInfo.Status,
ActivationStatus = userInfo.ActivationStatus & ~EmployeeActivationStatus.AutoGenerated,
Terminated = ApiDateTimeHelper.Get(userInfo.TerminatedDate),
WorkFrom = ApiDateTimeHelper.Get(userInfo.WorkFromDate),
Email = userInfo.Email,
IsVisitor = userInfo.IsVisitor(UserManager),
IsAdmin = userInfo.IsAdmin(UserManager),
IsOwner = userInfo.IsOwner(Context.Tenant),
IsLDAP = userInfo.IsLDAP(),
IsSSO = userInfo.IsSSO()
};
UserName = userInfo.UserName,
FirstName = userInfo.FirstName,
LastName = userInfo.LastName,
Birthday = _apiDateTimeHelper.Get(userInfo.BirthDate),
Status = userInfo.Status,
ActivationStatus = userInfo.ActivationStatus & ~EmployeeActivationStatus.AutoGenerated,
Terminated = _apiDateTimeHelper.Get(userInfo.TerminatedDate),
WorkFrom = _apiDateTimeHelper.Get(userInfo.WorkFromDate),
Email = userInfo.Email,
IsVisitor = userInfo.IsVisitor(UserManager),
IsAdmin = userInfo.IsAdmin(UserManager),
IsOwner = userInfo.IsOwner(_context.Tenant),
IsLDAP = userInfo.IsLDAP(),
IsSSO = userInfo.IsSSO()
};
Init(result, userInfo);
Init(result, userInfo);
if (userInfo.Sex.HasValue)
{
result.Sex = userInfo.Sex.Value ? "male" : "female";
}
if (!string.IsNullOrEmpty(userInfo.Location))
{
result.Location = userInfo.Location;
}
if (!string.IsNullOrEmpty(userInfo.Notes))
{
result.Notes = userInfo.Notes;
}
if (!string.IsNullOrEmpty(userInfo.MobilePhone))
{
result.MobilePhone = userInfo.MobilePhone;
}
result.MobilePhoneActivationStatus = userInfo.MobilePhoneActivationStatus;
if (!string.IsNullOrEmpty(userInfo.CultureName))
{
result.CultureName = userInfo.CultureName;
}
FillConacts(result, userInfo);
if (Context.Check("groups") || Context.Check("department"))
{
var groups = UserManager.GetUserGroups(userInfo.ID)
.Select(x => new GroupWrapperSummary(x, UserManager))
.ToList();
if (groups.Count > 0)
{
result.Groups = groups;
result.Department = string.Join(", ", result.Groups.Select(d => d.Name.HtmlEncode()));
}
else
{
result.Department = "";
}
}
var userInfoLM = userInfo.LastModified.GetHashCode();
if (Context.Check("avatarMax"))
{
result.AvatarMax = UserPhotoManager.GetMaxPhotoURL(userInfo.ID, out var isdef) + (isdef ? "" : $"?_={userInfoLM}");
}
if (Context.Check("avatarMedium"))
{
result.AvatarMedium = UserPhotoManager.GetMediumPhotoURL(userInfo.ID, out var isdef) + (isdef ? "" : $"?_={userInfoLM}");
}
if (Context.Check("avatar"))
{
result.Avatar = UserPhotoManager.GetBigPhotoURL(userInfo.ID, out var isdef) + (isdef ? "" : $"?_={userInfoLM}");
}
if (Context.Check("listAdminModules"))
{
var listAdminModules = userInfo.GetListAdminModules(WebItemSecurity);
if (listAdminModules.Any())
result.ListAdminModules = listAdminModules;
}
return result;
if (userInfo.Sex.HasValue)
{
result.Sex = userInfo.Sex.Value ? "male" : "female";
}
private void FillConacts(EmployeeWraperFull employeeWraperFull, UserInfo userInfo)
if (!string.IsNullOrEmpty(userInfo.Location))
{
if (userInfo.ContactsList == null) return;
result.Location = userInfo.Location;
}
var contacts = new List<Contact>();
if (!string.IsNullOrEmpty(userInfo.Notes))
{
result.Notes = userInfo.Notes;
}
for (var i = 0; i < userInfo.ContactsList.Count; i += 2)
if (!string.IsNullOrEmpty(userInfo.MobilePhone))
{
result.MobilePhone = userInfo.MobilePhone;
}
result.MobilePhoneActivationStatus = userInfo.MobilePhoneActivationStatus;
if (!string.IsNullOrEmpty(userInfo.CultureName))
{
result.CultureName = userInfo.CultureName;
}
FillConacts(result, userInfo);
if (_context.Check("groups") || _context.Check("department"))
{
var groups = UserManager.GetUserGroups(userInfo.ID)
.Select(x => new GroupWrapperSummary(x, UserManager))
.ToList();
if (groups.Count > 0)
{
if (i + 1 < userInfo.ContactsList.Count)
{
contacts.Add(new Contact(userInfo.ContactsList[i], userInfo.ContactsList[i + 1]));
}
result.Groups = groups;
result.Department = string.Join(", ", result.Groups.Select(d => d.Name.HtmlEncode()));
}
if (contacts.Any())
else
{
employeeWraperFull.Contacts = contacts;
result.Department = "";
}
}
var userInfoLM = userInfo.LastModified.GetHashCode();
if (_context.Check("avatarMax"))
{
result.AvatarMax = UserPhotoManager.GetMaxPhotoURL(userInfo.ID, out var isdef) + (isdef ? "" : $"?_={userInfoLM}");
}
if (_context.Check("avatarMedium"))
{
result.AvatarMedium = UserPhotoManager.GetMediumPhotoURL(userInfo.ID, out var isdef) + (isdef ? "" : $"?_={userInfoLM}");
}
if (_context.Check("avatar"))
{
result.Avatar = UserPhotoManager.GetBigPhotoURL(userInfo.ID, out var isdef) + (isdef ? "" : $"?_={userInfoLM}");
}
if (_context.Check("listAdminModules"))
{
var listAdminModules = userInfo.GetListAdminModules(_webItemSecurity);
if (listAdminModules.Count > 0)
{
result.ListAdminModules = listAdminModules;
}
}
return result;
}
private void FillConacts(EmployeeWraperFull employeeWraperFull, UserInfo userInfo)
{
if (userInfo.ContactsList == null)
{
return;
}
var contacts = new List<Contact>();
for (var i = 0; i < userInfo.ContactsList.Count; i += 2)
{
if (i + 1 < userInfo.ContactsList.Count)
{
contacts.Add(new Contact(userInfo.ContactsList[i], userInfo.ContactsList[i + 1]));
}
}
if (contacts.Count > 0)
{
employeeWraperFull.Contacts = contacts;
}
}
}

View File

@ -23,31 +23,32 @@
*
*/
namespace ASC.Web.Api.Models
using GroupInfo = ASC.Core.Users.GroupInfo;
namespace ASC.Web.Api.Models;
public class GroupWrapperSummary
{
public class GroupWrapperSummary
public Guid Id { get; set; }
public string Name { get; set; }
public string Manager { get; set; }
protected GroupWrapperSummary() { }
public GroupWrapperSummary(GroupInfo group, UserManager userManager)
{
public GroupWrapperSummary(ASC.Core.Users.GroupInfo group, UserManager userManager)
Id = group.ID;
Name = group.Name;
Manager = userManager.GetUsers(userManager.GetDepartmentManager(group.ID)).UserName;
}
public static GroupWrapperSummary GetSample()
{
return new GroupWrapperSummary
{
Id = group.ID;
Name = group.Name;
Manager = userManager.GetUsers(userManager.GetDepartmentManager(group.ID)).UserName;
}
protected GroupWrapperSummary()
{
}
public string Name { get; set; }
public Guid Id { get; set; }
public string Manager { get; set; }
public static GroupWrapperSummary GetSample()
{
return new GroupWrapperSummary { Id = Guid.Empty, Manager = "Jake.Zazhitski", Name = "Group Name" };
}
Id = Guid.Empty,
Manager = "Jake.Zazhitski",
Name = "Group Name"
};
}
}

View File

@ -1,16 +1,13 @@
namespace ASC.Web.Api.Routing
namespace ASC.Web.Api.Routing;
public class DefaultRouteAttribute : RouteAttribute
{
public class DefaultRouteAttribute : RouteAttribute
public static string BaseUrl { get; set; }
static DefaultRouteAttribute()
{
public static string BaseUrl { get; set; }
static DefaultRouteAttribute()
{
BaseUrl = "api/2.0";
}
public DefaultRouteAttribute() : base(BaseUrl)
{
}
BaseUrl = "api/2.0";
}
}
public DefaultRouteAttribute() : base(BaseUrl) { }
}

View File

@ -1,53 +1,55 @@
namespace ASC.Web.Api.Routing
namespace ASC.Web.Api.Routing;
public abstract class CustomHttpMethodAttribute : HttpMethodAttribute
{
public abstract class CustomHttpMethodAttribute : HttpMethodAttribute
{
public bool Check { get; set; }
public bool DisableFormat { get; set; }
public bool Check { get; set; }
public bool DisableFormat { get; set; }
public CustomHttpMethodAttribute(string method, string template = null, bool check = true, int order = 1)
: base(new List<string>() { method }, $"[controller]{(template != null ? $"/{template}" : "")}")
{
Check = check;
Order = order;
}
}
public class ReadAttribute : CustomHttpMethodAttribute
protected CustomHttpMethodAttribute(string method, string template = null, bool check = true, int order = 1)
: base(new List<string>() { method }, $"[controller]{(template != null ? $"/{template}" : "")}")
{
public ReadAttribute(bool check = true, int order = 1) :
this(null, check, order)
{ }
public ReadAttribute(string template, bool check = true, int order = 1) :
base(HttpMethod.Get.Method, template, check, order)
{ }
}
public class CreateAttribute : CustomHttpMethodAttribute
{
public CreateAttribute(bool check = true, int order = 1) :
this(null, check, order)
{ }
public CreateAttribute(string template, bool check = true, int order = 1) :
base(HttpMethod.Post.Method, template, check, order)
{ }
}
public class UpdateAttribute : CustomHttpMethodAttribute
{
public UpdateAttribute(bool check = true, int order = 1) :
this(null, check, order)
{ }
public UpdateAttribute(string template, bool check = true, int order = 1) :
base(HttpMethod.Put.Method, template, check, order)
{ }
}
public class DeleteAttribute : CustomHttpMethodAttribute
{
public DeleteAttribute(bool check = true, int order = 1) :
this(null, check, order)
{ }
public DeleteAttribute(string template, bool check = true, int order = 1) :
base(HttpMethod.Delete.Method, template, check, order)
{ }
Check = check;
Order = order;
}
}
public class ReadAttribute : CustomHttpMethodAttribute
{
public ReadAttribute(bool check = true, int order = 1) :
this(null, check, order)
{ }
public ReadAttribute(string template, bool check = true, int order = 1) :
base(HttpMethod.Get.Method, template, check, order)
{ }
}
public class CreateAttribute : CustomHttpMethodAttribute
{
public CreateAttribute(bool check = true, int order = 1) :
this(null, check, order)
{ }
public CreateAttribute(string template, bool check = true, int order = 1) :
base(HttpMethod.Post.Method, template, check, order)
{ }
}
public class UpdateAttribute : CustomHttpMethodAttribute
{
public UpdateAttribute(bool check = true, int order = 1) :
this(null, check, order)
{ }
public UpdateAttribute(string template, bool check = true, int order = 1) :
base(HttpMethod.Put.Method, template, check, order)
{ }
}
public class DeleteAttribute : CustomHttpMethodAttribute
{
public DeleteAttribute(bool check = true, int order = 1) :
this(null, check, order)
{ }
public DeleteAttribute(string template, bool check = true, int order = 1) :
base(HttpMethod.Delete.Method, template, check, order)
{ }
}

View File

@ -24,9 +24,6 @@
<EmbeddedResource Include="Utils\TimeZoneConverter\windowsZones.xml" />
<EmbeddedResource Include="Utils\TimeZoneConverter\timeZoneNames.xml" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Notify\AWSEmail.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ARSoft.Tools.NetStandard.DXSdata" Version="1.0.0" />
<PackageReference Include="Autofac.Configuration" Version="6.0.0" />
@ -64,7 +61,4 @@
<Protobuf Include="protos\distributed_task_cache.proto" />
<Protobuf Include="protos\distributed_task_cancelation.proto" />
</ItemGroup>
<ItemGroup>
<Folder Include="Notify\" />
</ItemGroup>
</Project>

View File

@ -23,129 +23,125 @@
*
*/
namespace ASC.Common.Caching
namespace ASC.Common.Caching;
[Singletone]
public class AscCacheNotify
{
[Singletone]
public class AscCacheNotify
private readonly ICacheNotify<AscCacheItem> _cacheNotify;
public AscCacheNotify(ICacheNotify<AscCacheItem> cacheNotify)
{
private ICacheNotify<AscCacheItem> CacheNotify { get; }
_cacheNotify = cacheNotify;
public AscCacheNotify(ICacheNotify<AscCacheItem> cacheNotify)
_cacheNotify.Subscribe((item) => { OnClearCache(); }, CacheNotifyAction.Any);
}
public void ClearCache() => _cacheNotify.Publish(new AscCacheItem { Id = Guid.NewGuid().ToString() }, CacheNotifyAction.Any);
public static void OnClearCache()
{
var keys = MemoryCache.Default.Select(r => r.Key);
foreach (var k in keys)
{
CacheNotify = cacheNotify;
CacheNotify.Subscribe((item) => { OnClearCache(); }, CacheNotifyAction.Any);
MemoryCache.Default.Remove(k);
}
}
}
public void ClearCache()
[Singletone]
public class AscCache : ICache
{
private readonly IMemoryCache _memoryCache;
private readonly ConcurrentDictionary<string, object> _memoryCacheKeys;
public AscCache(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
_memoryCacheKeys = new ConcurrentDictionary<string, object>();
}
public T Get<T>(string key) where T : class
{
return _memoryCache.Get<T>(key);
}
public void Insert(string key, object value, TimeSpan sligingExpiration)
{
var options = new MemoryCacheEntryOptions()
.SetSlidingExpiration(sligingExpiration)
.RegisterPostEvictionCallback(EvictionCallback);
_memoryCache.Set(key, value, options);
_memoryCacheKeys.TryAdd(key, null);
}
public void Insert(string key, object value, DateTime absolutExpiration)
{
var options = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(absolutExpiration == DateTime.MaxValue ? DateTimeOffset.MaxValue : new DateTimeOffset(absolutExpiration))
.RegisterPostEvictionCallback(EvictionCallback);
_memoryCache.Set(key, value, options);
_memoryCacheKeys.TryAdd(key, null);
}
public void Remove(string key)
{
_memoryCache.Remove(key);
}
public void Remove(Regex pattern)
{
var copy = _memoryCacheKeys.ToDictionary(p => p.Key, p => p.Value);
var keys = copy.Select(p => p.Key).Where(k => pattern.IsMatch(k));
foreach (var key in keys)
{
CacheNotify.Publish(new AscCacheItem { Id = Guid.NewGuid().ToString() }, CacheNotifyAction.Any);
}
public static void OnClearCache()
{
var keys = MemoryCache.Default.Select(r => r.Key).ToList();
foreach (var k in keys)
{
MemoryCache.Default.Remove(k);
}
_memoryCache.Remove(key);
}
}
[Singletone]
public class AscCache : ICache
{
private IMemoryCache MemoryCache { get; }
private ConcurrentDictionary<string, object> MemoryCacheKeys { get; }
public ConcurrentDictionary<string, T> HashGetAll<T>(string key) =>
_memoryCache.GetOrCreate(key, r => new ConcurrentDictionary<string, T>());
public AscCache(IMemoryCache memoryCache)
public T HashGet<T>(string key, string field)
{
if (_memoryCache.TryGetValue<ConcurrentDictionary<string, T>>(key, out var dic)
&& dic.TryGetValue(field, out var value))
{
MemoryCache = memoryCache;
MemoryCacheKeys = new ConcurrentDictionary<string, object>();
}
public T Get<T>(string key) where T : class
{
return MemoryCache.Get<T>(key);
}
public void Insert(string key, object value, TimeSpan sligingExpiration)
{
var options = new MemoryCacheEntryOptions()
.SetSlidingExpiration(sligingExpiration)
.RegisterPostEvictionCallback(EvictionCallback);
MemoryCache.Set(key, value, options);
MemoryCacheKeys.TryAdd(key, null);
}
public void Insert(string key, object value, DateTime absolutExpiration)
{
var options = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(absolutExpiration == DateTime.MaxValue ? DateTimeOffset.MaxValue : new DateTimeOffset(absolutExpiration))
.RegisterPostEvictionCallback(EvictionCallback);
MemoryCache.Set(key, value, options);
MemoryCacheKeys.TryAdd(key, null);
return value;
}
private void EvictionCallback(object key, object value, EvictionReason reason, object state)
return default;
}
public void HashSet<T>(string key, string field, T value)
{
var dic = HashGetAll<T>(key);
if (value != null)
{
MemoryCacheKeys.TryRemove(key.ToString(), out _);
dic.AddOrUpdate(field, value, (k, v) => value);
_memoryCache.Set(key, dic, DateTime.MaxValue);
}
public void Remove(string key)
{
MemoryCache.Remove(key);
}
public void Remove(Regex pattern)
{
var copy = MemoryCacheKeys.ToDictionary(p => p.Key, p => p.Value);
var keys = copy.Select(p => p.Key).Where(k => pattern.IsMatch(k)).ToArray();
foreach (var key in keys)
{
MemoryCache.Remove(key);
}
}
public ConcurrentDictionary<string, T> HashGetAll<T>(string key)
{
return MemoryCache.GetOrCreate(key, r => new ConcurrentDictionary<string, T>());
}
public T HashGet<T>(string key, string field)
{
if (MemoryCache.TryGetValue<ConcurrentDictionary<string, T>>(key, out var dic) && dic.TryGetValue(field, out var value))
{
return value;
}
return default;
}
public void HashSet<T>(string key, string field, T value)
{
var dic = HashGetAll<T>(key);
if (value != null)
else if (dic != null)
{
dic.TryRemove(field, out _);
if (dic.IsEmpty)
{
dic.AddOrUpdate(field, value, (k, v) => value);
MemoryCache.Set(key, dic, DateTime.MaxValue);
}
else if (dic != null)
{
dic.TryRemove(field, out _);
if (dic.Count == 0)
{
MemoryCache.Remove(key);
}
else
{
MemoryCache.Set(key, dic, DateTime.MaxValue);
}
}
}
}
_memoryCache.Remove(key);
}
else
{
_memoryCache.Set(key, dic, DateTime.MaxValue);
}
}
}
private void EvictionCallback(object key, object value, EvictionReason reason, object state)
{
_memoryCacheKeys.TryRemove(key.ToString(), out _);
}
}

View File

@ -23,15 +23,14 @@
*
*/
namespace ASC.Common.Caching
namespace ASC.Common.Caching;
[Flags]
public enum CacheNotifyAction
{
[Flags]
public enum CacheNotifyAction
{
Insert = 1,
Update = 2,
Remove = 4,
InsertOrUpdate = Insert | Update,
Any = InsertOrUpdate | Remove,
}
}
Insert = 1,
Update = 2,
Remove = 4,
InsertOrUpdate = Insert | Update,
Any = InsertOrUpdate | Remove,
}

View File

@ -23,26 +23,24 @@
*
*/
namespace ASC.Common.Caching
namespace ASC.Common.Caching;
[Singletone(typeof(AscCache))]
public interface ICache
{
[Singletone(typeof(AscCache))]
public interface ICache
{
T Get<T>(string key) where T : class;
void Insert(string key, object value, TimeSpan sligingExpiration);
void Insert(string key, object value, DateTime absolutExpiration);
void Remove(string key);
void Remove(Regex pattern);
ConcurrentDictionary<string, T> HashGetAll<T>(string key);
T HashGet<T>(string key, string field);
void HashSet<T>(string key, string field, T value);
}
}
T Get<T>(string key) where T : class;
void Insert(string key, object value, TimeSpan sligingExpiration);
void Insert(string key, object value, DateTime absolutExpiration);
void Remove(string key);
void Remove(Regex pattern);
ConcurrentDictionary<string, T> HashGetAll<T>(string key);
T HashGet<T>(string key, string field);
void HashSet<T>(string key, string field, T value);
}

View File

@ -23,15 +23,14 @@
*
*/
namespace ASC.Common.Caching
{
[Singletone]
public interface ICacheNotify<T> where T : IMessage<T>, new()
{
void Publish(T obj, CacheNotifyAction action);
namespace ASC.Common.Caching;
void Subscribe(Action<T> onchange, CacheNotifyAction action);
void Unsubscribe(CacheNotifyAction action);
}
}
[Singletone]
public interface ICacheNotify<T> where T : IMessage<T>, new()
{
void Publish(T obj, CacheNotifyAction action);
void Subscribe(Action<T> onchange, CacheNotifyAction action);
void Unsubscribe(CacheNotifyAction action);
}

View File

@ -1,199 +0,0 @@
namespace ASC.Common.Caching
{
[Singletone]
public class KafkaCache<T> : IDisposable, ICacheNotify<T> where T : IMessage<T>, new()
{
private ClientConfig ClientConfig { get; set; }
private AdminClientConfig AdminClientConfig { get; set; }
private ILog Log { get; set; }
private ConcurrentDictionary<string, CancellationTokenSource> Cts { get; set; }
private ConcurrentDictionary<string, Action<T>> Actions { get; set; }
private ProtobufSerializer<T> ValueSerializer { get; } = new ProtobufSerializer<T>();
private ProtobufDeserializer<T> ValueDeserializer { get; } = new ProtobufDeserializer<T>();
private ProtobufSerializer<AscCacheItem> KeySerializer { get; } = new ProtobufSerializer<AscCacheItem>();
private ProtobufDeserializer<AscCacheItem> KeyDeserializer { get; } = new ProtobufDeserializer<AscCacheItem>();
private IProducer<AscCacheItem, T> Producer { get; set; }
private Guid Key { get; set; }
public KafkaCache(ConfigurationExtension configuration, IOptionsMonitor<ILog> options)
{
Log = options.CurrentValue;
Cts = new ConcurrentDictionary<string, CancellationTokenSource>();
Actions = new ConcurrentDictionary<string, Action<T>>();
Key = Guid.NewGuid();
var settings = configuration.GetSetting<KafkaSettings>("kafka");
ClientConfig = new ClientConfig { BootstrapServers = settings.BootstrapServers };
AdminClientConfig = new AdminClientConfig { BootstrapServers = settings.BootstrapServers };
}
public void Publish(T obj, CacheNotifyAction cacheNotifyAction)
{
try
{
if (Producer == null)
{
Producer = new ProducerBuilder<AscCacheItem, T>(new ProducerConfig(ClientConfig))
.SetErrorHandler((_, e) => Log.Error(e))
.SetKeySerializer(KeySerializer)
.SetValueSerializer(ValueSerializer)
.Build();
}
var channelName = GetChannelName(cacheNotifyAction);
if (Actions.TryGetValue(channelName, out var onchange))
{
onchange(obj);
}
var message = new Message<AscCacheItem, T>
{
Value = obj,
Key = new AscCacheItem
{
Id = Key.ToString()
}
};
Producer.ProduceAsync(channelName, message);
}
catch (ProduceException<Null, string> e)
{
Log.Error(e);
}
catch (Exception e)
{
Log.Error(e);
}
}
public void Subscribe(Action<T> onchange, CacheNotifyAction cacheNotifyAction)
{
var channelName = GetChannelName(cacheNotifyAction);
Cts[channelName] = new CancellationTokenSource();
Actions[channelName] = onchange;
void action()
{
var conf = new ConsumerConfig(ClientConfig)
{
GroupId = Guid.NewGuid().ToString()
};
using (var adminClient = new AdminClientBuilder(AdminClientConfig)
.SetErrorHandler((_, e) => Log.Error(e))
.Build())
{
try
{
//TODO: must add checking exist
adminClient.CreateTopicsAsync(
new TopicSpecification[]
{
new TopicSpecification
{
Name = channelName,
NumPartitions = 1,
ReplicationFactor = 1
}
}).Wait();
}
catch (AggregateException)
{
}
}
using var c = new ConsumerBuilder<AscCacheItem, T>(conf)
.SetErrorHandler((_, e) => Log.Error(e))
.SetKeyDeserializer(KeyDeserializer)
.SetValueDeserializer(ValueDeserializer)
.Build();
c.Assign(new TopicPartition(channelName, new Partition()));
try
{
while (true)
{
try
{
var cr = c.Consume(Cts[channelName].Token);
if (cr != null && cr.Message != null && cr.Message.Value != null && !(new Guid(cr.Message.Key.Id)).Equals(Key) && Actions.TryGetValue(channelName, out var act))
{
try
{
act(cr.Message.Value);
}
catch (Exception e)
{
Log.Error("Kafka onmessage", e);
}
}
}
catch (ConsumeException e)
{
Log.Error(e);
}
}
}
catch (OperationCanceledException)
{
c.Close();
}
}
var task = new Task(action, TaskCreationOptions.LongRunning);
task.Start();
}
private string GetChannelName(CacheNotifyAction cacheNotifyAction)
{
return $"ascchannel{cacheNotifyAction}{typeof(T).FullName}".ToLower();
}
public void Unsubscribe(CacheNotifyAction action)
{
Cts.TryGetValue(GetChannelName(action), out var source);
if (source != null)
{
source.Cancel();
}
}
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing && Producer != null)
{
Producer.Dispose();
}
disposedValue = true;
}
}
~KafkaCache()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
public class KafkaSettings
{
public string BootstrapServers { get; set; }
}
}

View File

@ -0,0 +1,196 @@
namespace ASC.Common.Caching;
[Singletone]
public class KafkaCacheNotify<T> : IDisposable, ICacheNotify<T> where T : IMessage<T>, new()
{
private IProducer<AscCacheItem, T> _producer;
private bool _disposedValue = false; // To detect redundant calls
private readonly ClientConfig _clientConfig;
private readonly AdminClientConfig _adminClientConfig;
private readonly ILog _logger;
private readonly ConcurrentDictionary<string, CancellationTokenSource> _cancelationToken;
private readonly ConcurrentDictionary<string, Action<T>> _actions;
private readonly ProtobufSerializer<T> _valueSerializer = new ProtobufSerializer<T>();
private readonly ProtobufDeserializer<T> _valueDeserializer = new ProtobufDeserializer<T>();
private readonly ProtobufSerializer<AscCacheItem> _keySerializer = new ProtobufSerializer<AscCacheItem>();
private readonly ProtobufDeserializer<AscCacheItem> _keyDeserializer = new ProtobufDeserializer<AscCacheItem>();
private readonly Guid _key;
public KafkaCacheNotify(ConfigurationExtension configuration, IOptionsMonitor<ILog> options)
{
_logger = options.CurrentValue;
_cancelationToken = new ConcurrentDictionary<string, CancellationTokenSource>();
_actions = new ConcurrentDictionary<string, Action<T>>();
_key = Guid.NewGuid();
var settings = configuration.GetSetting<KafkaSettings>("kafka");
_clientConfig = new ClientConfig { BootstrapServers = settings.BootstrapServers };
_adminClientConfig = new AdminClientConfig { BootstrapServers = settings.BootstrapServers };
}
public void Publish(T obj, CacheNotifyAction notifyAction)
{
try
{
if (_producer == null)
{
_producer = new ProducerBuilder<AscCacheItem, T>(new ProducerConfig(_clientConfig))
.SetErrorHandler((_, e) => _logger.Error(e))
.SetKeySerializer(_keySerializer)
.SetValueSerializer(_valueSerializer)
.Build();
}
var channelName = GetChannelName(notifyAction);
if (_actions.TryGetValue(channelName, out var onchange))
{
onchange(obj);
}
var message = new Message<AscCacheItem, T>
{
Value = obj,
Key = new AscCacheItem
{
Id = _key.ToString()
}
};
_producer.ProduceAsync(channelName, message);
}
catch (ProduceException<Null, string> e)
{
_logger.Error(e);
}
catch (Exception e)
{
_logger.Error(e);
}
}
public void Subscribe(Action<T> onchange, CacheNotifyAction notifyAction)
{
var channelName = GetChannelName(notifyAction);
_cancelationToken[channelName] = new CancellationTokenSource();
_actions[channelName] = onchange;
void action()
{
var conf = new ConsumerConfig(_clientConfig)
{
GroupId = Guid.NewGuid().ToString()
};
using (var adminClient = new AdminClientBuilder(_adminClientConfig)
.SetErrorHandler((_, e) => _logger.Error(e))
.Build())
{
try
{
//TODO: must add checking exist
adminClient.CreateTopicsAsync(
new TopicSpecification[]
{
new TopicSpecification
{
Name = channelName,
NumPartitions = 1,
ReplicationFactor = 1
}
}).Wait();
}
catch (AggregateException) { }
}
using var c = new ConsumerBuilder<AscCacheItem, T>(conf)
.SetErrorHandler((_, e) => _logger.Error(e))
.SetKeyDeserializer(_keyDeserializer)
.SetValueDeserializer(_valueDeserializer)
.Build();
c.Assign(new TopicPartition(channelName, new Partition()));
try
{
while (true)
{
try
{
var cr = c.Consume(_cancelationToken[channelName].Token);
if (cr != null && cr.Message != null && cr.Message.Value != null && !(new Guid(cr.Message.Key.Id)).Equals(_key) && _actions.TryGetValue(channelName, out var act))
{
try
{
act(cr.Message.Value);
}
catch (Exception e)
{
_logger.Error("Kafka onmessage", e);
}
}
}
catch (ConsumeException e)
{
_logger.Error(e);
}
}
}
catch (OperationCanceledException)
{
c.Close();
}
}
var task = new Task(action, TaskCreationOptions.LongRunning);
task.Start();
}
public void Unsubscribe(CacheNotifyAction notifyAction)
{
_cancelationToken.TryGetValue(GetChannelName(notifyAction), out var source);
if (source != null)
{
source.Cancel();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing && _producer != null)
{
_producer.Dispose();
}
_disposedValue = true;
}
}
~KafkaCacheNotify()
{
Dispose(false);
}
private string GetChannelName(CacheNotifyAction notifyAction)
{
return $"ascchannel{notifyAction}{typeof(T).FullName}".ToLower();
}
}
public class KafkaSettings
{
public string BootstrapServers { get; set; }
}

View File

@ -1,40 +1,39 @@
namespace ASC.Common.Caching
namespace ASC.Common.Caching;
[Singletone]
public class MemoryCacheNotify<T> : ICacheNotify<T> where T : IMessage<T>, new()
{
[Singletone]
public class MemoryCacheNotify<T> : ICacheNotify<T> where T : IMessage<T>, new()
private readonly ConcurrentDictionary<string, List<Action<T>>> _actions;
public MemoryCacheNotify()
{
private readonly ConcurrentDictionary<string, List<Action<T>>> _actions;
_actions = new ConcurrentDictionary<string, List<Action<T>>>();
}
public MemoryCacheNotify()
public void Publish(T obj, CacheNotifyAction notifyAction)
{
if (_actions.TryGetValue(GetKey(notifyAction), out var onchange) && onchange != null)
{
_actions = new ConcurrentDictionary<string, List<Action<T>>>();
}
public void Publish(T obj, CacheNotifyAction action)
{
if (_actions.TryGetValue(GetKey(action), out var onchange) && onchange != null)
{
Parallel.ForEach(onchange, a => a(obj));
}
}
public void Subscribe(Action<T> onchange, CacheNotifyAction notifyAction)
{
if (onchange != null)
{
_actions.GetOrAdd(GetKey(notifyAction), new List<Action<T>>())
.Add(onchange);
}
}
public void Unsubscribe(CacheNotifyAction action)
{
_actions.TryRemove(GetKey(action), out _);
}
private string GetKey(CacheNotifyAction cacheNotifyAction)
{
return $"asc:channel:{cacheNotifyAction}:{typeof(T).FullName}".ToLower();
Parallel.ForEach(onchange, a => a(obj));
}
}
public void Subscribe(Action<T> onchange, CacheNotifyAction notifyAction)
{
if (onchange != null)
{
_actions.GetOrAdd(GetKey(notifyAction), new List<Action<T>>())
.Add(onchange);
}
}
public void Unsubscribe(CacheNotifyAction notifyAction)
{
_actions.TryRemove(GetKey(notifyAction), out _);
}
private string GetKey(CacheNotifyAction notifyAction)
{
return $"asc:channel:{notifyAction}:{typeof(T).FullName}".ToLower();
}
}

View File

@ -1,37 +1,31 @@
namespace ASC.Common.Caching
namespace ASC.Common.Caching;
public class ProtobufSerializer<T> : ISerializer<T> where T : IMessage<T>, new()
{
public class ProtobufSerializer<T> : ISerializer<T> where T : IMessage<T>, new()
public byte[] Serialize(T data, SerializationContext context)
{
public byte[] Serialize(T data, SerializationContext context)
{
return data.ToByteArray();
}
}
public class ProtobufDeserializer<T> : IDeserializer<T> where T : IMessage<T>, new()
{
private readonly MessageParser<T> parser;
public ProtobufDeserializer()
{
parser = new MessageParser<T>(() => new T());
}
public T Deserialize(ReadOnlySpan<byte> data, bool isNull, SerializationContext context)
{
return parser.ParseFrom(data.ToArray());
}
}
public static class GuidExtension
{
public static ByteString ToByteString(this Guid id)
{
return ByteString.CopyFrom(id.ToByteArray());
}
public static Guid FromByteString(this ByteString id)
{
return new Guid(id.ToByteArray());
}
return data.ToByteArray();
}
}
public class ProtobufDeserializer<T> : IDeserializer<T> where T : IMessage<T>, new()
{
private readonly MessageParser<T> _parser;
public ProtobufDeserializer()
{
_parser = new MessageParser<T>(() => new T());
}
public T Deserialize(ReadOnlySpan<byte> data, bool isNull, SerializationContext context)
{
return _parser.ParseFrom(data.ToArray());
}
}
public static class GuidExtension
{
public static ByteString ToByteString(this Guid id) => ByteString.CopyFrom(id.ToByteArray());
public static Guid FromByteString(this ByteString id) => new Guid(id.ToByteArray());
}

View File

@ -17,11 +17,11 @@
namespace ASC.Common.Caching;
[Singletone]
public class RedisCache<T> : ICacheNotify<T> where T : IMessage<T>, new()
public class RedisCacheNotify<T> : ICacheNotify<T> where T : IMessage<T>, new()
{
private readonly IRedisDatabase _redis;
public RedisCache(IRedisCacheClient redisCacheClient)
public RedisCacheNotify(IRedisCacheClient redisCacheClient)
{
_redis = redisCacheClient.GetDbFromConfiguration();
}
@ -53,9 +53,9 @@ public class RedisCache<T> : ICacheNotify<T> where T : IMessage<T>, new()
.GetResult();
}
private string GetChannelName(CacheNotifyAction cacheNotifyAction)
private string GetChannelName(CacheNotifyAction action)
{
return $"asc:channel:{cacheNotifyAction}:{typeof(T).FullName}".ToLower();
return $"asc:channel:{action}:{typeof(T).FullName}".ToLower();
}
class RedisCachePubSubItem<T0>
@ -64,7 +64,4 @@ public class RedisCache<T> : ICacheNotify<T> where T : IMessage<T>, new()
public CacheNotifyAction Action { get; set; }
}
}
}

View File

@ -23,124 +23,120 @@
*
*/
namespace ASC.Collections
namespace ASC.Collections;
public abstract class CachedDictionaryBase<T>
{
public abstract class CachedDictionaryBase<T>
protected string BaseKey { get; set; }
protected Func<T, bool> Condition { get; set; }
public T this[string key] => Get(key);
public T this[Func<T> @default] => Get(@default);
protected abstract void InsertRootKey(string rootKey);
public void Clear()
{
protected string baseKey;
protected Func<T, bool> condition;
InsertRootKey(BaseKey);
}
public T this[string key]
public void Clear(string rootKey)
{
InsertRootKey(BuildKey(string.Empty, rootKey));
}
public void Reset(string key)
{
Reset(string.Empty, key);
}
public T Get(string key)
{
return Get(string.Empty, key, null);
}
public T Get(string key, Func<T> defaults)
{
return Get(string.Empty, key, defaults);
}
public void Add(string key, T newValue)
{
Add(string.Empty, key, newValue);
}
public bool HasItem(string key)
{
return !Equals(Get(key), default(T));
}
public T Get(Func<T> @default)
{
var key = string.Format("func {0} {2}.{1}({3})", @default.Method.ReturnType, @default.Method.Name,
@default.Method.DeclaringType.FullName,
string.Join(",",
@default.Method.GetGenericArguments().Select(x => x.FullName).ToArray
()));
return Get(key, @default);
}
public virtual T Get(string rootkey, string key, Func<T> defaults)
{
var fullKey = BuildKey(key, rootkey);
var objectCache = GetObjectFromCache(fullKey);
if (FitsCondition(objectCache))
{
get { return Get(key); }
OnHit(fullKey);
return ReturnCached(objectCache);
}
public T this[Func<T> @default]
if (defaults != null)
{
get { return Get(@default); }
OnMiss(fullKey);
var newValue = defaults();
if (Condition == null || Condition(newValue))
Add(rootkey, key, newValue);
return newValue;
}
protected abstract void InsertRootKey(string rootKey);
return default;
}
public void Clear()
{
InsertRootKey(baseKey);
}
public abstract void Add(string rootkey, string key, T newValue);
public void Clear(string rootKey)
{
InsertRootKey(BuildKey(string.Empty, rootKey));
}
public abstract void Reset(string rootKey, string key);
public void Reset(string key)
{
Reset(string.Empty, key);
}
protected virtual bool FitsCondition(object cached)
{
return cached is T;
}
public abstract void Reset(string rootKey, string key);
protected virtual T ReturnCached(object objectCache)
{
return (T)objectCache;
}
public T Get(string key)
{
return Get(string.Empty, key, null);
}
protected string BuildKey(string key, string rootkey)
{
return $"{BaseKey}-{rootkey}-{key}";
}
public T Get(string key, Func<T> defaults)
{
return Get(string.Empty, key, defaults);
}
protected abstract object GetObjectFromCache(string fullKey);
[Conditional("DEBUG")]
protected virtual void OnHit(string fullKey)
{
Debug.Print("cache hit:{0}", fullKey);
}
public void Add(string key, T newValue)
{
Add(string.Empty, key, newValue);
}
public abstract void Add(string rootkey, string key, T newValue);
public bool HasItem(string key)
{
return !Equals(Get(key), default(T));
}
protected string BuildKey(string key, string rootkey)
{
return string.Format("{0}-{1}-{2}", baseKey, rootkey, key);
}
protected abstract object GetObjectFromCache(string fullKey);
public T Get(Func<T> @default)
{
var key = string.Format("func {0} {2}.{1}({3})", @default.Method.ReturnType, @default.Method.Name,
@default.Method.DeclaringType.FullName,
string.Join(",",
@default.Method.GetGenericArguments().Select(x => x.FullName).ToArray
()));
return Get(key, @default);
}
protected virtual bool FitsCondition(object cached)
{
return cached != null && cached is T;
}
public virtual T Get(string rootkey, string key, Func<T> defaults)
{
var fullKey = BuildKey(key, rootkey);
var objectCache = GetObjectFromCache(fullKey);
if (FitsCondition(objectCache))
{
OnHit(fullKey);
return ReturnCached(objectCache);
}
if (defaults != null)
{
OnMiss(fullKey);
var newValue = defaults();
if (condition == null || condition(newValue))
{
Add(rootkey, key, newValue);
}
return newValue;
}
return default;
}
protected virtual T ReturnCached(object objectCache)
{
return (T)objectCache;
}
[Conditional("DEBUG")]
protected virtual void OnHit(string fullKey)
{
Debug.Print("cache hit:{0}", fullKey);
}
[Conditional("DEBUG")]
protected virtual void OnMiss(string fullKey)
{
Debug.Print("cache miss:{0}", fullKey);
}
[Conditional("DEBUG")]
protected virtual void OnMiss(string fullKey)
{
Debug.Print("cache miss:{0}", fullKey);
}
}

View File

@ -23,73 +23,68 @@
*
*/
namespace ASC.Collections
{
public sealed class HttpRequestDictionary<T> : CachedDictionaryBase<T>
{
private class CachedItem
{
internal T Value { get; set; }
internal CachedItem(T value)
{
Value = value;
}
namespace ASC.Collections;
public sealed class HttpRequestDictionary<T> : CachedDictionaryBase<T>
{
private readonly HttpContext _httpContext;
public HttpRequestDictionary(HttpContext httpContext, string baseKey)
{
Condition = (T) => true;
BaseKey = baseKey;
_httpContext = httpContext;
}
public override void Reset(string rootKey, string key)
{
if (_httpContext != null)
{
var builtkey = BuildKey(key, rootKey);
_httpContext.Items[builtkey] = null;
}
HttpContext HttpContext { get; set; }
public HttpRequestDictionary(HttpContext httpContext, string baseKey)
{
condition = (T) => true;
this.baseKey = baseKey;
HttpContext = httpContext;
}
protected override void InsertRootKey(string rootKey)
{
//We can't expire in HtppContext in such way
}
public override void Reset(string rootKey, string key)
{
if (HttpContext != null)
{
var builtkey = BuildKey(key, rootKey);
HttpContext.Items[builtkey] = null;
}
}
public override void Add(string rootkey, string key, T newValue)
{
if (HttpContext != null)
{
var builtkey = BuildKey(key, rootkey);
HttpContext.Items[builtkey] = new CachedItem(newValue);
}
}
protected override object GetObjectFromCache(string fullKey)
{
return HttpContext?.Items[fullKey];
}
protected override bool FitsCondition(object cached)
{
return cached is CachedItem;
}
protected override T ReturnCached(object objectCache)
{
return ((CachedItem)objectCache).Value;
}
protected override void OnHit(string fullKey)
{
}
protected override void OnMiss(string fullKey)
{
}
}
}
public override void Add(string rootkey, string key, T newValue)
{
if (_httpContext != null)
{
var builtkey = BuildKey(key, rootkey);
_httpContext.Items[builtkey] = new CachedItem(newValue);
}
}
protected override object GetObjectFromCache(string fullKey)
{
return _httpContext?.Items[fullKey];
}
protected override bool FitsCondition(object cached)
{
return cached is CachedItem;
}
protected override T ReturnCached(object objectCache)
{
return ((CachedItem)objectCache).Value;
}
protected override void OnHit(string fullKey) { }
protected override void OnMiss(string fullKey) { }
protected override void InsertRootKey(string rootKey)
{
//We can't expire in HtppContext in such way
}
private sealed class CachedItem
{
internal T Value { get; set; }
internal CachedItem(T value)
{
Value = value;
}
}
}

View File

@ -1,412 +1,436 @@
namespace ASC.Common
namespace ASC.Common;
public enum DIAttributeEnum
{
public enum DIAttributeEnum
Singletone,
Scope,
Transient
}
public class TransientAttribute : DIAttribute
{
public override DIAttributeEnum DIAttributeEnum => DIAttributeEnum.Transient;
public TransientAttribute() { }
public TransientAttribute(Type service) : base(service) { }
public TransientAttribute(Type service, Type implementation) : base(service, implementation) { }
public override void TryAdd(IServiceCollection services, Type service, Type implementation = null)
{
Singletone,
Scope,
Transient
}
public class TransientAttribute : DIAttribute
{
public override DIAttributeEnum DIAttributeEnum { get => DIAttributeEnum.Transient; }
public TransientAttribute() { }
public TransientAttribute(Type service) : base(service) { }
public TransientAttribute(Type service, Type implementation) : base(service, implementation) { }
public override void TryAdd(IServiceCollection services, Type service, Type implementation = null)
if (implementation != null)
{
if (implementation != null)
{
services.AddTransient(service, implementation);
}
else
{
services.AddTransient(service);
}
services.AddTransient(service, implementation);
}
else
{
services.AddTransient(service);
}
}
}
public class ScopeAttribute : DIAttribute
public class ScopeAttribute : DIAttribute
{
public override DIAttributeEnum DIAttributeEnum => DIAttributeEnum.Scope;
public ScopeAttribute() { }
public ScopeAttribute(Type service) : base(service) { }
public ScopeAttribute(Type service, Type implementation) : base(service, implementation) { }
public override void TryAdd(IServiceCollection services, Type service, Type implementation = null)
{
public override DIAttributeEnum DIAttributeEnum { get => DIAttributeEnum.Scope; }
public ScopeAttribute() { }
public ScopeAttribute(Type service) : base(service) { }
public ScopeAttribute(Type service, Type implementation) : base(service, implementation) { }
public override void TryAdd(IServiceCollection services, Type service, Type implementation = null)
if (implementation != null)
{
if (implementation != null)
{
services.AddScoped(service, implementation);
}
else
{
services.AddScoped(service);
}
services.AddScoped(service, implementation);
}
else
{
services.AddScoped(service);
}
}
}
public class SingletoneAttribute : DIAttribute
public class SingletoneAttribute : DIAttribute
{
public override DIAttributeEnum DIAttributeEnum => DIAttributeEnum.Singletone;
public SingletoneAttribute() { }
public SingletoneAttribute(Type service) : base(service) { }
public SingletoneAttribute(Type service, Type implementation) : base(service, implementation) { }
public override void TryAdd(IServiceCollection services, Type service, Type implementation = null)
{
public override DIAttributeEnum DIAttributeEnum { get => DIAttributeEnum.Singletone; }
public SingletoneAttribute() { }
public SingletoneAttribute(Type service) : base(service) { }
public SingletoneAttribute(Type service, Type implementation) : base(service, implementation) { }
public override void TryAdd(IServiceCollection services, Type service, Type implementation = null)
if (implementation != null)
{
if (implementation != null)
{
services.AddSingleton(service, implementation);
}
else
{
services.AddSingleton(service);
}
services.AddSingleton(service, implementation);
}
else
{
services.AddSingleton(service);
}
}
}
public abstract class DIAttribute : Attribute
public abstract class DIAttribute : Attribute
{
public abstract DIAttributeEnum DIAttributeEnum { get; }
public Type Implementation { get; }
public Type Service { get; }
public Type Additional { get; set; }
protected DIAttribute() { }
protected DIAttribute(Type service)
{
public abstract DIAttributeEnum DIAttributeEnum { get; }
public Type Implementation { get; }
public Type Service { get; }
public Type Additional { get; set; }
public DIAttribute() { }
public DIAttribute(Type service)
{
Service = service;
}
public DIAttribute(Type service, Type implementation)
{
Implementation = implementation;
Service = service;
}
public abstract void TryAdd(IServiceCollection services, Type service, Type implementation = null);
Service = service;
}
public class DIHelper
protected DIAttribute(Type service, Type implementation)
{
public Dictionary<DIAttributeEnum, List<string>> Services { get; set; }
public List<string> Added { get; set; }
public List<string> Configured { get; set; }
public IServiceCollection ServiceCollection { get; private set; }
Implementation = implementation;
Service = service;
}
public DIHelper()
{
Services = new Dictionary<DIAttributeEnum, List<string>>()
public abstract void TryAdd(IServiceCollection services, Type service, Type implementation = null);
}
public class DIHelper
{
public Dictionary<DIAttributeEnum, List<string>> Services { get; set; }
public List<string> Added { get; set; }
public List<string> Configured { get; set; }
public IServiceCollection ServiceCollection { get; private set; }
public DIHelper()
{
Services = new Dictionary<DIAttributeEnum, List<string>>()
{
{ DIAttributeEnum.Singletone, new List<string>() },
{ DIAttributeEnum.Scope, new List<string>() },
{ DIAttributeEnum.Transient, new List<string>() }
};
Added = new List<string>();
Configured = new List<string>();
}
public DIHelper(IServiceCollection serviceCollection) : this()
Added = new List<string>();
Configured = new List<string>();
}
public DIHelper(IServiceCollection serviceCollection) : this()
{
ServiceCollection = serviceCollection;
}
public void Configure(IServiceCollection serviceCollection)
{
ServiceCollection = serviceCollection;
}
public void RegisterProducts(IConfiguration configuration, string path)
{
var types = AutofacExtension.FindAndLoad(configuration, path);
foreach (var t in types.Select(Type.GetType).Where(r => r != null))
{
ServiceCollection = serviceCollection;
TryAdd(t);
}
}
public void Configure(IServiceCollection serviceCollection)
public bool TryAdd<TService>() where TService : class
{
return TryAdd(typeof(TService));
}
public bool TryAdd<TService, TImplementation>() where TService : class
{
return TryAdd(typeof(TService), typeof(TImplementation));
}
public bool TryAdd(Type service, Type implementation = null)
{
if (service.IsInterface && service.IsGenericType && implementation == null &&
(service.GetGenericTypeDefinition() == typeof(IOptionsSnapshot<>) ||
service.GetGenericTypeDefinition() == typeof(IOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
))
{
ServiceCollection = serviceCollection;
}
service = service.GetGenericArguments().FirstOrDefault();
public void RegisterProducts(IConfiguration configuration, string path)
{
var types = AutofacExtension.FindAndLoad(configuration, path);
foreach (var t in types.Select(Type.GetType).Where(r => r != null))
if (service == null)
{
TryAdd(t);
return false;
}
}
public bool TryAdd<TService>() where TService : class
var serviceName = $"{service}{implementation}";
if (Added.Contains(serviceName))
{
return TryAdd(typeof(TService));
return false;
}
public bool TryAdd<TService, TImplementation>() where TService : class
{
return TryAdd(typeof(TService), typeof(TImplementation));
}
Added.Add(serviceName);
public bool TryAdd(Type service, Type implementation = null)
var di = service.IsGenericType && (
service.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
) && implementation != null ? implementation.GetCustomAttribute<DIAttribute>() : service.GetCustomAttribute<DIAttribute>();
var isnew = false;
if (di != null)
{
if (service.IsInterface && service.IsGenericType && implementation == null &&
(service.GetGenericTypeDefinition() == typeof(IOptionsSnapshot<>) ||
service.GetGenericTypeDefinition() == typeof(IOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
))
if (di.Additional != null)
{
service = service.GetGenericArguments().FirstOrDefault();
if (service == null)
var m = di.Additional.GetMethod("Register", BindingFlags.Public | BindingFlags.Static);
m.Invoke(null, new[] { this });
}
if (!service.IsInterface || implementation != null)
{
isnew = implementation != null ? Register(service, implementation) : Register(service);
if (!isnew)
{
return false;
}
}
var serviceName = $"{service}{implementation}";
if (Added.Contains(serviceName)) return false;
Added.Add(serviceName);
var di = service.IsGenericType && (
service.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
) && implementation != null ? implementation.GetCustomAttribute<DIAttribute>() : service.GetCustomAttribute<DIAttribute>();
var isnew = false;
if (di != null)
if (service.IsInterface && implementation == null || !service.IsInterface)
{
if (di.Additional != null)
if (di.Service != null)
{
var m = di.Additional.GetMethod("Register", BindingFlags.Public | BindingFlags.Static);
m.Invoke(null, new[] { this });
}
var a = di.Service.GetInterfaces().FirstOrDefault(x => x.IsGenericType && (
x.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
));
if (!service.IsInterface || implementation != null)
{
isnew = implementation != null ? Register(service, implementation) : Register(service);
if (!isnew) return false;
}
if (service.IsInterface && implementation == null || !service.IsInterface)
{
if (di.Service != null)
if (a != null)
{
var a = di.Service.GetInterfaces().FirstOrDefault(x => x.IsGenericType && (
x.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
));
if (a != null)
if (!a.ContainsGenericParameters)
{
if (!a.ContainsGenericParameters)
{
var b = a.GetGenericArguments();
var b = a.GetGenericArguments();
foreach (var g in b)
foreach (var g in b)
{
if (g != service)
{
if (g != service)
TryAdd(g);
if (service.IsInterface && di.Implementation == null)
{
TryAdd(g);
if (service.IsInterface && di.Implementation == null)
{
TryAdd(service, g);
}
TryAdd(service, g);
}
}
TryAdd(a, di.Service);
}
else
{
Type c = null;
var a1 = a.GetGenericTypeDefinition();
var b = a.GetGenericArguments().FirstOrDefault();
if (b != null && b.IsGenericType)
{
var b1 = b.GetGenericTypeDefinition().MakeGenericType(service.GetGenericArguments());
TryAdd(b1);
c = a1.MakeGenericType(b1);
}
else
{
c = a1.MakeGenericType(service.GetGenericArguments());
}
TryAdd(c, di.Service.MakeGenericType(service.GetGenericArguments()));
//a, di.Service
}
TryAdd(a, di.Service);
}
else
{
if (di.Implementation == null)
Type c;
var a1 = a.GetGenericTypeDefinition();
var b = a.GetGenericArguments().FirstOrDefault();
if (b != null && b.IsGenericType)
{
isnew = Register(service, di.Service);
TryAdd(di.Service);
var b1 = b.GetGenericTypeDefinition().MakeGenericType(service.GetGenericArguments());
TryAdd(b1);
c = a1.MakeGenericType(b1);
}
else
{
Register(di.Service);
c = a1.MakeGenericType(service.GetGenericArguments());
}
TryAdd(c, di.Service.MakeGenericType(service.GetGenericArguments()));
//a, di.Service
}
}
if (di.Implementation != null)
else
{
var a = di.Implementation.GetInterfaces().FirstOrDefault(x => x.IsGenericType &&
(x.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>))
);
if (a != null)
if (di.Implementation == null)
{
if (!a.ContainsGenericParameters)
{
var b = a.GetGenericArguments();
foreach (var g in b)
{
if (g != service)
{
//TryAdd(g);
if (service.IsInterface && implementation == null)
{
TryAdd(service, g);
}
}
}
TryAdd(a, di.Implementation);
}
else
{
Type c = null;
var a1 = a.GetGenericTypeDefinition();
var b = a.GetGenericArguments().FirstOrDefault();
if (b != null && b.IsGenericType)
{
var b1 = b.GetGenericTypeDefinition().MakeGenericType(service.GetGenericArguments());
TryAdd(b1);
c = a1.MakeGenericType(b1);
}
else
{
c = a1.MakeGenericType(service.GetGenericArguments());
}
TryAdd(c, di.Implementation.MakeGenericType(service.GetGenericArguments()));
//a, di.Service
}
isnew = Register(service, di.Service);
TryAdd(di.Service);
}
else
{
isnew = TryAdd(service, di.Implementation);
Register(di.Service);
}
}
}
}
if (isnew)
{
ConstructorInfo[] props = null;
if (!service.IsInterface)
if (di.Implementation != null)
{
props = service.GetConstructors();
}
else if (implementation != null)
{
props = implementation.GetConstructors();
}
else if (di.Service != null)
{
props = di.Service.GetConstructors();
}
if (props != null)
{
var par = props.SelectMany(r => r.GetParameters()).Distinct();
foreach (var p1 in par)
var a = di.Implementation.GetInterfaces().FirstOrDefault(x => x.IsGenericType &&
(x.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>))
);
if (a != null)
{
TryAdd(p1.ParameterType);
if (!a.ContainsGenericParameters)
{
var b = a.GetGenericArguments();
foreach (var g in b)
{
if (g != service)
{
//TryAdd(g);
if (service.IsInterface && implementation == null)
{
TryAdd(service, g);
}
}
}
TryAdd(a, di.Implementation);
}
else
{
Type c;
var a1 = a.GetGenericTypeDefinition();
var b = a.GetGenericArguments().FirstOrDefault();
if (b != null && b.IsGenericType)
{
var b1 = b.GetGenericTypeDefinition().MakeGenericType(service.GetGenericArguments());
TryAdd(b1);
c = a1.MakeGenericType(b1);
}
else
{
c = a1.MakeGenericType(service.GetGenericArguments());
}
TryAdd(c, di.Implementation.MakeGenericType(service.GetGenericArguments()));
//a, di.Service
}
}
else
{
isnew = TryAdd(service, di.Implementation);
}
}
}
return isnew;
}
private bool Register(Type service, Type implementation = null)
if (isnew)
{
if (service.IsSubclassOf(typeof(ControllerBase)) || service.GetInterfaces().Contains(typeof(IResourceFilter)) || service.GetInterfaces().Contains(typeof(IDictionary<string, string>))) return true;
var c = service.IsGenericType && (
service.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
) && implementation != null ? implementation.GetCustomAttribute<DIAttribute>() : service.GetCustomAttribute<DIAttribute>();
var serviceName = $"{service}{implementation}";
ConstructorInfo[] props = null;
if (!Services[c.DIAttributeEnum].Contains(serviceName))
if (!service.IsInterface)
{
c.TryAdd(ServiceCollection, service, implementation);
Services[c.DIAttributeEnum].Add(serviceName);
return true;
props = service.GetConstructors();
}
else if (implementation != null)
{
props = implementation.GetConstructors();
}
else if (di.Service != null)
{
props = di.Service.GetConstructors();
}
return false;
}
public DIHelper TryAddSingleton<TService>(Func<IServiceProvider, TService> implementationFactory) where TService : class
{
var serviceName = $"{typeof(TService)}";
if (!Services[DIAttributeEnum.Singletone].Contains(serviceName))
if (props != null)
{
Services[DIAttributeEnum.Singletone].Add(serviceName);
ServiceCollection.TryAddSingleton(implementationFactory);
}
var par = props.SelectMany(r => r.GetParameters()).Distinct();
return this;
foreach (var p1 in par)
{
TryAdd(p1.ParameterType);
}
}
}
public DIHelper TryAddSingleton<TService, TImplementation>() where TService : class where TImplementation : class, TService
{
var serviceName = $"{typeof(TService)}{typeof(TImplementation)}";
if (!Services[DIAttributeEnum.Singletone].Contains(serviceName))
{
Services[DIAttributeEnum.Singletone].Add(serviceName);
ServiceCollection.TryAddSingleton<TService, TImplementation>();
}
return this;
}
public DIHelper Configure<TOptions>(Action<TOptions> configureOptions) where TOptions : class
{
var serviceName = $"{typeof(TOptions)}";
if (!Configured.Contains(serviceName))
{
Configured.Add(serviceName);
ServiceCollection.Configure(configureOptions);
}
return this;
}
public DIHelper Configure<TOptions>(string name, Action<TOptions> configureOptions) where TOptions : class
{
var serviceName = $"{typeof(TOptions)}{name}";
if (!Configured.Contains(serviceName))
{
Configured.Add(serviceName);
ServiceCollection.Configure(name, configureOptions);
}
return this;
}
return isnew;
}
}
public DIHelper TryAddSingleton<TService>(Func<IServiceProvider, TService> implementationFactory) where TService : class
{
var serviceName = $"{typeof(TService)}";
if (!Services[DIAttributeEnum.Singletone].Contains(serviceName))
{
Services[DIAttributeEnum.Singletone].Add(serviceName);
ServiceCollection.TryAddSingleton(implementationFactory);
}
return this;
}
public DIHelper TryAddSingleton<TService, TImplementation>() where TService : class where TImplementation : class, TService
{
var serviceName = $"{typeof(TService)}{typeof(TImplementation)}";
if (!Services[DIAttributeEnum.Singletone].Contains(serviceName))
{
Services[DIAttributeEnum.Singletone].Add(serviceName);
ServiceCollection.TryAddSingleton<TService, TImplementation>();
}
return this;
}
public DIHelper Configure<TOptions>(Action<TOptions> configureOptions) where TOptions : class
{
var serviceName = $"{typeof(TOptions)}";
if (!Configured.Contains(serviceName))
{
Configured.Add(serviceName);
ServiceCollection.Configure(configureOptions);
}
return this;
}
public DIHelper Configure<TOptions>(string name, Action<TOptions> configureOptions) where TOptions : class
{
var serviceName = $"{typeof(TOptions)}{name}";
if (!Configured.Contains(serviceName))
{
Configured.Add(serviceName);
ServiceCollection.Configure(name, configureOptions);
}
return this;
}
private bool Register(Type service, Type implementation = null)
{
if (service.IsSubclassOf(typeof(ControllerBase)) || service.GetInterfaces().Contains(typeof(IResourceFilter))
|| service.GetInterfaces().Contains(typeof(IDictionary<string, string>)))
{
return true;
}
var c = service.IsGenericType && (
service.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
) && implementation != null ? implementation.GetCustomAttribute<DIAttribute>() : service.GetCustomAttribute<DIAttribute>();
var serviceName = $"{service}{implementation}";
if (!Services[c.DIAttributeEnum].Contains(serviceName))
{
c.TryAdd(ServiceCollection, service, implementation);
Services[c.DIAttributeEnum].Add(serviceName);
return true;
}
return false;
}
}

View File

@ -22,6 +22,8 @@
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
namespace ASC.Common.Data;
public static class StreamExtension
{
@ -29,12 +31,13 @@ public static class StreamExtension
public static void StreamCopyTo(this Stream srcStream, Stream dstStream, int length)
{
if (srcStream == null) throw new ArgumentNullException("srcStream");
if (dstStream == null) throw new ArgumentNullException("dstStream");
if (srcStream == null) throw new ArgumentNullException(nameof(srcStream));
if (dstStream == null) throw new ArgumentNullException(nameof(dstStream));
var buffer = new byte[BufferSize];
int totalRead = 0;
int readed;
while ((readed = srcStream.Read(buffer, 0, length - totalRead > BufferSize ? BufferSize : length - totalRead)) > 0 && totalRead < length)
{
dstStream.Write(buffer, 0, readed);

View File

@ -14,70 +14,71 @@
*
*/
namespace System.IO
namespace System.IO;
[Singletone]
public class TempPath
{
[Singletone]
public class TempPath
private readonly string _tempFolder;
public TempPath(IConfiguration configuration)
{
readonly string tempFolder;
public TempPath(IConfiguration configuration)
string rootFolder = AppContext.BaseDirectory;
if (string.IsNullOrEmpty(rootFolder))
{
string rootFolder = AppContext.BaseDirectory;
if (string.IsNullOrEmpty(rootFolder))
{
rootFolder = Assembly.GetEntryAssembly().Location;
}
tempFolder = configuration["temp"] ?? Path.Combine("..", "Data", "temp");
if (!Path.IsPathRooted(tempFolder))
{
tempFolder = Path.GetFullPath(Path.Combine(rootFolder, tempFolder));
}
if (!Directory.Exists(tempFolder))
{
Directory.CreateDirectory(tempFolder);
}
rootFolder = Assembly.GetEntryAssembly().Location;
}
public string GetTempPath()
_tempFolder = configuration["temp"] ?? Path.Combine("..", "Data", "temp");
if (!Path.IsPathRooted(_tempFolder))
{
return tempFolder;
_tempFolder = Path.GetFullPath(Path.Combine(rootFolder, _tempFolder));
}
public string GetTempFileName()
if (!Directory.Exists(_tempFolder))
{
FileStream f = null;
string path;
var count = 0;
do
{
path = Path.Combine(tempFolder, Path.GetRandomFileName());
try
{
using (f = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read))
{
return path;
}
}
catch (IOException ex)
{
if (ex.HResult != -2147024816 || count++ > 65536)
throw;
}
catch (UnauthorizedAccessException ex)
{
if (count++ > 65536)
throw new IOException(ex.Message, ex);
}
} while (f == null);
return path;
Directory.CreateDirectory(_tempFolder);
}
}
}
public string GetTempPath()
{
return _tempFolder;
}
public string GetTempFileName()
{
FileStream f = null;
string path;
var count = 0;
do
{
path = Path.Combine(_tempFolder, Path.GetRandomFileName());
try
{
using (f = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read))
{
return path;
}
}
catch (IOException ex)
{
if (ex.HResult != -2147024816 || count++ > 65536)
{
throw;
}
}
catch (UnauthorizedAccessException ex)
{
if (count++ > 65536)
{
throw new IOException(ex.Message, ex);
}
}
} while (f == null);
return path;
}
}

View File

@ -14,35 +14,37 @@
*
*/
namespace ASC.Common
namespace ASC.Common;
[Singletone]
public class TempStream
{
[Singletone]
public class TempStream
private readonly TempPath _tempPath;
public TempStream(TempPath tempPath)
{
private TempPath TempPath { get; }
_tempPath = tempPath;
}
public TempStream(TempPath tempPath)
public Stream GetBuffered(Stream srcStream)
{
if (srcStream == null) throw new ArgumentNullException(nameof(srcStream));
if (!srcStream.CanSeek || srcStream.CanTimeout)
{
TempPath = tempPath;
//Buffer it
var memStream = Create();
srcStream.CopyTo(memStream);
memStream.Position = 0;
return memStream;
}
public Stream GetBuffered(Stream srcStream)
{
if (srcStream == null) throw new ArgumentNullException("srcStream");
if (!srcStream.CanSeek || srcStream.CanTimeout)
{
//Buffer it
var memStream = Create();
srcStream.CopyTo(memStream);
memStream.Position = 0;
return memStream;
}
return srcStream;
}
return srcStream;
}
public Stream Create()
{
return new FileStream(TempPath.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose);
}
public Stream Create()
{
return new FileStream(_tempPath.GetTempFileName(), FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose);
}
}

View File

@ -1,154 +1,162 @@
namespace ASC.Common.DependencyInjection
{
internal class AutofacComponent
{
public string Type { get; set; }
public IEnumerable<AutofacService> Services { get; set; }
}
internal class AutofacService
{
public string Type { get; set; }
}
namespace ASC.Common.DependencyInjection;
public static class AutofacExtension
internal class AutofacComponent
{
public string Type { get; set; }
public IEnumerable<AutofacService> Services { get; set; }
}
internal class AutofacService
{
public string Type { get; set; }
}
public static class AutofacExtension
{
public static void Register(this ContainerBuilder builder, IConfiguration configuration,
bool loadproducts = true, bool loadconsumers = true, params string[] intern)
{
public static void Register(this ContainerBuilder builder, IConfiguration configuration, bool loadproducts = true, bool loadconsumers = true, params string[] intern)
{
var modules = new List<(bool, string)>
var modules = new List<(bool, string)>
{
(true, "autofac.json")
};
if (loadproducts)
{
modules.Add((true, "autofac.products.json"));
}
if (loadconsumers)
{
modules.Add((true, "autofac.consumers.json"));
}
if (intern != null)
{
modules.AddRange(intern.Select(r => (false, r)));
}
foreach (var p in modules)
{
var config = new ConfigurationBuilder();
if (p.Item1)
{
config.SetBasePath(configuration["pathToConf"]);
}
config.AddJsonFile(p.Item2);
var root = config.Build();
var module = new ConfigurationModule(root);
builder.RegisterModule(module);
}
return;
if (loadproducts)
{
modules.Add((true, "autofac.products.json"));
}
public static List<string> FindAndLoad(IConfiguration configuration, string currentDir, string section = "autofac.products.json")
if (loadconsumers)
{
modules.Add((true, "autofac.consumers.json"));
}
if (intern != null)
{
modules.AddRange(intern.Select(r => (false, r)));
}
foreach (var p in modules)
{
var config = new ConfigurationBuilder();
config.SetBasePath(configuration["pathToConf"]);
config.AddJsonFile(section);
var root = config.Build();
var sectionSettings = root.GetSection("components");
if (sectionSettings == null)
if (p.Item1)
{
return new List<string>();
config.SetBasePath(configuration["pathToConf"]);
}
var folder = configuration["core:products:folder"];
var subfolder = configuration["core:products:subfolder"];
string productsDir;
config.AddJsonFile(p.Item2);
if (!Path.IsPathRooted(folder))
var root = config.Build();
var module = new ConfigurationModule(root);
builder.RegisterModule(module);
}
return;
}
public static List<string> FindAndLoad(IConfiguration configuration, string currentDir, string section = "autofac.products.json")
{
var config = new ConfigurationBuilder();
config.SetBasePath(configuration["pathToConf"]);
config.AddJsonFile(section);
var root = config.Build();
var sectionSettings = root.GetSection("components");
if (sectionSettings == null)
{
return new List<string>();
}
var folder = configuration["core:products:folder"];
var subfolder = configuration["core:products:subfolder"];
string productsDir;
if (!Path.IsPathRooted(folder))
{
if (currentDir.EndsWith(CrossPlatform.PathCombine(Path.GetFileName(folder), Assembly.GetEntryAssembly().GetName().Name, subfolder)))
{
if (currentDir.EndsWith(CrossPlatform.PathCombine(Path.GetFileName(folder), Assembly.GetEntryAssembly().GetName().Name, subfolder)))
{
productsDir = Path.GetFullPath(CrossPlatform.PathCombine("..", ".."));
}
else
{
productsDir = Path.GetFullPath(CrossPlatform.PathCombine(currentDir, folder));
}
productsDir = Path.GetFullPath(CrossPlatform.PathCombine("..", ".."));
}
else
{
productsDir = folder;
productsDir = Path.GetFullPath(CrossPlatform.PathCombine(currentDir, folder));
}
}
else
{
productsDir = folder;
}
var cs = new List<AutofacComponent>();
sectionSettings.Bind(cs);
var cs = new List<AutofacComponent>();
sectionSettings.Bind(cs);
var types = new List<string>();
var types = new List<string>();
foreach (var component in cs)
foreach (var component in cs)
{
try
{
try
{
LoadAssembly(component.Type);
types.Add(component.Type);
}
catch (System.Exception)
{
//TODO
}
LoadAssembly(component.Type);
types.Add(component.Type);
}
return types;
void LoadAssembly(string type)
catch (System.Exception)
{
var dll = type.Substring(type.IndexOf(",") + 1).Trim();
var path = GetFullPath(dll);
if (!string.IsNullOrEmpty(path))
{
AssemblyLoadContext.Default.Resolving += new Resolver(path).Resolving;
}
}
string GetFullPath(string n)
{
var productPath = CrossPlatform.PathCombine(productsDir, n, subfolder);
return GetPath(CrossPlatform.PathCombine(productPath, "bin"), n, SearchOption.AllDirectories) ?? GetPath(productPath, n, SearchOption.TopDirectoryOnly);
}
static string GetPath(string dirPath, string dll, SearchOption searchOption)
{
if (!Directory.Exists(dirPath)) return null;
return Directory.GetFiles(dirPath, $"{dll}.dll", searchOption).FirstOrDefault();
//TODO
}
}
}
return types;
class Resolver
{
private string ResolvePath { get; set; }
public Resolver(string assemblyPath)
void LoadAssembly(string type)
{
ResolvePath = assemblyPath;
var dll = type.Substring(type.IndexOf(',') + 1).Trim();
var path = GetFullPath(dll);
if (!string.IsNullOrEmpty(path))
{
AssemblyLoadContext.Default.Resolving += new Resolver(path).Resolving;
}
}
public Assembly Resolving(AssemblyLoadContext context, AssemblyName assemblyName)
string GetFullPath(string n)
{
var path = CrossPlatform.PathCombine(Path.GetDirectoryName(ResolvePath), $"{assemblyName.Name}.dll");
var productPath = CrossPlatform.PathCombine(productsDir, n, subfolder);
if (!File.Exists(path)) return null;
return GetPath(CrossPlatform.PathCombine(productPath, "bin"), n, SearchOption.AllDirectories)
?? GetPath(productPath, n, SearchOption.TopDirectoryOnly);
}
return context.LoadFromAssemblyPath(path);
static string GetPath(string dirPath, string dll, SearchOption searchOption)
{
if (!Directory.Exists(dirPath))
{
return null;
}
return Directory.GetFiles(dirPath, $"{dll}.dll", searchOption).FirstOrDefault();
}
}
}
class Resolver
{
private readonly string _resolvePath;
public Resolver(string assemblyPath)
{
_resolvePath = assemblyPath;
}
public Assembly Resolving(AssemblyLoadContext context, AssemblyName assemblyName)
{
var path = CrossPlatform.PathCombine(Path.GetDirectoryName(_resolvePath), $"{assemblyName.Name}.dll");
if (!File.Exists(path))
{
return null;
}
return context.LoadFromAssemblyPath(path);
}
}

View File

@ -23,30 +23,23 @@
*
*/
namespace ASC.Geolocation
{
public class IPGeolocationInfo
{
public string Key { get; set; }
public string City { get; set; }
namespace ASC.Geolocation;
public double TimezoneOffset { get; set; }
public class IPGeolocationInfo
{
public string Key { get; set; }
public string City { get; set; }
public double TimezoneOffset { get; set; }
public string TimezoneName { get; set; }
public string IPStart { get; set; }
public string IPEnd { get; set; }
public string TimezoneName { get; set; }
public string IPStart { get; set; }
public string IPEnd { get; set; }
public readonly static IPGeolocationInfo Default = new IPGeolocationInfo
{
Key = string.Empty,
IPStart = string.Empty,
IPEnd = string.Empty,
City = string.Empty,
TimezoneName = string.Empty,
};
}
public readonly static IPGeolocationInfo Default = new IPGeolocationInfo
{
Key = string.Empty,
IPStart = string.Empty,
IPEnd = string.Empty,
City = string.Empty,
TimezoneName = string.Empty,
};
}

View File

@ -21,6 +21,8 @@ global using System.Threading.Tasks;
global using System.Web;
global using System.Xml.Linq;
global using System.Xml.XPath;
global using System.ServiceModel;
global using System.Runtime.Serialization;
global using ARSoft.Tools.Net;
global using ARSoft.Tools.Net.Dns;

View File

@ -1,92 +1,93 @@
using ILogger = Microsoft.Extensions.Logging.ILogger;
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
namespace ASC.Common.Logging
namespace ASC.Common.Logging;
[Singletone]
public class EFLoggerFactory : ILoggerFactory
{
[Singletone]
public class EFLoggerFactory : ILoggerFactory
private readonly Lazy<ILogger> _logger;
private readonly ILoggerProvider _loggerProvider;
public EFLoggerFactory(EFLoggerProvider loggerProvider)
{
Lazy<ILogger> Logger { get; set; }
ILoggerProvider LoggerProvider { get; set; }
public EFLoggerFactory(EFLoggerProvider loggerProvider)
{
LoggerProvider = loggerProvider;
Logger = new Lazy<ILogger>(() => LoggerProvider.CreateLogger(""));
}
public void AddProvider(ILoggerProvider provider)
{
//LoggerProvider = provider;
}
public ILogger CreateLogger(string categoryName)
{
return Logger.Value;
}
public void Dispose()
{
}
_loggerProvider = loggerProvider;
_logger = new Lazy<ILogger>(() => _loggerProvider.CreateLogger(""));
}
[Singletone]
public class EFLoggerProvider : ILoggerProvider
public void AddProvider(ILoggerProvider provider)
{
private IOptionsMonitor<ILog> Option { get; }
public EFLoggerProvider(IOptionsMonitor<ILog> option)
{
Option = option;
}
public ILogger CreateLogger(string categoryName)
{
return new EFLogger(Option.Get("ASC.SQL"));
}
public void Dispose() { }
//LoggerProvider = provider;
}
public class EFLogger : ILogger
public ILogger CreateLogger(string categoryName)
{
public ILog CustomLogger { get; }
return _logger.Value;
}
public EFLogger(ILog customLogger)
public void Dispose() { }
}
[Singletone]
public class EFLoggerProvider : ILoggerProvider
{
private readonly IOptionsMonitor<ILog> _option;
public EFLoggerProvider(IOptionsMonitor<ILog> option)
{
_option = option;
}
public ILogger CreateLogger(string categoryName)
{
return new EFLogger(_option.Get("ASC.SQL"));
}
public void Dispose() { }
}
public class EFLogger : ILogger
{
public ILog CustomLogger { get; }
public EFLogger(ILog customLogger)
{
CustomLogger = customLogger;
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return logLevel switch
{
CustomLogger = customLogger;
}
LogLevel.Trace => CustomLogger.IsTraceEnabled,
LogLevel.Information => CustomLogger.IsInfoEnabled,
LogLevel.None => false,
public IDisposable BeginScope<TState>(TState state) { return null; }
public bool IsEnabled(LogLevel logLevel)
LogLevel.Debug => CustomLogger.IsDebugEnabled,
LogLevel.Warning => CustomLogger.IsWarnEnabled,
LogLevel.Error => CustomLogger.IsErrorEnabled,
LogLevel.Critical => CustomLogger.IsErrorEnabled,
_ => true,
};
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
switch (eventId.Id)
{
return logLevel switch
{
LogLevel.Trace => CustomLogger.IsTraceEnabled,
LogLevel.Information => CustomLogger.IsInfoEnabled,
LogLevel.None => false,
LogLevel.Debug => CustomLogger.IsDebugEnabled,
LogLevel.Warning => CustomLogger.IsWarnEnabled,
LogLevel.Error => CustomLogger.IsErrorEnabled,
LogLevel.Critical => CustomLogger.IsErrorEnabled,
_ => true,
};
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
switch (eventId.Id)
{
//case 20000:
// CustomLogger.Debug(formatter(state, exception));
// break;
case 20101:
var keyValuePairs = state as IEnumerable<KeyValuePair<string, object>>;
CustomLogger.DebugWithProps("", keyValuePairs);
break;
}
//case 20000:
// CustomLogger.Debug(formatter(state, exception));
// break;
case 20101:
var keyValuePairs = state as IEnumerable<KeyValuePair<string, object>>;
CustomLogger.DebugWithProps("", keyValuePairs);
break;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -23,87 +23,89 @@
*
*/
namespace ASC.Common.Logging
{
public class SelfCleaningAppender : RollingFileAppender
{
private static DateTime _lastCleanDate;
private static int? _cleanPeriod;
private static int GetCleanPeriod()
{
if (_cleanPeriod != null)
return _cleanPeriod.Value;
const string key = "CleanPeriod";
var value = 30;
var repo = log4net.LogManager.GetRepository(Assembly.GetCallingAssembly());
if (repo != null && repo.Properties.GetKeys().Contains(key))
{
int.TryParse(repo.Properties[key].ToString(), out value);
}
_cleanPeriod = value;
return value;
}
private void Clean()
{
try
{
if (string.IsNullOrEmpty(File))
return;
namespace ASC.Common.Logging;
var fileInfo = new FileInfo(File);
if (!fileInfo.Exists)
return;
var directory = fileInfo.Directory;
if (directory == null || !directory.Exists)
return;
var files = directory.GetFiles();
var cleanPeriod = GetCleanPeriod();
foreach (var file in files.Where(file => (DateTime.UtcNow.Date - file.CreationTimeUtc.Date).Days > cleanPeriod))
{
file.Delete();
}
}
catch (Exception err)
{
LogLog.Error(GetType(), err.Message, err);
}
}
protected override void Append(LoggingEvent loggingEvent)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
public class SelfCleaningAppender : RollingFileAppender
{
private static DateTime _lastCleanDate;
private static int? _cleanPeriod;
base.Append(loggingEvent);
protected override void Append(LoggingEvent loggingEvent)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
protected override void Append(LoggingEvent[] loggingEvents)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
base.Append(loggingEvent);
}
protected override void Append(LoggingEvent[] loggingEvents)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
base.Append(loggingEvents);
}
private static int GetCleanPeriod()
{
if (_cleanPeriod != null)
{
return _cleanPeriod.Value;
}
const string key = "CleanPeriod";
var value = 30;
var repo = log4net.LogManager.GetRepository(Assembly.GetCallingAssembly());
if (repo != null && repo.Properties.GetKeys().Contains(key))
{
int.TryParse(repo.Properties[key].ToString(), out value);
}
_cleanPeriod = value;
return value;
}
private void Clean()
{
try
{
if (string.IsNullOrEmpty(File))
{
return;
}
base.Append(loggingEvents);
}
}
var fileInfo = new FileInfo(File);
if (!fileInfo.Exists)
{
return;
}
var directory = fileInfo.Directory;
if (directory == null || !directory.Exists)
{
return;
}
var files = directory.GetFiles();
var cleanPeriod = GetCleanPeriod();
foreach (var file in files.Where(file => (DateTime.UtcNow.Date - file.CreationTimeUtc.Date).Days > cleanPeriod))
{
file.Delete();
}
}
catch (Exception err)
{
LogLog.Error(GetType(), err.Message, err);
}
}
}

View File

@ -25,118 +25,125 @@
using LogLevel = NLog.LogLevel;
namespace ASC.Common.Logging
{
[Target("SelfCleaning")]
public class SelfCleaningTarget : FileTarget
{
private static DateTime _lastCleanDate;
private static int? _cleanPeriod;
private static int GetCleanPeriod()
{
if (_cleanPeriod != null)
return _cleanPeriod.Value;
var value = 30;
const string key = "cleanPeriod";
if (NLog.LogManager.Configuration.Variables.Keys.Contains(key))
{
var variable = NLog.LogManager.Configuration.Variables[key];
if (variable != null && !string.IsNullOrEmpty(variable.Text))
{
int.TryParse(variable.Text, out value);
}
}
_cleanPeriod = value;
return value;
}
private void Clean()
{
var filePath = string.Empty;
var dirPath = string.Empty;
try
{
if (FileName == null)
return;
filePath = ((NLog.Layouts.SimpleLayout)FileName).Text;
if (string.IsNullOrEmpty(filePath))
return;
dirPath = Path.GetDirectoryName(filePath);
if (string.IsNullOrEmpty(dirPath))
return;
if (!Path.IsPathRooted(dirPath))
dirPath = CrossPlatform.PathCombine(AppDomain.CurrentDomain.BaseDirectory, dirPath);
var directory = new DirectoryInfo(dirPath);
if (!directory.Exists)
return;
var files = directory.GetFiles();
var cleanPeriod = GetCleanPeriod();
foreach (var file in files.Where(file => (DateTime.UtcNow.Date - file.CreationTimeUtc.Date).Days > cleanPeriod))
{
file.Delete();
}
}
catch (Exception err)
{
base.Write(new LogEventInfo
{
Exception = err,
Level = LogLevel.Error,
Message = string.Format("file: {0}, dir: {1}, mess: {2}", filePath, dirPath, err.Message),
LoggerName = "SelfCleaningTarget"
});
}
}
protected override void Write(IList<AsyncLogEventInfo> logEvents)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
namespace ASC.Common.Logging;
var buffer = new List<AsyncLogEventInfo>();
[Target("SelfCleaning")]
public class SelfCleaningTarget : FileTarget
{
private static DateTime _lastCleanDate;
private static int? _cleanPeriod;
foreach (var logEvent in logEvents)
protected override void Write(IList<AsyncLogEventInfo> logEvents)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
var buffer = new List<AsyncLogEventInfo>();
foreach (var logEvent in logEvents)
{
buffer.Add(logEvent);
if (buffer.Count < 10)
{
buffer.Add(logEvent);
if (buffer.Count < 10) continue;
base.Write(buffer);
buffer.Clear();
continue;
}
base.Write(buffer);
base.Write(buffer);
buffer.Clear();
}
protected override void Write(LogEventInfo logEvent)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
base.Write(logEvent);
base.Write(buffer);
}
protected override void Write(LogEventInfo logEvent)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
}
base.Write(logEvent);
}
private static int GetCleanPeriod()
{
if (_cleanPeriod != null)
{
return _cleanPeriod.Value;
}
var value = 30;
const string key = "cleanPeriod";
if (LogManager.Configuration.Variables.TryGetValue(key, out var variable))
{
if (variable != null && !string.IsNullOrEmpty(variable.Text))
{
int.TryParse(variable.Text, out value);
}
}
_cleanPeriod = value;
return value;
}
private void Clean()
{
var filePath = string.Empty;
var dirPath = string.Empty;
try
{
if (FileName == null)
{
return;
}
filePath = ((NLog.Layouts.SimpleLayout)FileName).Text;
if (string.IsNullOrEmpty(filePath))
{
return;
}
dirPath = Path.GetDirectoryName(filePath);
if (string.IsNullOrEmpty(dirPath))
{
return;
}
if (!Path.IsPathRooted(dirPath))
{
dirPath = CrossPlatform.PathCombine(AppDomain.CurrentDomain.BaseDirectory, dirPath);
}
var directory = new DirectoryInfo(dirPath);
if (!directory.Exists)
{
return;
}
var files = directory.GetFiles();
var cleanPeriod = GetCleanPeriod();
foreach (var file in files.Where(file => (DateTime.UtcNow.Date - file.CreationTimeUtc.Date).Days > cleanPeriod))
{
file.Delete();
}
}
catch (Exception err)
{
base.Write(new LogEventInfo
{
Exception = err,
Level = LogLevel.Error,
Message = $"file: {filePath}, dir: {dirPath}, mess: {err.Message}",
LoggerName = "SelfCleaningTarget"
});
}
}
}

View File

@ -23,72 +23,74 @@
*
*/
namespace ASC.Common.Logging
{
public class SpecialFolderPathConverter : PatternConverter
{
protected override void Convert(TextWriter writer, object state)
{
if (string.IsNullOrEmpty(Option))
{
return;
}
try
{
var result = string.Empty;
const string CMD_LINE = "CommandLine:";
if (Option.StartsWith(CMD_LINE))
{
var args = Environment.CommandLine.Split(' ');
for (var i = 0; i < args.Length - 1; i++)
{
if (args[i].Equals(Option.Substring(CMD_LINE.Length), StringComparison.InvariantCultureIgnoreCase))
{
result = args[i + 1];
}
}
}
else
{
var repo = log4net.LogManager.GetRepository(Assembly.GetCallingAssembly());
if (repo != null)
{
var realKey = Option;
foreach (var key in repo.Properties.GetKeys())
{
if (Path.DirectorySeparatorChar == '/' && key == "UNIX:" + Option)
{
realKey = "UNIX:" + Option;
}
if (Path.DirectorySeparatorChar == '\\' && key == "WINDOWS:" + Option)
{
realKey = "WINDOWS:" + Option;
}
}
var val = repo.Properties[realKey];
if (val is PatternString patternString)
{
patternString.ActivateOptions();
patternString.Format(writer);
}
else if (val != null)
{
result = val.ToString();
}
}
}
if (!string.IsNullOrEmpty(result))
{
result = result.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
writer.Write(result);
}
}
catch (Exception err)
{
LogLog.Error(GetType(), "Can not convert " + Option, err);
}
}
}
}
namespace ASC.Common.Logging;
public class SpecialFolderPathConverter : PatternConverter
{
protected override void Convert(TextWriter writer, object state)
{
if (string.IsNullOrEmpty(Option))
{
return;
}
try
{
var result = string.Empty;
const string CMD_LINE = "CommandLine:";
if (Option.StartsWith(CMD_LINE))
{
var args = Environment.CommandLine.Split(' ');
for (var i = 0; i < args.Length - 1; i++)
{
if (args[i].Contains(Option, StringComparison.InvariantCultureIgnoreCase))
{
result = args[i + 1];
}
}
}
else
{
var repo = log4net.LogManager.GetRepository(Assembly.GetCallingAssembly());
if (repo != null)
{
var realKey = Option;
foreach (var key in repo.Properties.GetKeys())
{
if (Path.DirectorySeparatorChar == '/' && key == "UNIX:" + Option)
{
realKey = "UNIX:" + Option;
}
if (Path.DirectorySeparatorChar == '\\' && key == "WINDOWS:" + Option)
{
realKey = "WINDOWS:" + Option;
}
}
var val = repo.Properties[realKey];
if (val is PatternString patternString)
{
patternString.ActivateOptions();
patternString.Format(writer);
}
else if (val != null)
{
result = val.ToString();
}
}
}
if (!string.IsNullOrEmpty(result))
{
result = result.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
writer.Write(result);
}
}
catch (Exception err)
{
LogLog.Error(GetType(), "Can not convert " + Option, err);
}
}
}

View File

@ -23,10 +23,12 @@
*
*/
namespace ASC.Common.Mapping
namespace ASC.Common.Mapping;
public interface IMapFrom<T>
{
public interface IMapFrom<T>
void Mapping(Profile profile)
{
void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
profile.CreateMap(typeof(T), GetType());
}
}

View File

@ -23,34 +23,31 @@
*
*/
namespace ASC.Common.Mapping
namespace ASC.Common.Mapping;
public class MappingProfile : Profile
{
public class MappingProfile : Profile
public MappingProfile() => Array.ForEach(AppDomain.CurrentDomain.GetAssemblies(), a => ApplyMappingsFromAssembly(a));
private void ApplyMappingsFromAssembly(Assembly assembly)
{
public MappingProfile()
if (!assembly.GetName().Name.StartsWith("ASC."))
{
Array.ForEach(AppDomain.CurrentDomain.GetAssemblies(), a => ApplyMappingsFromAssembly(a));
return;
}
private void ApplyMappingsFromAssembly(Assembly assembly)
var types = assembly.GetExportedTypes()
.Where(t => t.GetInterfaces().Any(i =>
i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>)));
foreach (var type in types)
{
if (!assembly.GetName().Name.StartsWith("ASC.")) return;
var instance = Activator.CreateInstance(type);
var types = assembly.GetExportedTypes()
.Where(t => t.GetInterfaces().Any(i =>
i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>)))
.ToList();
var methodInfo = type.GetMethod("Mapping")
?? type.GetInterface("IMapFrom`1").GetMethod("Mapping");
foreach (var type in types)
{
var instance = Activator.CreateInstance(type);
var methodInfo = type.GetMethod("Mapping")
?? type.GetInterface("IMapFrom`1").GetMethod("Mapping");
methodInfo?.Invoke(instance, new object[] { this });
}
methodInfo?.Invoke(instance, new object[] { this });
}
}
}
}

View File

@ -23,37 +23,31 @@
*
*/
namespace ASC.Common.Module;
using System.ServiceModel;
namespace ASC.Common.Module
public class BaseWcfClient<TService> : ClientBase<TService>, IDisposable where TService : class
{
public class BaseWcfClient<TService> : ClientBase<TService>, IDisposable where TService : class
{
public BaseWcfClient()
{
}
public BaseWcfClient() { }
void IDisposable.Dispose()
void IDisposable.Dispose()
{
// msdn recommendation to close wcf client
try
{
// msdn recommendation to close wcf client
try
{
//Close();
}
catch (CommunicationException)
{
Abort();
}
catch (TimeoutException)
{
Abort();
}
catch (Exception)
{
Abort();
throw;
}
//Close();
}
catch (CommunicationException)
{
Abort();
}
catch (TimeoutException)
{
Abort();
}
catch (Exception)
{
Abort();
throw;
}
}
}
}

View File

@ -24,12 +24,11 @@
*/
namespace ASC.Common.Module
{
public interface IServiceController
{
void Start();
namespace ASC.Common.Module;
void Stop();
}
public interface IServiceController
{
void Start();
void Stop();
}

View File

@ -1,192 +0,0 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading;
using ASC.Common.Utils;
using Amazon.SimpleEmail;
using Amazon.SimpleEmail.Model;
using log4net;
namespace ASC.Common.Notify
{
public class AWSEmail
{
public enum SendStatus
{
Ok,
Failed,
QuotaLimit
}
private readonly AmazonSimpleEmailServiceClient _emailService;
private readonly ILog _log = LogHolder.Log("ASC.Notify.AmazonSES");
//Static fields
private static readonly TimeSpan RefreshTimeout;
private static DateTime _lastRefresh;
private static DateTime _lastSend;
private static TimeSpan _sendWindow = TimeSpan.MinValue;
private static GetSendQuotaResult _quota;
private static readonly object SynchRoot = new object();
static AWSEmail()
{
RefreshTimeout = TimeSpan.FromMinutes(30);
if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["ses.refreshTimeout"]))
{
TimeSpan.TryParse(ConfigurationManager.AppSettings["ses.refreshTimeout"], out RefreshTimeout);
}
_lastRefresh = DateTime.UtcNow - RefreshTimeout;//Set to refresh on first send
}
public AWSEmail()
{
var accessKey = ConfigurationManager.AppSettings["ses.accessKey"];
var secretKey = ConfigurationManager.AppSettings["ses.secretKey"];
_emailService = new AmazonSimpleEmailServiceClient(accessKey, secretKey);
}
public SendStatus SendEmail(MailMessage mailMessage)
{
//Check if we need to query stats
RefreshQuotaIfNeeded();
if (_quota != null)
{
lock (SynchRoot)
{
if (_quota.Max24HourSend <= _quota.SentLast24Hours)
{
//Quota exceeded
//Queu next refresh to +24 hours
_lastRefresh = DateTime.UtcNow.AddHours(24);
_log.WarnFormat("quota limit reached. setting next check to: {0}", _lastRefresh);
return SendStatus.QuotaLimit;
}
}
}
var destination = new Destination
{
ToAddresses = mailMessage.To.Select(adresses => adresses.Address).ToList(),
BccAddresses = mailMessage.Bcc.Select(adresses => adresses.Address).ToList(),
CcAddresses = mailMessage.CC.Select(adresses => adresses.Address).ToList(),
};
var body = new Body(new Content(mailMessage.Body) { Charset = Encoding.UTF8.WebName });
if (mailMessage.AlternateViews.Count > 0)
{
//Get html body
foreach (var alternateView in mailMessage.AlternateViews)
{
if ("text/html".Equals(alternateView.ContentType.MediaType, StringComparison.OrdinalIgnoreCase))
{
var stream = alternateView.ContentStream;
var buf = new byte[stream.Length];
stream.Read(buf, 0, buf.Length);
stream.Seek(0, SeekOrigin.Begin);//NOTE:seek to begin to keep HTML body
body.Html = new Content(Encoding.UTF8.GetString(buf)) { Charset = Encoding.UTF8.WebName };
break;
}
}
}
var message = new Message(new Content(mailMessage.Subject), body);
var seRequest = new SendEmailRequest(mailMessage.From.ToEncodedStringEx(), destination, message);
if (mailMessage.ReplyTo != null)
seRequest.ReplyToAddresses.Add(mailMessage.ReplyTo.Address);
ThrottleIfNeeded();
var response = _emailService.SendEmail(seRequest);
_lastSend = DateTime.UtcNow;
return response != null ? SendStatus.Ok : SendStatus.Failed;
}
private void ThrottleIfNeeded()
{
//Check last send and throttle if needed
if (_sendWindow != TimeSpan.MinValue)
{
if (DateTime.UtcNow - _lastSend <= _sendWindow)
//Possible BUG: at high frequncies maybe bug with to little differences
{
//This means that time passed from last send is less then message per second
_log.DebugFormat("send rate doesn't fit in send window. sleeping for:{0}", _sendWindow);
Thread.Sleep(_sendWindow);
}
}
}
private void RefreshQuotaIfNeeded()
{
if (!IsRefreshNeeded()) return;
lock (SynchRoot)
{
if (IsRefreshNeeded())//Double check
{
_log.DebugFormat("refreshing qouta. interval: {0} Last refresh was at: {1}", RefreshTimeout,
_lastRefresh);
//Do quota refresh
_lastRefresh = DateTime.UtcNow.AddMinutes(1);
try
{
var quotaRequest = new GetSendQuotaRequest();
_quota = _emailService.GetSendQuota(quotaRequest).GetSendQuotaResult;
_sendWindow = TimeSpan.FromSeconds(1.0 / _quota.MaxSendRate);
_log.DebugFormat("quota: {0}/{1} at {2} mps. send window:{3}", _quota.SentLast24Hours,
_quota.Max24HourSend, _quota.MaxSendRate, _sendWindow);
}
catch (Exception e)
{
_log.Error("error refreshing quota", e);
}
}
}
}
private static bool IsRefreshNeeded()
{
return (DateTime.UtcNow - _lastRefresh) > RefreshTimeout || _quota == null;
}
}
}

View File

@ -23,99 +23,113 @@
*
*/
namespace ASC.Common.Security
{
public class AscRandom : Random
{
private int inext;
private int inextp;
private const int MBIG = int.MaxValue;
private const int MSEED = 161803398;
private const int MZ = 0;
private readonly int[] seeds;
namespace ASC.Common.Security;
public class AscRandom : Random
{
private const int Mbig = int.MaxValue;
private const int Mseed = 161803398;
private const int Mz = 0;
private int _inext;
private int _inextp;
private readonly int[] _seeds;
public AscRandom() : this(Environment.TickCount) { }
public AscRandom(int seed)
{
_seeds = new int[56];
var num4 = (seed == int.MinValue) ? int.MaxValue : Math.Abs(seed);
var num2 = 161803398 - num4;
_seeds[^1] = num2;
var num3 = 1;
for (var i = 1; i < _seeds.Length - 1; i++)
{
var index = 21 * i % (_seeds.Length - 1);
_seeds[index] = num3;
num3 = num2 - num3;
if (num3 < 0)
{
num3 += int.MaxValue;
}
num2 = _seeds[index];
}
for (var j = 1; j < 5; j++)
{
for (var k = 1; k < _seeds.Length; k++)
{
_seeds[k] -= _seeds[1 + ((k + 30) % (_seeds.Length - 1))];
if (_seeds[k] < 0)
{
_seeds[k] += int.MaxValue;
}
}
}
_inext = 0;
_inextp = 21;
}
public override int Next(int maxValue)
{
if (maxValue < 0)
{
throw new ArgumentOutOfRangeException(nameof(maxValue));
}
return (int)(InternalSample() * 4.6566128752457969E-10 * maxValue);
}
public override void NextBytes(byte[] buffer)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
for (var i = 0; i < buffer.Length; i++)
{
buffer[i] = (byte)(InternalSample() % (byte.MaxValue + 1));
}
}
private int InternalSample()
{
var inext = _inext;
var inextp = _inextp;
public AscRandom() : this(Environment.TickCount)
{
}
if (++inext >= _seeds.Length - 1)
{
inext = 1;
}
if (++inextp >= _seeds.Length - 1)
{
inextp = 1;
}
var num = _seeds[inext] - _seeds[inextp];
if (num == int.MaxValue)
{
num--;
}
if (num < 0)
{
num += int.MaxValue;
}
public AscRandom(int seed)
{
seeds = new int[56];
var num4 = (seed == int.MinValue) ? int.MaxValue : Math.Abs(seed);
var num2 = 161803398 - num4;
seeds[^1] = num2;
var num3 = 1;
for (var i = 1; i < seeds.Length - 1; i++)
{
var index = (21 * i) % (seeds.Length - 1);
seeds[index] = num3;
num3 = num2 - num3;
if (num3 < 0)
{
num3 += int.MaxValue;
}
num2 = seeds[index];
}
for (var j = 1; j < 5; j++)
{
for (var k = 1; k < seeds.Length; k++)
{
seeds[k] -= seeds[1 + ((k + 30) % (seeds.Length - 1))];
if (seeds[k] < 0)
{
seeds[k] += int.MaxValue;
}
}
}
inext = 0;
inextp = 21;
}
_seeds[inext] = num;
_inext = inext;
_inextp = inextp;
public override int Next(int maxValue)
{
if (maxValue < 0)
{
throw new ArgumentOutOfRangeException(nameof(maxValue));
}
return (int)(InternalSample() * 4.6566128752457969E-10 * maxValue);
}
public override void NextBytes(byte[] buffer)
{
if (buffer == null) throw new ArgumentNullException(nameof(buffer));
for (var i = 0; i < buffer.Length; i++)
{
buffer[i] = (byte)(InternalSample() % (byte.MaxValue + 1));
}
}
private int InternalSample()
{
var inext = this.inext;
var inextp = this.inextp;
if (++inext >= seeds.Length - 1)
{
inext = 1;
}
if (++inextp >= seeds.Length - 1)
{
inextp = 1;
}
var num = seeds[inext] - seeds[inextp];
if (num == int.MaxValue)
{
num--;
}
if (num < 0)
{
num += int.MaxValue;
}
seeds[inext] = num;
this.inext = inext;
this.inextp = inextp;
return num;
}
}
return num;
}
}

View File

@ -23,56 +23,40 @@
*
*/
namespace ASC.Common.Security.Authentication
namespace ASC.Common.Security.Authentication;
[Serializable]
public class Account : IAccount
{
[Serializable]
public class Account : IAccount
public Guid ID { get; private set; }
public string Name { get; private set; }
public virtual bool IsAuthenticated { get; private set; }
public string AuthenticationType => "ASC";
public Account(Guid id, string name, bool authenticated)
{
public Account(Guid id, string name, bool authenticated)
{
ID = id;
Name = name;
IsAuthenticated = authenticated;
}
#region IAccount Members
public Guid ID { get; private set; }
public string Name { get; private set; }
public object Clone()
{
return MemberwiseClone();
}
public string AuthenticationType
{
get { return "ASC"; }
}
public virtual bool IsAuthenticated
{
get;
private set;
}
#endregion
public override bool Equals(object obj)
{
return obj is IAccount a && ID.Equals(a.ID);
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override string ToString()
{
return Name;
}
ID = id;
Name = name;
IsAuthenticated = authenticated;
}
}
public object Clone()
{
return MemberwiseClone();
}
public override bool Equals(object obj)
{
return obj is IAccount a && ID.Equals(a.ID);
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override string ToString()
{
return Name;
}
}

View File

@ -23,10 +23,6 @@
*
*/
namespace ASC.Common.Security.Authentication
{
public interface IAccount : ISubject, ICloneable
{
}
}
namespace ASC.Common.Security.Authentication;
public interface IAccount : ISubject, ICloneable { }

View File

@ -24,9 +24,6 @@
*/
namespace ASC.Common.Security.Authentication
{
public interface ISystemAccount : IAccount
{
}
}
namespace ASC.Common.Security.Authentication;
public interface ISystemAccount : IAccount { }

View File

@ -24,16 +24,13 @@
*/
namespace ASC.Common.Security.Authentication
namespace ASC.Common.Security.Authentication;
public interface IUserAccount : IAccount
{
public interface IUserAccount : IAccount
{
string Email { get; }
string FirstName { get; }
string LastName { get; }
string Title { get; }
int Tenant { get; }
}
}
string Email { get; }
string FirstName { get; }
string LastName { get; }
string Title { get; }
int Tenant { get; }
}

View File

@ -23,14 +23,11 @@
*
*/
namespace ASC.Common.Security.Authentication
namespace ASC.Common.Security.Authentication;
[Serializable]
public class SystemAccount : Account, ISystemAccount
{
[Serializable]
public class SystemAccount : Account, ISystemAccount
{
public SystemAccount(Guid id, string name, bool authenticated)
: base(id, name, authenticated)
{
}
}
}
public SystemAccount(Guid id, string name, bool authenticated)
: base(id, name, authenticated) { }
}

View File

@ -24,101 +24,111 @@
*/
#region usings
namespace ASC.Common.Security.Authorizing;
using System.Runtime.Serialization;
#endregion
namespace ASC.Common.Security.Authorizing
[Serializable]
public class AuthorizingException : Exception
{
[Serializable]
public class AuthorizingException : Exception
public ISubject Subject { get; internal set; }
public IAction[] Actions { get; internal set; }
public override string Message => _message;
private readonly string _message;
public AuthorizingException(string message)
: base(message) { }
public AuthorizingException(ISubject subject, IAction[] actions)
{
private readonly string _Message;
public AuthorizingException(string message)
: base(message)
if (actions == null || actions.Length == 0)
{
throw new ArgumentNullException(nameof(actions));
}
public AuthorizingException(ISubject subject, IAction[] actions)
{
if (actions == null || actions.Length == 0) throw new ArgumentNullException(nameof(actions));
Subject = subject ?? throw new ArgumentNullException(nameof(subject));
Actions = actions;
var sactions = "";
Array.ForEach(actions, action => { sactions += action.ToString() + ", "; });
_Message = string.Format(
"\"{0}\" access denied \"{1}\"",
subject,
sactions
);
}
Subject = subject ?? throw new ArgumentNullException(nameof(subject));
Actions = actions;
var sactions = "";
public AuthorizingException(ISubject subject, IAction[] actions, ISubject[] denySubjects, IAction[] denyActions)
{
_Message = FormatErrorMessage(subject, actions, denySubjects, denyActions);
}
Array.ForEach(actions, action => { sactions += action.ToString() + ", "; });
protected AuthorizingException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
_Message = info.GetValue("_Message", typeof(string)) as string;
Subject = info.GetValue("Subject", typeof(ISubject)) as ISubject;
Actions = info.GetValue("Actions", typeof(IAction[])) as IAction[];
}
public override string Message
{
get { return _Message; }
}
public ISubject Subject { get; internal set; }
public IAction[] Actions { get; internal set; }
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Subject", Subject, typeof(ISubject));
info.AddValue("_Message", _Message, typeof(string));
info.AddValue("Actions", Actions, typeof(IAction[]));
base.GetObjectData(info, context);
}
internal static string FormatErrorMessage(ISubject subject, IAction[] actions, ISubject[] denySubjects,
IAction[] denyActions)
{
if (subject == null) throw new ArgumentNullException(nameof(subject));
if (actions == null || actions.Length == 0) throw new ArgumentNullException(nameof(actions));
if (denySubjects == null || denySubjects.Length == 0) throw new ArgumentNullException(nameof(denySubjects));
if (denyActions == null || denyActions.Length == 0) throw new ArgumentNullException(nameof(denyActions));
if (actions.Length != denySubjects.Length || actions.Length != denyActions.Length)
throw new ArgumentException();
var reasons = "";
for (var i = 0; i < actions.Length; i++)
{
var reason = "";
if (denySubjects[i] != null && denyActions[i] != null)
reason = string.Format("{0}:{1} access denied {2}.",
actions[i].Name,
(denySubjects[i] is IRole ? "role:" : "") + denySubjects[i].Name,
denyActions[i].Name
);
else
reason = string.Format("{0}: access denied.", actions[i].Name);
if (i != actions.Length - 1)
reason += ", ";
reasons += reason;
}
var sactions = "";
Array.ForEach(actions, action => { sactions += action.ToString() + ", "; });
var message = string.Format(
"\"{0}\" access denied \"{1}\". Cause: {2}.",
(subject is IRole ? "role:" : "") + subject.Name,
sactions,
reasons
);
return message;
}
_message = string.Format(
"\"{0}\" access denied \"{1}\"",
subject,
sactions
);
}
}
public AuthorizingException(ISubject subject, IAction[] actions, ISubject[] denySubjects, IAction[] denyActions) =>
_message = FormatErrorMessage(subject, actions, denySubjects, denyActions);
protected AuthorizingException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
_message = info.GetValue("_Message", typeof(string)) as string;
Subject = info.GetValue("Subject", typeof(ISubject)) as ISubject;
Actions = info.GetValue("Actions", typeof(IAction[])) as IAction[];
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Subject", Subject, typeof(ISubject));
info.AddValue("_Message", _message, typeof(string));
info.AddValue("Actions", Actions, typeof(IAction[]));
base.GetObjectData(info, context);
}
internal static string FormatErrorMessage(ISubject subject, IAction[] actions, ISubject[] denySubjects,
IAction[] denyActions)
{
if (subject == null)
{
throw new ArgumentNullException(nameof(subject));
}
if (actions == null || actions.Length == 0)
{
throw new ArgumentNullException(nameof(actions));
}
if (denySubjects == null || denySubjects.Length == 0)
{
throw new ArgumentNullException(nameof(denySubjects));
}
if (denyActions == null || denyActions.Length == 0)
{
throw new ArgumentNullException(nameof(denyActions));
}
if (actions.Length != denySubjects.Length || actions.Length != denyActions.Length)
{
throw new ArgumentException();
}
var sb = new StringBuilder();
for (var i = 0; i < actions.Length; i++)
{
var action = actions[i];
var denyAction = denyActions[i];
var denySubject = denySubjects[i];
string reason;
if (denySubject != null && denyAction != null)
{
reason = $"{action.Name}:{(denySubject is IRole ? "role:" : "") + denySubject.Name} access denied {denyAction.Name}.";
}
else
{
reason = $"{action.Name}: access denied.";
}
if (i != actions.Length - 1)
{
reason += ", ";
}
sb.Append(reason);
}
var reasons = sb.ToString();
var sactions = "";
Array.ForEach(actions, action => { sactions += action.ToString() + ", "; });
var message = $"\"{(subject is IRole ? "role:" : "") + subject.Name}\" access denied \"{sactions}\". Cause: {reasons}.";
return message;
}
}

View File

@ -24,16 +24,19 @@
*/
namespace ASC.Common.Security.Authorizing
{
public static class AzObjectIdHelper
{
private static readonly string separator = "|";
namespace ASC.Common.Security.Authorizing;
public static string GetFullObjectId(ISecurityObjectId objectId)
public static class AzObjectIdHelper
{
private static readonly string _separator = "|";
public static string GetFullObjectId(ISecurityObjectId objectId)
{
if (objectId == null)
{
if (objectId == null) return null;
return string.Format("{0}{1}{2}", objectId.ObjectType.FullName, separator, objectId.SecurityId);
return null;
}
return $"{objectId.ObjectType.FullName}{_separator}{objectId.SecurityId}";
}
}
}

View File

@ -23,61 +23,67 @@
*
*/
namespace ASC.Common.Security.Authorizing;
#region usings
#endregion
namespace ASC.Common.Security.Authorizing
public class AzObjectSecurityProviderHelper
{
public class AzObjectSecurityProviderHelper
public ISecurityObjectId CurrentObjectId { get; private set; }
public bool ObjectRolesSupported => _currSecObjProvider != null && _currSecObjProvider.ObjectRolesSupported;
private readonly SecurityCallContext _callContext;
private readonly bool _currObjIdAsProvider;
private ISecurityObjectProvider _currSecObjProvider;
public AzObjectSecurityProviderHelper(ISecurityObjectId objectId, ISecurityObjectProvider secObjProvider)
{
private readonly SecurityCallContext callContext;
private readonly bool currObjIdAsProvider;
private ISecurityObjectProvider currSecObjProvider;
_currObjIdAsProvider = false;
CurrentObjectId = objectId ?? throw new ArgumentNullException(nameof(objectId));
_currSecObjProvider = secObjProvider;
public AzObjectSecurityProviderHelper(ISecurityObjectId objectId, ISecurityObjectProvider secObjProvider)
if (_currSecObjProvider == null && CurrentObjectId is ISecurityObjectProvider securityObjectProvider)
{
currObjIdAsProvider = false;
CurrentObjectId = objectId ?? throw new ArgumentNullException(nameof(objectId));
currSecObjProvider = secObjProvider;
if (currSecObjProvider == null && CurrentObjectId is ISecurityObjectProvider securityObjectProvider)
_currObjIdAsProvider = true;
_currSecObjProvider = securityObjectProvider;
}
_callContext = new SecurityCallContext();
}
public IEnumerable<IRole> GetObjectRoles(ISubject account)
{
var roles = _currSecObjProvider.GetObjectRoles(account, CurrentObjectId, _callContext);
foreach (var role in roles)
{
if (!_callContext.RolesList.Contains(role))
{
currObjIdAsProvider = true;
currSecObjProvider = securityObjectProvider;
_callContext.RolesList.Add(role);
}
callContext = new SecurityCallContext();
}
public ISecurityObjectId CurrentObjectId { get; private set; }
return roles;
}
public bool ObjectRolesSupported
public bool NextInherit()
{
if (_currSecObjProvider == null || !_currSecObjProvider.InheritSupported)
{
get { return currSecObjProvider != null && currSecObjProvider.ObjectRolesSupported; }
return false;
}
public IEnumerable<IRole> GetObjectRoles(ISubject account)
CurrentObjectId = _currSecObjProvider.InheritFrom(CurrentObjectId);
if (CurrentObjectId == null)
{
var roles = currSecObjProvider.GetObjectRoles(account, CurrentObjectId, callContext);
foreach (var role in roles)
{
if (!callContext.RolesList.Contains(role)) callContext.RolesList.Add(role);
}
return roles;
return false;
}
public bool NextInherit()
if (_currObjIdAsProvider)
{
if (currSecObjProvider == null || !currSecObjProvider.InheritSupported) return false;
CurrentObjectId = currSecObjProvider.InheritFrom(CurrentObjectId);
if (CurrentObjectId == null) return false;
if (currObjIdAsProvider)
{
currSecObjProvider = CurrentObjectId as ISecurityObjectProvider;
}
callContext.ObjectsStack.Insert(0, CurrentObjectId);
return currSecObjProvider != null;
_currSecObjProvider = CurrentObjectId as ISecurityObjectProvider;
}
_callContext.ObjectsStack.Insert(0, CurrentObjectId);
return _currSecObjProvider != null;
}
}

View File

@ -23,24 +23,23 @@
*
*/
namespace ASC.Common.Security.Authorizing
namespace ASC.Common.Security.Authorizing;
public static class Constants
{
public sealed class Constants
{
public static readonly Role Admin = new Role(new Guid("cd84e66b-b803-40fc-99f9-b2969a54a1de"), "Admin");
public static readonly Role Admin = new Role(new Guid("cd84e66b-b803-40fc-99f9-b2969a54a1de"), "Admin");
public static readonly Role Everyone = new Role(new Guid("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), "Everyone");
public static readonly Role Everyone = new Role(new Guid("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), "Everyone");
public static readonly Role User = new Role(new Guid("abef62db-11a8-4673-9d32-ef1d8af19dc0"), "User");
public static readonly Role User = new Role(new Guid("abef62db-11a8-4673-9d32-ef1d8af19dc0"), "User");
public static readonly Role Visitor = new Role(new Guid("aced04fa-dd96-4b35-af3e-346bf1eb972d"), "Visitor");
public static readonly Role Visitor = new Role(new Guid("aced04fa-dd96-4b35-af3e-346bf1eb972d"), "Visitor");
public static readonly Role Member = new Role(new Guid("ba74ca02-873f-43dc-8470-8620c156bc67"), "Member");
public static readonly Role Member = new Role(new Guid("ba74ca02-873f-43dc-8470-8620c156bc67"), "Member");
public static readonly Role Owner = new Role(new Guid("bba32183-a14d-48ed-9d39-c6b4d8925fbf"), "Owner");
public static readonly Role Owner = new Role(new Guid("bba32183-a14d-48ed-9d39-c6b4d8925fbf"), "Owner");
public static readonly Role Self = new Role(new Guid("5d5b7260-f7f7-49f1-a1c9-95fbb6a12604"), "Self");
}
}
public static readonly Role Self = new Role(new Guid("5d5b7260-f7f7-49f1-a1c9-95fbb6a12604"), "Self");
}

View File

@ -23,20 +23,17 @@
*
*/
namespace ASC.Common.Security.Authorizing
{
[Serializable]
public class Ace
{
public Guid ActionId { get; set; }
public AceType Reaction { get; set; }
namespace ASC.Common.Security.Authorizing;
[Serializable]
public class Ace
{
public Guid ActionId { get; set; }
public AceType Reaction { get; set; }
public Ace(Guid actionId, AceType reaction)
{
ActionId = actionId;
Reaction = reaction;
}
}
}
public Ace(Guid actionId, AceType reaction)
{
ActionId = actionId;
Reaction = reaction;
}
}

View File

@ -24,11 +24,10 @@
*/
namespace ASC.Common.Security.Authorizing
namespace ASC.Common.Security.Authorizing;
public enum AceType
{
public enum AceType
{
Allow,
Deny,
}
}
Allow,
Deny,
}

View File

@ -23,48 +23,44 @@
*
*/
namespace ASC.Common.Security.Authorizing
namespace ASC.Common.Security.Authorizing;
[Serializable]
public class Action : IAction
{
[Serializable]
public class Action : IAction
public Guid ID { get; private set; }
public string Name { get; private set; }
public bool AdministratorAlwaysAllow { get; private set; }
public bool Conjunction { get; private set; }
public Action(Guid id, string name)
: this(id, name, true, true) { }
public Action(Guid id, string name, bool administratorAlwaysAllow, bool conjunction)
{
public Guid ID { get; private set; }
public string Name { get; private set; }
public bool AdministratorAlwaysAllow { get; private set; }
public bool Conjunction { get; private set; }
public Action(Guid id, string name)
: this(id, name, true, true)
if (id == Guid.Empty)
{
throw new ArgumentNullException(nameof(id));
}
public Action(Guid id, string name, bool administratorAlwaysAllow, bool conjunction)
{
if (id == Guid.Empty) throw new ArgumentNullException(nameof(id));
ID = id;
Name = name;
AdministratorAlwaysAllow = administratorAlwaysAllow;
Conjunction = conjunction;
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is Action a && a.ID == ID;
}
public override string ToString()
{
return Name;
}
ID = id;
Name = name;
AdministratorAlwaysAllow = administratorAlwaysAllow;
Conjunction = conjunction;
}
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is Action a && a.ID == ID;
}
public override string ToString()
{
return Name;
}
}

View File

@ -23,56 +23,50 @@
*
*/
namespace ASC.Common.Security.Authorizing
namespace ASC.Common.Security.Authorizing;
[Serializable]
public sealed class Role : IRole
{
[Serializable]
public sealed class Role : IRole
public const string Everyone = "Everyone";
public const string Visitors = "Visitors";
public const string Users = "Users";
public const string Administrators = "Administrators";
public const string System = "System";
public Guid ID { get; internal set; }
public string Name { get; internal set; }
public string AuthenticationType => "ASC";
public bool IsAuthenticated => false;
public Role(Guid id, string name)
{
public const string Everyone = "Everyone";
public const string Visitors = "Visitors";
public const string Users = "Users";
public const string Administrators = "Administrators";
public const string System = "System";
public Guid ID { get; internal set; }
public string Name { get; internal set; }
public string AuthenticationType
if (id == Guid.Empty)
{
get { return "ASC"; }
throw new ArgumentException(nameof(id));
}
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException(nameof(name));
}
public bool IsAuthenticated
{
get { return false; }
}
public Role(Guid id, string name)
{
if (id == Guid.Empty) throw new ArgumentException("id");
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));
ID = id;
Name = name;
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is Role r && r.ID == ID;
}
public override string ToString()
{
return string.Format("Role: {0}", Name);
}
ID = id;
Name = name;
}
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is Role r && r.ID == ID;
}
public override string ToString()
{
return $"Role: {Name}";
}
}

View File

@ -23,16 +23,12 @@
*
*/
namespace ASC.Common.Security.Authorizing
namespace ASC.Common.Security.Authorizing;
public interface IAction
{
public interface IAction
{
Guid ID { get; }
string Name { get; }
bool AdministratorAlwaysAllow { get; }
bool Conjunction { get; }
}
}
Guid ID { get; }
string Name { get; }
bool AdministratorAlwaysAllow { get; }
bool Conjunction { get; }
}

View File

@ -24,9 +24,6 @@
*/
namespace ASC.Common.Security.Authorizing
{
public interface IRole : ISubject
{
}
}
namespace ASC.Common.Security.Authorizing;
public interface IRole : ISubject { }

View File

@ -23,10 +23,9 @@
*
*/
namespace ASC.Common.Security.Authorizing
namespace ASC.Common.Security.Authorizing;
public interface ISubject : IIdentity
{
public interface ISubject : IIdentity
{
Guid ID { get; }
}
}
Guid ID { get; }
}

View File

@ -24,16 +24,12 @@
*/
namespace ASC.Security.Cryptography
namespace ASC.Security.Cryptography;
public enum HashAlg
{
public enum HashAlg
{
MD5,
SHA1,
SHA256,
SHA512
}
}
MD5,
SHA1,
SHA256,
SHA512
}

View File

@ -23,132 +23,146 @@
*
*/
namespace ASC.Security.Cryptography
{
public sealed class Hasher
{
private const HashAlg DefaultAlg = HashAlg.SHA256;
public static byte[] Hash(string data, HashAlg hashAlg)
{
return ComputeHash(data, hashAlg);
}
public static byte[] Hash(string data)
{
return Hash(data, DefaultAlg);
}
public static byte[] Hash(byte[] data, HashAlg hashAlg)
{
return ComputeHash(data, hashAlg);
}
public static byte[] Hash(byte[] data)
{
return Hash(data, DefaultAlg);
}
public static string Base64Hash(string data, HashAlg hashAlg)
{
return ComputeHash64(data, hashAlg);
}
public static string Base64Hash(string data)
{
return Base64Hash(data, DefaultAlg);
}
public static string Base64Hash(byte[] data, HashAlg hashAlg)
{
return ComputeHash64(data, hashAlg);
}
public static string Base64Hash(byte[] data)
{
return Base64Hash(data, DefaultAlg);
}
public static bool EqualHash(byte[] dataToCompare, byte[] hash, HashAlg hashAlg)
{
return string.Equals(
ComputeHash64(dataToCompare, hashAlg),
B2S64(hash)
);
}
public static bool EqualHash(byte[] dataToCompare, byte[] hash)
{
return EqualHash(dataToCompare, hash, DefaultAlg);
}
public static bool EqualHash(string dataToCompare, string hash, HashAlg hashAlg)
{
return EqualHash(S2B(dataToCompare), S642B(hash), hashAlg);
}
public static bool EqualHash(string dataToCompare, string hash)
{
return EqualHash(dataToCompare, hash, DefaultAlg);
}
private static HashAlgorithm GetAlg(HashAlg hashAlg)
{
return hashAlg switch
{
HashAlg.MD5 => MD5.Create(),
HashAlg.SHA1 => SHA1.Create(),
HashAlg.SHA256 => SHA256.Create(),
HashAlg.SHA512 => SHA512.Create(),
_ => SHA256.Create()
};
}
private static byte[] S2B(string str)
{
if (str == null) throw new ArgumentNullException(nameof(str));
return Encoding.UTF8.GetBytes(str);
}
private static string B2S(byte[] data)
{
if (data == null) throw new ArgumentNullException(nameof(data));
return Encoding.UTF8.GetString(data);
}
private static byte[] S642B(string str)
{
if (str == null) throw new ArgumentNullException(nameof(str));
return Convert.FromBase64String(str);
}
private static string B2S64(byte[] data)
{
if (data == null) throw new ArgumentNullException(nameof(data));
return Convert.ToBase64String(data);
}
private static byte[] ComputeHash(byte[] data, HashAlg hashAlg)
namespace ASC.Security.Cryptography;
public static class Hasher
{
private const HashAlg DefaultAlg = HashAlg.SHA256;
public static byte[] Hash(string data, HashAlg hashAlg)
{
return ComputeHash(data, hashAlg);
}
public static byte[] Hash(string data)
{
return Hash(data, DefaultAlg);
}
public static byte[] Hash(byte[] data, HashAlg hashAlg)
{
return ComputeHash(data, hashAlg);
}
public static byte[] Hash(byte[] data)
{
return Hash(data, DefaultAlg);
}
public static string Base64Hash(string data, HashAlg hashAlg)
{
return ComputeHash64(data, hashAlg);
}
public static string Base64Hash(string data)
{
return Base64Hash(data, DefaultAlg);
}
public static string Base64Hash(byte[] data, HashAlg hashAlg)
{
return ComputeHash64(data, hashAlg);
}
public static string Base64Hash(byte[] data)
{
return Base64Hash(data, DefaultAlg);
}
public static bool EqualHash(byte[] dataToCompare, byte[] hash)
{
return EqualHash(dataToCompare, hash, DefaultAlg);
}
public static bool EqualHash(string dataToCompare, string hash, HashAlg hashAlg)
{
return EqualHash(S2B(dataToCompare), S642B(hash), hashAlg);
}
public static bool EqualHash(string dataToCompare, string hash)
{
return EqualHash(dataToCompare, hash, DefaultAlg);
}
public static bool EqualHash(byte[] dataToCompare, byte[] hash, HashAlg hashAlg)
{
return string.Equals(
ComputeHash64(dataToCompare, hashAlg),
B2S64(hash)
);
}
private static HashAlgorithm GetAlg(HashAlg hashAlg)
{
return hashAlg switch
{
using var alg = GetAlg(hashAlg);
return alg.ComputeHash(data);
}
private static byte[] ComputeHash(string data, HashAlg hashAlg)
{
return ComputeHash(S2B(data), hashAlg);
}
private static string ComputeHash64(byte[] data, HashAlg hashAlg)
{
return B2S64(ComputeHash(data, hashAlg));
}
private static string ComputeHash64(string data, HashAlg hashAlg)
{
return ComputeHash64(S2B(data), hashAlg);
}
}
HashAlg.MD5 => MD5.Create(),
HashAlg.SHA1 => SHA1.Create(),
HashAlg.SHA256 => SHA256.Create(),
HashAlg.SHA512 => SHA512.Create(),
_ => SHA256.Create()
};
}
private static byte[] S2B(string str)
{
if (str == null)
{
throw new ArgumentNullException(nameof(str));
}
return Encoding.UTF8.GetBytes(str);
}
private static string B2S(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
return Encoding.UTF8.GetString(data);
}
private static byte[] S642B(string str)
{
if (str == null)
{
throw new ArgumentNullException(nameof(str));
}
return Convert.FromBase64String(str);
}
private static string B2S64(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
return Convert.ToBase64String(data);
}
private static byte[] ComputeHash(byte[] data, HashAlg hashAlg)
{
using var alg = GetAlg(hashAlg);
return alg.ComputeHash(data);
}
private static byte[] ComputeHash(string data, HashAlg hashAlg)
{
return ComputeHash(S2B(data), hashAlg);
}
private static string ComputeHash64(byte[] data, HashAlg hashAlg)
{
return B2S64(ComputeHash(data, hashAlg));
}
private static string ComputeHash64(string data, HashAlg hashAlg)
{
return ComputeHash64(S2B(data), hashAlg);
}
}

View File

@ -23,56 +23,54 @@
*
*/
namespace ASC.Security.Cryptography
namespace ASC.Security.Cryptography;
[Singletone]
public class InstanceCrypto
{
[Singletone]
public class InstanceCrypto
private readonly byte[] _eKey;
public InstanceCrypto(MachinePseudoKeys machinePseudoKeys)
{
private byte[] EKey { get; }
public InstanceCrypto(MachinePseudoKeys machinePseudoKeys)
{
EKey = machinePseudoKeys.GetMachineConstant(32);
}
public string Encrypt(string data)
{
return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(data)));
}
public byte[] Encrypt(byte[] data)
{
using var hasher = Aes.Create();
hasher.Key = EKey;
hasher.IV = new byte[hasher.BlockSize >> 3];
using var ms = new MemoryStream();
using var ss = new CryptoStream(ms, hasher.CreateEncryptor(), CryptoStreamMode.Write);
using var plainTextStream = new MemoryStream(data);
plainTextStream.CopyTo(ss);
ss.FlushFinalBlock();
hasher.Clear();
return ms.ToArray();
}
public string Decrypt(string data)
{
return Decrypt(Convert.FromBase64String(data));
}
public string Decrypt(byte[] data)
{
using var hasher = Aes.Create();
hasher.Key = EKey;
hasher.IV = new byte[hasher.BlockSize >> 3];
using var msDecrypt = new MemoryStream(data);
using var csDecrypt = new CryptoStream(msDecrypt, hasher.CreateDecryptor(), CryptoStreamMode.Read);
using var srDecrypt = new StreamReader(csDecrypt);
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
return srDecrypt.ReadToEnd();
}
_eKey = machinePseudoKeys.GetMachineConstant(32);
}
}
public string Encrypt(string data)
{
return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(data)));
}
public byte[] Encrypt(byte[] data)
{
using var hasher = Aes.Create();
hasher.Key = _eKey;
hasher.IV = new byte[hasher.BlockSize >> 3];
using var ms = new MemoryStream();
using var ss = new CryptoStream(ms, hasher.CreateEncryptor(), CryptoStreamMode.Write);
using var plainTextStream = new MemoryStream(data);
plainTextStream.CopyTo(ss);
ss.FlushFinalBlock();
hasher.Clear();
return ms.ToArray();
}
public string Decrypt(string data) => Decrypt(Convert.FromBase64String(data));
public string Decrypt(byte[] data)
{
using var hasher = Aes.Create();
hasher.Key = _eKey;
hasher.IV = new byte[hasher.BlockSize >> 3];
using var msDecrypt = new MemoryStream(data);
using var csDecrypt = new CryptoStream(msDecrypt, hasher.CreateDecryptor(), CryptoStreamMode.Read);
using var srDecrypt = new StreamReader(csDecrypt);
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
return srDecrypt.ReadToEnd();
}
}

View File

@ -23,47 +23,50 @@
*
*/
namespace ASC.Security.Cryptography
namespace ASC.Security.Cryptography;
[Singletone]
public class MachinePseudoKeys
{
[Singletone]
public class MachinePseudoKeys
private readonly byte[] _confKey = null;
public MachinePseudoKeys(IConfiguration configuration)
{
private readonly byte[] confkey = null;
var key = configuration["core:machinekey"];
public MachinePseudoKeys(IConfiguration configuration)
if (string.IsNullOrEmpty(key))
{
var key = configuration["core:machinekey"];
if (string.IsNullOrEmpty(key))
{
key = configuration["asc:common.machinekey"];
}
if (!string.IsNullOrEmpty(key))
{
confkey = Encoding.UTF8.GetBytes(key);
}
key = configuration["asc:common.machinekey"];
}
public byte[] GetMachineConstant()
if (!string.IsNullOrEmpty(key))
{
if (confkey != null)
{
return confkey;
}
var path = typeof(MachinePseudoKeys).Assembly.Location;
var fi = new FileInfo(path);
return BitConverter.GetBytes(fi.CreationTime.ToOADate());
}
public byte[] GetMachineConstant(int bytesCount)
{
var cnst = Enumerable.Repeat<byte>(0, sizeof(int)).Concat(GetMachineConstant()).ToArray();
var icnst = BitConverter.ToInt32(cnst, cnst.Length - sizeof(int));
var rnd = new AscRandom(icnst);
var buff = new byte[bytesCount];
rnd.NextBytes(buff);
return buff;
_confKey = Encoding.UTF8.GetBytes(key);
}
}
}
public byte[] GetMachineConstant()
{
if (_confKey != null)
{
return _confKey;
}
var path = typeof(MachinePseudoKeys).Assembly.Location;
var fi = new FileInfo(path);
return BitConverter.GetBytes(fi.CreationTime.ToOADate());
}
public byte[] GetMachineConstant(int bytesCount)
{
var cnst = Enumerable.Repeat<byte>(0, sizeof(int)).Concat(GetMachineConstant()).ToArray();
var icnst = BitConverter.ToInt32(cnst, cnst.Length - sizeof(int));
var rnd = new AscRandom(icnst);
var buff = new byte[bytesCount];
rnd.NextBytes(buff);
return buff;
}
}

View File

@ -23,69 +23,64 @@
*
*/
namespace ASC.Security.Cryptography
namespace ASC.Security.Cryptography;
[Singletone]
public class PasswordHasher
{
[Singletone]
public class PasswordHasher
public int Size { get; private set; }
public int Iterations { get; private set; }
public string Salt { get; private set; }
public PasswordHasher(IConfiguration configuration, MachinePseudoKeys machinePseudoKeys)
{
public PasswordHasher(IConfiguration configuration, MachinePseudoKeys machinePseudoKeys)
if (!int.TryParse(configuration["core:password:size"], out var size))
{
if (!int.TryParse(configuration["core:password:size"], out var size)) size = 256;
Size = size;
if (!int.TryParse(configuration["core.password.iterations"], out var iterations)) iterations = 100000;
Iterations = iterations;
Salt = (configuration["core:password:salt"] ?? "").Trim();
if (string.IsNullOrEmpty(Salt))
{
var salt = Hasher.Hash("{9450BEF7-7D9F-4E4F-A18A-971D8681722D}", HashAlg.SHA256);
var PasswordHashSaltBytes = KeyDerivation.Pbkdf2(
Encoding.UTF8.GetString(machinePseudoKeys.GetMachineConstant()),
salt,
KeyDerivationPrf.HMACSHA256,
Iterations,
Size / 8);
Salt = BitConverter.ToString(PasswordHashSaltBytes).Replace("-", string.Empty).ToLower();
}
size = 256;
}
public int Size
Size = size;
if (!int.TryParse(configuration["core.password.iterations"], out var iterations))
{
get;
private set;
iterations = 100000;
}
public int Iterations
Iterations = iterations;
Salt = (configuration["core:password:salt"] ?? "").Trim();
if (string.IsNullOrEmpty(Salt))
{
get;
private set;
}
var salt = Hasher.Hash("{9450BEF7-7D9F-4E4F-A18A-971D8681722D}", HashAlg.SHA256);
public string Salt
{
get;
private set;
}
public string GetClientPassword(string password)
{
if (string.IsNullOrWhiteSpace(password)) password = Guid.NewGuid().ToString();
var salt = new UTF8Encoding(false).GetBytes(Salt);
var hashBytes = KeyDerivation.Pbkdf2(
password,
salt,
KeyDerivationPrf.HMACSHA256,
Iterations,
Size / 8);
var hash = BitConverter.ToString(hashBytes).Replace("-", string.Empty).ToLower();
return hash;
var PasswordHashSaltBytes = KeyDerivation.Pbkdf2(
Encoding.UTF8.GetString(machinePseudoKeys.GetMachineConstant()),
salt,
KeyDerivationPrf.HMACSHA256,
Iterations,
Size / 8);
Salt = BitConverter.ToString(PasswordHashSaltBytes).Replace("-", string.Empty).ToLower();
}
}
public string GetClientPassword(string password)
{
if (string.IsNullOrWhiteSpace(password))
{
password = Guid.NewGuid().ToString();
}
var salt = new UTF8Encoding(false).GetBytes(Salt);
var hashBytes = KeyDerivation.Pbkdf2(
password,
salt,
KeyDerivationPrf.HMACSHA256,
Iterations,
Size / 8);
var hash = BitConverter.ToString(hashBytes).Replace("-", string.Empty).ToLower();
return hash;
}
}

View File

@ -24,9 +24,6 @@
*/
namespace ASC.Common.Security
{
public interface ISecurityObject : ISecurityObjectId, ISecurityObjectProvider
{
}
}
namespace ASC.Common.Security;
public interface ISecurityObject : ISecurityObjectId, ISecurityObjectProvider { }

View File

@ -24,11 +24,10 @@
*/
namespace ASC.Common.Security
namespace ASC.Common.Security;
public interface ISecurityObjectId
{
public interface ISecurityObjectId
{
object SecurityId { get; }
Type ObjectType { get; }
}
}
object SecurityId { get; }
Type ObjectType { get; }
}

View File

@ -24,15 +24,13 @@
*/
namespace ASC.Common.Security
{
public interface ISecurityObjectProvider
{
bool InheritSupported { get; }
bool ObjectRolesSupported { get; }
ISecurityObjectId InheritFrom(ISecurityObjectId objectId);
IEnumerable<IRole> GetObjectRoles(ISubject account, ISecurityObjectId objectId, SecurityCallContext callContext);
}
}
namespace ASC.Common.Security;
public interface ISecurityObjectProvider
{
bool InheritSupported { get; }
bool ObjectRolesSupported { get; }
ISecurityObjectId InheritFrom(ISecurityObjectId objectId);
IEnumerable<IRole> GetObjectRoles(ISubject account, ISecurityObjectId objectId, SecurityCallContext callContext);
}

View File

@ -23,20 +23,17 @@
*
*/
namespace ASC.Common.Security
{
public class SecurityCallContext
{
public SecurityCallContext()
{
ObjectsStack = new List<ISecurityObjectId>();
RolesList = new List<IRole>();
}
public List<ISecurityObjectId> ObjectsStack { get; private set; }
public List<IRole> RolesList { get; private set; }
public object UserData { get; set; }
}
}
namespace ASC.Common.Security;
public class SecurityCallContext
{
public object UserData { get; set; }
public List<ISecurityObjectId> ObjectsStack { get; private set; }
public List<IRole> RolesList { get; private set; }
public SecurityCallContext()
{
ObjectsStack = new List<ISecurityObjectId>();
RolesList = new List<IRole>();
}
}

View File

@ -23,31 +23,28 @@
*
*/
namespace ASC.Common.Security
{
[DebuggerDisplay("ObjectType: {ObjectType.Name}, SecurityId: {SecurityId}")]
public class SecurityObjectId : ISecurityObjectId
{
public object SecurityId { get; private set; }
public Type ObjectType { get; private set; }
public SecurityObjectId(object id, Type objType)
{
SecurityId = id;
ObjectType = objType ?? throw new ArgumentNullException(nameof(objType));
}
public override int GetHashCode()
{
return AzObjectIdHelper.GetFullObjectId(this).GetHashCode();
}
public override bool Equals(object obj)
{
return obj is SecurityObjectId other &&
Equals(AzObjectIdHelper.GetFullObjectId(other), AzObjectIdHelper.GetFullObjectId(this));
}
}
namespace ASC.Common.Security;
[DebuggerDisplay("ObjectType: {ObjectType.Name}, SecurityId: {SecurityId}")]
public class SecurityObjectId : ISecurityObjectId
{
public object SecurityId { get; private set; }
public Type ObjectType { get; private set; }
public SecurityObjectId(object id, Type objType)
{
SecurityId = id;
ObjectType = objType ?? throw new ArgumentNullException(nameof(objType));
}
public override int GetHashCode()
{
return AzObjectIdHelper.GetFullObjectId(this).GetHashCode();
}
public override bool Equals(object obj)
{
return obj is SecurityObjectId other &&
Equals(AzObjectIdHelper.GetFullObjectId(other), AzObjectIdHelper.GetFullObjectId(this));
}
}

View File

@ -25,110 +25,84 @@
using JsonSerializer = System.Text.Json.JsonSerializer;
namespace ASC.Common.Threading
{
public class DistributedTask
{
public Action<DistributedTask> Publication { get; set; }
namespace ASC.Common.Threading;
protected internal DistributedTaskCache DistributedTaskCache { get; internal set; }
public int InstanceId
public class DistributedTask
{
public Action<DistributedTask> Publication { get; set; }
public int InstanceId
{
get => DistributedTaskCache.InstanceId;
set => DistributedTaskCache.InstanceId = value;
}
public string Id
{
get => DistributedTaskCache.Id;
protected set => DistributedTaskCache.Id = value ?? "";
}
public DistributedTaskStatus Status
{
get => Enum.Parse<DistributedTaskStatus>(DistributedTaskCache.Status);
set => DistributedTaskCache.Status = value.ToString();
}
public Exception Exception
{
get => new Exception(DistributedTaskCache.Exception);
set => DistributedTaskCache.Exception = value?.ToString() ?? "";
}
protected internal DistributedTaskCache DistributedTaskCache { get; internal set; }
public DistributedTask()
{
DistributedTaskCache = new DistributedTaskCache
{
get
{
return DistributedTaskCache.InstanceId;
}
set
{
DistributedTaskCache.InstanceId = value;
}
}
public string Id
Id = Guid.NewGuid().ToString()
};
}
public DistributedTask(DistributedTaskCache distributedTaskCache)
{
DistributedTaskCache = distributedTaskCache;
}
public T GetProperty<T>(string name)
{
var prop = DistributedTaskCache.Props.FirstOrDefault(r => r.Key == name);
if (prop == null)
{
get
{
return DistributedTaskCache.Id;
}
protected set
{
DistributedTaskCache.Id = value?.ToString() ?? "";
}
}
public DistributedTaskStatus Status
{
get
{
return Enum.Parse<DistributedTaskStatus>(DistributedTaskCache.Status);
}
set
{
DistributedTaskCache.Status = value.ToString();
}
}
public Exception Exception
{
get
{
return new Exception(DistributedTaskCache.Exception);
}
set
{
DistributedTaskCache.Exception = value?.ToString() ?? "";
}
return default;
}
public DistributedTask()
{
DistributedTaskCache = new DistributedTaskCache
{
Id = Guid.NewGuid().ToString()
};
}
public DistributedTask(DistributedTaskCache distributedTaskCache)
{
DistributedTaskCache = distributedTaskCache;
}
public T GetProperty<T>(string name)
{
var prop = DistributedTaskCache.Props.FirstOrDefault(r => r.Key == name);
if (prop == null) return default;
return JsonSerializer.Deserialize<T>(prop.Value);
}
public void SetProperty(string name, object value)
{
var prop = new DistributedTaskCache.Types.DistributedTaskCacheProp()
{
Key = name,
Value = JsonSerializer.Serialize(value)
};
return JsonSerializer.Deserialize<T>(prop.Value);
}
var current = DistributedTaskCache.Props.SingleOrDefault(r => r.Key == name);
if (current != null)
{
DistributedTaskCache.Props.Remove(current);
}
if (value != null)
{
DistributedTaskCache.Props.Add(prop);
}
}
public void PublishChanges()
{
if (Publication == null)
{
throw new InvalidOperationException("Publication not found.");
}
Publication(this);
}
}
}
public void SetProperty(string name, object value)
{
var prop = new DistributedTaskCache.Types.DistributedTaskCacheProp()
{
Key = name,
Value = JsonSerializer.Serialize(value)
};
var current = DistributedTaskCache.Props.SingleOrDefault(r => r.Key == name);
if (current != null)
{
DistributedTaskCache.Props.Remove(current);
}
if (value != null)
{
DistributedTaskCache.Props.Add(prop);
}
}
public void PublishChanges()
{
if (Publication == null)
{
throw new InvalidOperationException("Publication not found.");
}
Publication(this);
}
}

View File

@ -1,64 +1,41 @@
namespace ASC.Common.Threading
namespace ASC.Common.Threading;
[Transient]
public class DistributedTaskProgress : DistributedTask
{
[Transient]
public class DistributedTaskProgress : DistributedTask
public double Percentage
{
public double Percentage
{
get
{
return Math.Min(100.0, Math.Max(0, DistributedTaskCache.Percentage));
}
set
{
DistributedTaskCache.Percentage = value;
}
}
public bool IsCompleted
{
get
{
return DistributedTaskCache.IsCompleted;
}
set
{
DistributedTaskCache.IsCompleted = value;
}
}
protected int StepCount
{
get
{
return DistributedTaskCache.StepCount;
}
set
{
DistributedTaskCache.StepCount = value;
}
}
protected void StepDone()
{
if (StepCount > 0)
{
Percentage += 100.0 / StepCount;
}
PublishChanges();
}
public void RunJob()
{
Percentage = 0;
Status = DistributedTaskStatus.Running;
DoJob();
}
protected virtual void DoJob()
{
}
get => Math.Min(100.0, Math.Max(0, DistributedTaskCache.Percentage));
set => DistributedTaskCache.Percentage = value;
}
}
public bool IsCompleted
{
get => DistributedTaskCache.IsCompleted;
set => DistributedTaskCache.IsCompleted = value;
}
protected int StepCount
{
get => DistributedTaskCache.StepCount;
set => DistributedTaskCache.StepCount = value;
}
public void RunJob()
{
Percentage = 0;
Status = DistributedTaskStatus.Running;
DoJob();
}
protected virtual void DoJob() { }
protected void StepDone()
{
if (StepCount > 0)
{
Percentage += 100.0 / StepCount;
}
PublishChanges();
}
}

View File

@ -23,307 +23,318 @@
*
*/
namespace ASC.Common.Threading
namespace ASC.Common.Threading;
[Singletone]
public class DistributedTaskCacheNotify
{
[Singletone]
public class DistributedTaskCacheNotify
public ConcurrentDictionary<string, CancellationTokenSource> Cancelations { get; }
public ICache Cache { get; }
private readonly ICacheNotify<DistributedTaskCancelation> _cancelTaskNotify;
private readonly ICacheNotify<DistributedTaskCache> _taskCacheNotify;
public DistributedTaskCacheNotify(
ICacheNotify<DistributedTaskCancelation> cancelTaskNotify,
ICacheNotify<DistributedTaskCache> taskCacheNotify,
ICache cache)
{
public ConcurrentDictionary<string, CancellationTokenSource> Cancelations { get; }
public ICache Cache { get; }
private readonly ICacheNotify<DistributedTaskCancelation> notify;
private readonly ICacheNotify<DistributedTaskCache> notifyCache;
Cancelations = new ConcurrentDictionary<string, CancellationTokenSource>();
public DistributedTaskCacheNotify(
ICacheNotify<DistributedTaskCancelation> notify,
ICacheNotify<DistributedTaskCache> notifyCache,
ICache cache)
Cache = cache;
_cancelTaskNotify = cancelTaskNotify;
cancelTaskNotify.Subscribe((c) =>
{
Cancelations = new ConcurrentDictionary<string, CancellationTokenSource>();
Cache = cache;
this.notify = notify;
notify.Subscribe((c) =>
{
if (Cancelations.TryGetValue(c.Id, out var s))
{
s.Cancel();
}
}, CacheNotifyAction.Remove);
this.notifyCache = notifyCache;
notifyCache.Subscribe((c) =>
if (Cancelations.TryGetValue(c.Id, out var s))
{
Cache.HashSet(c.Key, c.Id, (DistributedTaskCache)null);
}, CacheNotifyAction.Remove);
s.Cancel();
}
}, CacheNotifyAction.Remove);
notifyCache.Subscribe((c) =>
{
Cache.HashSet(c.Key, c.Id, c);
}, CacheNotifyAction.InsertOrUpdate);
}
_taskCacheNotify = taskCacheNotify;
public void CancelTask(string id)
{
notify.Publish(new DistributedTaskCancelation() { Id = id }, CacheNotifyAction.Remove);
}
public void SetTask(DistributedTask task)
taskCacheNotify.Subscribe((c) =>
{
notifyCache.Publish(task.DistributedTaskCache, CacheNotifyAction.InsertOrUpdate);
}
public void RemoveTask(string id, string key)
Cache.HashSet(c.Key, c.Id, (DistributedTaskCache)null);
}, CacheNotifyAction.Remove);
taskCacheNotify.Subscribe((c) =>
{
notifyCache.Publish(new DistributedTaskCache() { Id = id, Key = key }, CacheNotifyAction.Remove);
}
Cache.HashSet(c.Key, c.Id, c);
}, CacheNotifyAction.InsertOrUpdate);
}
[Singletone(typeof(ConfigureDistributedTaskQueue))]
public class DistributedTaskQueueOptionsManager : OptionsManager<DistributedTaskQueue>
{
public DistributedTaskQueueOptionsManager(IOptionsFactory<DistributedTaskQueue> factory) : base(factory)
{
}
public void CancelTask(string id)
{
_cancelTaskNotify.Publish(new DistributedTaskCancelation() { Id = id }, CacheNotifyAction.Remove);
}
public DistributedTaskQueue Get<T>() where T : DistributedTask
{
return Get(typeof(T).FullName);
}
public void SetTask(DistributedTask task)
{
_taskCacheNotify.Publish(task.DistributedTaskCache, CacheNotifyAction.InsertOrUpdate);
}
public void RemoveTask(string id, string key)
{
_taskCacheNotify.Publish(new DistributedTaskCache() { Id = id, Key = key }, CacheNotifyAction.Remove);
}
}
[Singletone(typeof(ConfigureDistributedTaskQueue))]
public class DistributedTaskQueueOptionsManager : OptionsManager<DistributedTaskQueue>
{
public DistributedTaskQueueOptionsManager(IOptionsFactory<DistributedTaskQueue> factory) : base(factory) { }
public DistributedTaskQueue Get<T>() where T : DistributedTask
{
return Get(typeof(T).FullName);
}
}
[Scope]
public class ConfigureDistributedTaskQueue : IConfigureNamedOptions<DistributedTaskQueue>
{
private readonly DistributedTaskCacheNotify _distributedTaskCacheNotify;
public readonly IServiceProvider _serviceProvider;
public ConfigureDistributedTaskQueue(
DistributedTaskCacheNotify distributedTaskCacheNotify,
IServiceProvider serviceProvider)
{
_distributedTaskCacheNotify = distributedTaskCacheNotify;
_serviceProvider = serviceProvider;
}
public void Configure(DistributedTaskQueue queue)
{
queue.DistributedTaskCacheNotify = _distributedTaskCacheNotify;
queue.ServiceProvider = _serviceProvider;
}
public void Configure(string name, DistributedTaskQueue options)
{
Configure(options);
options.Name = name;
}
}
public class DistributedTaskQueue
{
public IServiceProvider ServiceProvider { get; set; }
public DistributedTaskCacheNotify DistributedTaskCacheNotify { get; set; }
public string Name
{
get => _name;
set => _name = value + GetType().Name;
}
public int MaxThreadsCount
{
set => Scheduler = value <= 0
? TaskScheduler.Default
: new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, value).ConcurrentScheduler;
}
[Scope]
public class ConfigureDistributedTaskQueue : IConfigureNamedOptions<DistributedTaskQueue>
private ICache Cache => DistributedTaskCacheNotify.Cache;
private TaskScheduler Scheduler { get; set; } = TaskScheduler.Default;
public static readonly int InstanceId = Process.GetCurrentProcess().Id;
private string _name;
private ConcurrentDictionary<string, CancellationTokenSource> Cancelations
{
private DistributedTaskCacheNotify DistributedTaskCacheNotify { get; }
public IServiceProvider ServiceProvider { get; }
public ConfigureDistributedTaskQueue(DistributedTaskCacheNotify distributedTaskCacheNotify, IServiceProvider serviceProvider)
get
{
DistributedTaskCacheNotify = distributedTaskCacheNotify;
ServiceProvider = serviceProvider;
}
public void Configure(DistributedTaskQueue queue)
{
queue.DistributedTaskCacheNotify = DistributedTaskCacheNotify;
queue.ServiceProvider = ServiceProvider;
}
public void Configure(string name, DistributedTaskQueue options)
{
Configure(options);
options.Name = name;
return DistributedTaskCacheNotify.Cancelations;
}
}
public class DistributedTaskQueue
{
public static readonly int InstanceId;
private string key;
private TaskScheduler Scheduler { get; set; } = TaskScheduler.Default;
public IServiceProvider ServiceProvider { get; set; }
public string Name { get { return key; } set { key = value + GetType().Name; } }
private ICache Cache { get => DistributedTaskCacheNotify.Cache; }
private ConcurrentDictionary<string, CancellationTokenSource> Cancelations { get => DistributedTaskCacheNotify.Cancelations; }
public int MaxThreadsCount
{
set
{
Scheduler = value <= 0
? TaskScheduler.Default
: new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, value).ConcurrentScheduler;
}
}
public DistributedTaskCacheNotify DistributedTaskCacheNotify { get; set; }
static DistributedTaskQueue()
{
InstanceId = Process.GetCurrentProcess().Id;
}
public void QueueTask(DistributedTaskProgress taskProgress)
{
QueueTask((a, b) => taskProgress.RunJob(), taskProgress);
}
public void QueueTask(Action<DistributedTask, CancellationToken> action, DistributedTask distributedTask = null)
{
if (distributedTask == null)
{
distributedTask = new DistributedTask();
}
distributedTask.InstanceId = InstanceId;
var cancelation = new CancellationTokenSource();
var token = cancelation.Token;
Cancelations[distributedTask.Id] = cancelation;
var task = new Task(() => { action(distributedTask, token); }, token, TaskCreationOptions.LongRunning);
task
.ConfigureAwait(false)
.GetAwaiter()
.OnCompleted(() => OnCompleted(task, distributedTask.Id));
distributedTask.Status = DistributedTaskStatus.Running;
if (distributedTask.Publication == null)
{
distributedTask.Publication = GetPublication();
}
distributedTask.PublishChanges();
task.Start(Scheduler);
}
public IEnumerable<DistributedTask> GetTasks()
{
var tasks = Cache.HashGetAll<DistributedTaskCache>(key).Values.Select(r => new DistributedTask(r)).ToList();
tasks.ForEach(t =>
{
if (t.Publication == null)
{
t.Publication = GetPublication();
}
});
return tasks;
}
public IEnumerable<T> GetTasks<T>() where T : DistributedTask
{
var tasks = Cache.HashGetAll<DistributedTaskCache>(key).Values.Select(r =>
{
var result = ServiceProvider.GetService<T>();
result.DistributedTaskCache = r;
return result;
}).ToList();
tasks.ForEach(t =>
{
if (t.Publication == null)
{
t.Publication = GetPublication();
}
});
return tasks;
}
public T GetTask<T>(string id) where T : DistributedTask
{
var cache = Cache.HashGet<DistributedTaskCache>(key, id);
if (cache != null)
{
using var scope = ServiceProvider.CreateScope();
var task = scope.ServiceProvider.GetService<T>();
task.DistributedTaskCache = cache;
if (task != null && task.Publication == null)
{
task.Publication = GetPublication();
}
return task;
}
return null;
}
public DistributedTask GetTask(string id)
{
var cache = Cache.HashGet<DistributedTaskCache>(key, id);
if (cache != null)
{
var task = new DistributedTask();
task.DistributedTaskCache = cache;
if (task != null && task.Publication == null)
{
task.Publication = GetPublication();
}
return task;
}
return null;
}
public void SetTask(DistributedTask task)
{
DistributedTaskCacheNotify.SetTask(task);
}
public void RemoveTask(string id)
{
DistributedTaskCacheNotify.RemoveTask(id, key);
}
public void CancelTask(string id)
{
DistributedTaskCacheNotify.CancelTask(id);
}
private void OnCompleted(Task task, string id)
{
var distributedTask = GetTask(id);
if (distributedTask != null)
{
distributedTask.Status = DistributedTaskStatus.Completed;
distributedTask.Exception = task.Exception;
if (task.IsFaulted)
{
distributedTask.Status = DistributedTaskStatus.Failted;
}
if (task.IsCanceled)
{
distributedTask.Status = DistributedTaskStatus.Canceled;
}
Cancelations.TryRemove(id, out _);
distributedTask.PublishChanges();
}
}
private Action<DistributedTask> GetPublication()
{
return (t) =>
{
if (t.DistributedTaskCache != null)
{
t.DistributedTaskCache.Key = key;
}
DistributedTaskCacheNotify.SetTask(t);
};
}
public void QueueTask(DistributedTaskProgress taskProgress)
{
QueueTask((a, b) => taskProgress.RunJob(), taskProgress);
}
public static class DistributedTaskQueueExtention
{
public static DIHelper AddDistributedTaskQueueService<T>(this DIHelper services, int maxThreadsCount) where T : DistributedTask
public void QueueTask(Action<DistributedTask, CancellationToken> action, DistributedTask distributedTask = null)
{
if (distributedTask == null)
{
services.TryAdd<DistributedTaskCacheNotify>();
services.TryAdd<DistributedTaskQueueOptionsManager>();
services.TryAdd<DistributedTaskQueue>();
distributedTask = new DistributedTask();
}
var type = typeof(T);
if (!type.IsAbstract)
distributedTask.InstanceId = InstanceId;
var cancelation = new CancellationTokenSource();
var token = cancelation.Token;
Cancelations[distributedTask.Id] = cancelation;
var task = new Task(() => { action(distributedTask, token); }, token, TaskCreationOptions.LongRunning);
task.ConfigureAwait(false)
.GetAwaiter()
.OnCompleted(() => OnCompleted(task, distributedTask.Id));
distributedTask.Status = DistributedTaskStatus.Running;
if (distributedTask.Publication == null)
{
distributedTask.Publication = GetPublication();
}
distributedTask.PublishChanges();
task.Start(Scheduler);
}
public IEnumerable<DistributedTask> GetTasks()
{
var tasks = Cache.HashGetAll<DistributedTaskCache>(_name).Values.Select(r => new DistributedTask(r)).ToList();
tasks.ForEach(t =>
{
if (t.Publication == null)
{
services.TryAdd<T>();
t.Publication = GetPublication();
}
});
return tasks;
}
public IEnumerable<T> GetTasks<T>() where T : DistributedTask
{
var tasks = Cache.HashGetAll<DistributedTaskCache>(_name).Values.Select(r =>
{
var result = ServiceProvider.GetService<T>();
result.DistributedTaskCache = r;
return result;
}).ToList();
tasks.ForEach(t =>
{
if (t.Publication == null)
{
t.Publication = GetPublication();
}
});
return tasks;
}
public T GetTask<T>(string id) where T : DistributedTask
{
var cache = Cache.HashGet<DistributedTaskCache>(_name, id);
if (cache != null)
{
using var scope = ServiceProvider.CreateScope();
var task = scope.ServiceProvider.GetService<T>();
task.DistributedTaskCache = cache;
if (task.Publication == null)
{
task.Publication = GetPublication();
}
services.TryAddSingleton<IConfigureOptions<DistributedTaskQueue>, ConfigureDistributedTaskQueue>();
return task;
}
_ = services.Configure<DistributedTaskQueue>(type.Name, r =>
return null;
}
public DistributedTask GetTask(string id)
{
var cache = Cache.HashGet<DistributedTaskCache>(_name, id);
if (cache != null)
{
var task = new DistributedTask();
task.DistributedTaskCache = cache;
if (task.Publication == null)
{
r.MaxThreadsCount = maxThreadsCount;
task.Publication = GetPublication();
}
return task;
}
return null;
}
public void SetTask(DistributedTask task)
{
DistributedTaskCacheNotify.SetTask(task);
}
public void RemoveTask(string id)
{
DistributedTaskCacheNotify.RemoveTask(id, _name);
}
public void CancelTask(string id)
{
DistributedTaskCacheNotify.CancelTask(id);
}
private void OnCompleted(Task task, string id)
{
var distributedTask = GetTask(id);
if (distributedTask != null)
{
distributedTask.Status = DistributedTaskStatus.Completed;
distributedTask.Exception = task.Exception;
if (task.IsFaulted)
{
distributedTask.Status = DistributedTaskStatus.Failted;
}
if (task.IsCanceled)
{
distributedTask.Status = DistributedTaskStatus.Canceled;
}
Cancelations.TryRemove(id, out _);
distributedTask.PublishChanges();
}
}
private Action<DistributedTask> GetPublication()
{
return (t) =>
{
if (t.DistributedTaskCache != null)
{
t.DistributedTaskCache.Key = _name;
}
DistributedTaskCacheNotify.SetTask(t);
};
}
}
public static class DistributedTaskQueueExtention
{
public static DIHelper AddDistributedTaskQueueService<T>(this DIHelper services, int maxThreadsCount) where T : DistributedTask
{
services.TryAdd<DistributedTaskCacheNotify>();
services.TryAdd<DistributedTaskQueueOptionsManager>();
services.TryAdd<DistributedTaskQueue>();
var type = typeof(T);
if (!type.IsAbstract)
{
services.TryAdd<T>();
}
services.TryAddSingleton<IConfigureOptions<DistributedTaskQueue>, ConfigureDistributedTaskQueue>();
_ = services.Configure<DistributedTaskQueue>(type.Name, r =>
{
r.MaxThreadsCount = maxThreadsCount;
//r.errorCount = 1;
});
return services;
}
return services;
}
}
}

View File

@ -24,14 +24,13 @@
*/
namespace ASC.Common.Threading
namespace ASC.Common.Threading;
public enum DistributedTaskStatus
{
public enum DistributedTaskStatus
{
Created,
Running,
Completed,
Canceled,
Failted
}
Created,
Running,
Completed,
Canceled,
Failted
}

View File

@ -23,16 +23,15 @@
*
*/
namespace ASC.Common.Threading.Progress
{
public interface IProgressItem : ICloneable
{
string Id { get; }
DistributedTaskStatus Status { get; set; }
object Error { get; set; }
double Percentage { get; set; }
bool IsCompleted { get; set; }
namespace ASC.Common.Threading.Progress;
void RunJob();
}
}
public interface IProgressItem : ICloneable
{
string Id { get; }
DistributedTaskStatus Status { get; set; }
object Error { get; set; }
double Percentage { get; set; }
bool IsCompleted { get; set; }
void RunJob();
}

View File

@ -1,86 +1,82 @@
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
public class ConnectionStringCollection : IEnumerable<ConnectionStringSettings>
{
public class ConnectionStringCollection : IEnumerable<ConnectionStringSettings>
private List<ConnectionStringSettings> _data;
public ConnectionStringSettings this[string name] => _data.FirstOrDefault(r => r.Name == name);
public ConnectionStringCollection(IEnumerable<ConnectionStringSettings> data)
{
private List<ConnectionStringSettings> Data { get; set; }
public ConnectionStringCollection(IEnumerable<ConnectionStringSettings> data) => Data = data.ToList();
public IEnumerator<ConnectionStringSettings> GetEnumerator()
{
return Data.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public ConnectionStringSettings this[string name]
{
get
{
return Data.FirstOrDefault(r => r.Name == name);
}
}
_data = data.ToList();
}
[Singletone]
public class ConfigurationExtension
public IEnumerator<ConnectionStringSettings> GetEnumerator()
{
private IConfiguration Configuration { get; }
private Lazy<ConnectionStringCollection> ConnectionStringSettings { get; }
return _data.GetEnumerator();
}
public ConfigurationExtension(IConfiguration configuration)
{
Configuration = configuration;
ConnectionStringSettings = new Lazy<ConnectionStringCollection>(new ConnectionStringCollection(GetSettings<ConnectionStringSettings>("ConnectionStrings")));
}
public IEnumerable<T> GetSettings<T>(string section) where T : new()
{
var result = new List<T>();
var sectionSettings = Configuration.GetSection(section);
foreach (var ch in sectionSettings.GetChildren())
{
var cs = new T();
ch.Bind(cs);
result.Add(cs);
}
return result;
}
public T GetSetting<T>(string section) where T : new()
{
return GetSetting(section, new T());
}
public T GetSetting<T>(string section, T instance)
{
var sectionSettings = Configuration.GetSection(section);
sectionSettings.Bind(instance);
return instance;
}
public ConnectionStringCollection GetConnectionStrings()
{
return ConnectionStringSettings.Value;
}
public ConnectionStringSettings GetConnectionStrings(string key)
{
return GetConnectionStrings()[key];
}
public string this[string key]
{
get => Configuration[key];
set => Configuration[key] = value;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
[Singletone]
public class ConfigurationExtension
{
public string this[string key]
{
get => _configuration[key];
set => _configuration[key] = value;
}
private readonly IConfiguration _configuration;
private readonly Lazy<ConnectionStringCollection> _connectionStringSettings;
public ConfigurationExtension(IConfiguration configuration)
{
_configuration = configuration;
_connectionStringSettings = new Lazy<ConnectionStringCollection>(new ConnectionStringCollection(GetSettings<ConnectionStringSettings>("ConnectionStrings")));
}
public IEnumerable<T> GetSettings<T>(string section) where T : new()
{
var result = new List<T>();
var sectionSettings = _configuration.GetSection(section);
foreach (var ch in sectionSettings.GetChildren())
{
var cs = new T();
ch.Bind(cs);
result.Add(cs);
}
return result;
}
public T GetSetting<T>(string section) where T : new()
{
return GetSetting(section, new T());
}
public T GetSetting<T>(string section, T instance)
{
var sectionSettings = _configuration.GetSection(section);
sectionSettings.Bind(instance);
return instance;
}
public ConnectionStringCollection GetConnectionStrings()
{
return _connectionStringSettings.Value;
}
public ConnectionStringSettings GetConnectionStrings(string key)
{
return GetConnectionStrings()[key];
}
}

View File

@ -23,28 +23,29 @@
*
*/
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
public static class CrossPlatform
{
public static class CrossPlatform
private static char[] _pathSplitCharacters = new char[] { '/', '\\' };
public static string PathCombine(string basePath, params string[] additional)
{
public static string PathCombine(string basePath, params string[] additional)
var splits = additional.Select(s => s.Split(_pathSplitCharacters)).ToArray();
var totalLength = splits.Sum(arr => arr.Length);
var segments = new string[totalLength + 1];
segments[0] = basePath;
var i = 0;
foreach (var split in splits)
{
var splits = additional.Select(s => s.Split(pathSplitCharacters)).ToArray();
var totalLength = splits.Sum(arr => arr.Length);
var segments = new string[totalLength + 1];
segments[0] = basePath;
var i = 0;
foreach (var split in splits)
foreach (var value in split)
{
foreach (var value in split)
{
i++;
segments[i] = value;
}
i++;
segments[i] = value;
}
return Path.Combine(segments);
}
static char[] pathSplitCharacters = new char[] { '/', '\\' };
return Path.Combine(segments);
}
}

View File

@ -23,228 +23,247 @@
*
*/
namespace ASC.Common.Utils
{
public class DnsLookup
{
private readonly IDnsResolver _sDnsResolver;
private readonly DnsClient _dnsClient;
public DnsLookup()
{
_dnsClient = DnsClient.Default;
_sDnsResolver = new DnsStubResolver(_dnsClient);
}
/// <summary>
/// Get domain MX records
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of MxRecord</returns>
public List<MxRecord> GetDomainMxRecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var mxRecords = DnsResolve<MxRecord>(domainName, RecordType.Mx);
return mxRecords;
}
/// <summary>
/// Check existance of MX record in domain DNS
/// </summary>
/// <param name="domainName">domain name</param>
/// <param name="mxRecord">MX record value</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainMxRecordExists(string domainName, string mxRecord)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
if (string.IsNullOrEmpty(mxRecord))
throw new ArgumentNullException(nameof(mxRecord));
var mxDomain = DomainName.Parse(mxRecord);
var records = GetDomainMxRecords(domainName);
return records.Any(
mx => mx.ExchangeDomainName.Equals(mxDomain));
}
/// <summary>
/// Check domain existance
/// </summary>
/// <param name="domainName"></param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <exception cref="SystemException">if DNS request failed</exception>
/// <returns>true if any DNS record exists and vice versa</returns>
public bool IsDomainExists(string domainName)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var dnsMessage = GetDnsMessage(domainName);
return dnsMessage.AnswerRecords.Any();
}
/// <summary>
/// Get domain A records
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of ARecord</returns>
public List<ARecord> GetDomainARecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var aRecords = DnsResolve<ARecord>(domainName, RecordType.A);
return aRecords;
}
/// <summary>
/// Get domain IP addresses list
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of IPAddress</returns>
public List<IPAddress> GetDomainIPs(string domainName)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var addresses = _sDnsResolver.ResolveHost(domainName);
return addresses;
}
/// <summary>
/// Get domain TXT records
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of TxtRecord</returns>
public List<TxtRecord> GetDomainTxtRecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var txtRecords = DnsResolve<TxtRecord>(domainName, RecordType.Txt);
return txtRecords;
}
/// <summary>
/// Check existance of TXT record in domain DNS
/// </summary>
/// <param name="domainName">domain name</param>
/// <param name="recordValue">TXT record value</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainTxtRecordExists(string domainName, string recordValue)
{
var txtRecords = GetDomainTxtRecords(domainName);
return
txtRecords.Any(
txtRecord =>
txtRecord.TextData.Trim('\"').Equals(recordValue, StringComparison.InvariantCultureIgnoreCase));
}
/// <summary>
/// Check existance of DKIM record in domain DNS
/// </summary>
/// <param name="domainName">domain name</param>
/// <param name="dkimSelector">DKIM selector (example is "dkim")</param>
/// <param name="dkimValue">DKIM record value</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainDkimRecordExists(string domainName, string dkimSelector, string dkimValue)
{
var dkimRecordName = dkimSelector + "._domainkey." + domainName;
var txtRecords = GetDomainTxtRecords(dkimRecordName);
return txtRecords.Any(txtRecord => txtRecord.TextData.Trim('\"').Equals(dkimValue));
}
/// <summary>
/// Check existance Domain in PTR record
/// </summary>
/// <param name="ipAddress">IP address for PTR check</param>
/// <param name="domainName">PTR domain name</param>
/// <exception cref="ArgumentNullException">if domainName or ipAddress is empty/null</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainPtrRecordExists(IPAddress ipAddress, string domainName)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
if (ipAddress == null)
throw new ArgumentNullException(nameof(ipAddress));
var domain = DomainName.Parse(domainName);
var ptrDomain = _sDnsResolver.ResolvePtr(ipAddress);
return ptrDomain.Equals(domain);
}
/// <summary>
/// Check existance Domain in PTR record
/// </summary>
/// <param name="ipAddress">IP address for PTR check</param>
/// <param name="domainName">PTR domain name</param>
/// <exception cref="ArgumentNullException">if domainName or ipAddress is empty/null</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <exception cref="FormatException">if ipAddress is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainPtrRecordExists(string ipAddress, string domainName)
{
return IsDomainPtrRecordExists(IPAddress.Parse(ipAddress), domainName);
}
private DnsMessage GetDnsMessage(string domainName, RecordType? type = null)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var domain = DomainName.Parse(domainName);
var dnsMessage = type.HasValue ? _dnsClient.Resolve(domain, type.Value) : _dnsClient.Resolve(domain);
if ((dnsMessage == null) ||
((dnsMessage.ReturnCode != ReturnCode.NoError) && (dnsMessage.ReturnCode != ReturnCode.NxDomain)))
{
throw new SystemException(); // DNS request failed
}
return dnsMessage;
}
private List<T> DnsResolve<T>(string domainName, RecordType type)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var dnsMessage = GetDnsMessage(domainName, type);
return dnsMessage.AnswerRecords.Where(r => r.RecordType == type).Cast<T>().ToList();
}
}
}
namespace ASC.Common.Utils;
public class DnsLookup
{
private readonly IDnsResolver _sDnsResolver;
private readonly DnsClient _dnsClient;
public DnsLookup()
{
_dnsClient = DnsClient.Default;
_sDnsResolver = new DnsStubResolver(_dnsClient);
}
/// <summary>
/// Get domain MX records
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of MxRecord</returns>
public List<MxRecord> GetDomainMxRecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var mxRecords = DnsResolve<MxRecord>(domainName, RecordType.Mx);
return mxRecords;
}
/// <summary>
/// Check existance of MX record in domain DNS
/// </summary>
/// <param name="domainName">domain name</param>
/// <param name="mxRecord">MX record value</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainMxRecordExists(string domainName, string mxRecord)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
if (string.IsNullOrEmpty(mxRecord))
{
throw new ArgumentNullException(nameof(mxRecord));
}
var mxDomain = DomainName.Parse(mxRecord);
var records = GetDomainMxRecords(domainName);
return records.Any(
mx => mx.ExchangeDomainName.Equals(mxDomain));
}
/// <summary>
/// Check domain existance
/// </summary>
/// <param name="domainName"></param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <exception cref="SystemException">if DNS request failed</exception>
/// <returns>true if any DNS record exists and vice versa</returns>
public bool IsDomainExists(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var dnsMessage = GetDnsMessage(domainName);
return dnsMessage.AnswerRecords.Count != 0;
}
/// <summary>
/// Get domain A records
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of ARecord</returns>
public List<ARecord> GetDomainARecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var aRecords = DnsResolve<ARecord>(domainName, RecordType.A);
return aRecords;
}
/// <summary>
/// Get domain IP addresses list
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of IPAddress</returns>
public List<IPAddress> GetDomainIPs(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var addresses = _sDnsResolver.ResolveHost(domainName);
return addresses;
}
/// <summary>
/// Get domain TXT records
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of TxtRecord</returns>
public List<TxtRecord> GetDomainTxtRecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var txtRecords = DnsResolve<TxtRecord>(domainName, RecordType.Txt);
return txtRecords;
}
/// <summary>
/// Check existance of TXT record in domain DNS
/// </summary>
/// <param name="domainName">domain name</param>
/// <param name="recordValue">TXT record value</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainTxtRecordExists(string domainName, string recordValue)
{
var txtRecords = GetDomainTxtRecords(domainName);
return
txtRecords.Any(
txtRecord =>
txtRecord.TextData.Trim('\"').Equals(recordValue, StringComparison.InvariantCultureIgnoreCase));
}
/// <summary>
/// Check existance of DKIM record in domain DNS
/// </summary>
/// <param name="domainName">domain name</param>
/// <param name="dkimSelector">DKIM selector (example is "dkim")</param>
/// <param name="dkimValue">DKIM record value</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainDkimRecordExists(string domainName, string dkimSelector, string dkimValue)
{
var dkimRecordName = dkimSelector + "._domainkey." + domainName;
var txtRecords = GetDomainTxtRecords(dkimRecordName);
return txtRecords.Any(txtRecord => txtRecord.TextData.Trim('\"').Equals(dkimValue));
}
/// <summary>
/// Check existance Domain in PTR record
/// </summary>
/// <param name="ipAddress">IP address for PTR check</param>
/// <param name="domainName">PTR domain name</param>
/// <exception cref="ArgumentNullException">if domainName or ipAddress is empty/null</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainPtrRecordExists(IPAddress ipAddress, string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
if (ipAddress == null)
{
throw new ArgumentNullException(nameof(ipAddress));
}
var domain = DomainName.Parse(domainName);
var ptrDomain = _sDnsResolver.ResolvePtr(ipAddress);
return ptrDomain.Equals(domain);
}
/// <summary>
/// Check existance Domain in PTR record
/// </summary>
/// <param name="ipAddress">IP address for PTR check</param>
/// <param name="domainName">PTR domain name</param>
/// <exception cref="ArgumentNullException">if domainName or ipAddress is empty/null</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <exception cref="FormatException">if ipAddress is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainPtrRecordExists(string ipAddress, string domainName)
{
return IsDomainPtrRecordExists(IPAddress.Parse(ipAddress), domainName);
}
private DnsMessage GetDnsMessage(string domainName, RecordType? type = null)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var domain = DomainName.Parse(domainName);
var dnsMessage = type.HasValue ? _dnsClient.Resolve(domain, type.Value) : _dnsClient.Resolve(domain);
if ((dnsMessage == null) ||
((dnsMessage.ReturnCode != ReturnCode.NoError) && (dnsMessage.ReturnCode != ReturnCode.NxDomain)))
{
throw new SystemException(); // DNS request failed
}
return dnsMessage;
}
private List<T> DnsResolve<T>(string domainName, RecordType type)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var dnsMessage = GetDnsMessage(domainName, type);
return dnsMessage.AnswerRecords.Where(r => r.RecordType == type).Cast<T>().ToList();
}
}

View File

@ -23,82 +23,94 @@
*
*/
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
public static class HtmlUtil
{
public static class HtmlUtil
private static readonly Regex _tagReplacer
= new Regex("<[^>]*>", RegexOptions.Multiline | RegexOptions.Compiled);
private static readonly Regex _commentsReplacer
= new Regex("<!--(?s).*?-->", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex _xssReplacer
= new Regex(@"<\s*(style|script)[^>]*>(.*?)<\s*/\s*(style|script)>", RegexOptions.IgnoreCase
| RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.Singleline);
private static readonly Regex _worder =
new Regex(@"\S+", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
public static string GetText(string html, int maxLength = 0, string endBlockTemplate = "...")
{
private static readonly Regex tagReplacer = new Regex("<[^>]*>", RegexOptions.Multiline | RegexOptions.Compiled);
private static readonly Regex commentsReplacer = new Regex("<!--(?s).*?-->", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex xssReplacer = new Regex(@"<\s*(style|script)[^>]*>(.*?)<\s*/\s*(style|script)>", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.Singleline);
private static readonly Regex Worder = new Regex(@"\S+", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
var unformatedText = string.Empty;
public static string GetText(string html, int maxLength = 0, string endBlockTemplate = "...")
if (!string.IsNullOrEmpty(html))
{
var unformatedText = string.Empty;
if (!string.IsNullOrEmpty(html))
html = _xssReplacer.Replace(html, string.Empty); //Clean malicious tags. <script> <style>
if (string.IsNullOrEmpty(html))
{
html = xssReplacer.Replace(html, string.Empty); //Clean malicious tags. <script> <style>
return html;
}
if (string.IsNullOrEmpty(html))
{
return html;
}
unformatedText = _tagReplacer.Replace(html, string.Empty);
unformatedText = tagReplacer.Replace(html, string.Empty);
if (!string.IsNullOrEmpty(unformatedText))
{
// kill comments
unformatedText = _commentsReplacer.Replace(unformatedText, string.Empty);
unformatedText = unformatedText.Trim();
if (!string.IsNullOrEmpty(unformatedText))
{
// kill comments
unformatedText = commentsReplacer.Replace(unformatedText, string.Empty);
unformatedText = unformatedText.Trim();
if (!string.IsNullOrEmpty(unformatedText))
if (maxLength == 0 || unformatedText.Length < maxLength)
{
if (maxLength == 0 || unformatedText.Length < maxLength)
{
return HttpUtility.HtmlDecode(unformatedText);
}
return HttpUtility.HtmlDecode(unformatedText);
}
//Set maximum length with end block
maxLength = Math.Max(0, maxLength - endBlockTemplate.Length);
var startIndex = Math.Max(0, Math.Min(unformatedText.Length - 1, maxLength));
var countToScan = Math.Max(0, startIndex - 1);
//Set maximum length with end block
maxLength = Math.Max(0, maxLength - endBlockTemplate.Length);
var startIndex = Math.Max(0, Math.Min(unformatedText.Length - 1, maxLength));
var countToScan = Math.Max(0, startIndex - 1);
var lastSpaceIndex = unformatedText.LastIndexOf(' ', startIndex, countToScan);
var lastSpaceIndex = unformatedText.LastIndexOf(' ', startIndex, countToScan);
unformatedText = lastSpaceIndex > 0 && lastSpaceIndex < unformatedText.Length
? unformatedText.Remove(lastSpaceIndex)
: unformatedText.Substring(0, maxLength);
if (!string.IsNullOrEmpty(endBlockTemplate))
{
unformatedText += endBlockTemplate;
}
unformatedText = lastSpaceIndex > 0 && lastSpaceIndex < unformatedText.Length
? unformatedText.Remove(lastSpaceIndex)
: unformatedText.Substring(0, maxLength);
if (!string.IsNullOrEmpty(endBlockTemplate))
{
unformatedText += endBlockTemplate;
}
}
}
return HttpUtility.HtmlDecode(unformatedText);//TODO:!!!
}
public static string ToPlainText(string html)
return HttpUtility.HtmlDecode(unformatedText);//TODO:!!!
}
public static string ToPlainText(string html)
{
return GetText(html);
}
/// <summary>
/// The function highlight all words in htmlText by searchText.
/// </summary>
/// <param name="searchText">the space separated string</param>
/// <param name="htmlText">html for highlight</param>
/// <param name="withoutLink"></param>
/// <returns>highlighted html</returns>
public static string SearchTextHighlight(string searchText, string htmlText, bool withoutLink = false)
{
if (string.IsNullOrEmpty(searchText) || string.IsNullOrEmpty(htmlText))
{
return GetText(html);
return htmlText;
}
/// <summary>
/// The function highlight all words in htmlText by searchText.
/// </summary>
/// <param name="searchText">the space separated string</param>
/// <param name="htmlText">html for highlight</param>
/// <param name="withoutLink"></param>
/// <returns>highlighted html</returns>
public static string SearchTextHighlight(string searchText, string htmlText, bool withoutLink = false)
{
if (string.IsNullOrEmpty(searchText) || string.IsNullOrEmpty(htmlText)) return htmlText;
var regexpstr = Worder.Matches(searchText).Cast<Match>().Select(m => m.Value).Distinct().Aggregate((r, n) => r + "|" + n);
var wordsFinder = new Regex(Regex.Escape(regexpstr), RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Multiline);
return wordsFinder.Replace(htmlText, m => string.Format("<span class='searchTextHighlight{1}'>{0}</span>", m.Value, withoutLink ? " bold" : string.Empty));
}
var regexpstr = _worder.Matches(searchText).Select(m => m.Value).Distinct().Aggregate((r, n) => r + "|" + n);
var wordsFinder = new Regex(Regex.Escape(regexpstr), RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Multiline);
return wordsFinder.Replace(htmlText, m => "<span class='searchTextHighlight" + (withoutLink ? " bold" : string.Empty) + "'>" + m.Value + "</span>");
}
}

View File

@ -26,186 +26,190 @@
using HttpContext = Microsoft.AspNetCore.Http.HttpContext;
namespace System.Web
{
public static class HttpRequestExtensions
{
public static readonly string UrlRewriterHeader = "X-REWRITER-URL";
public static Uri GetUrlRewriter(this HttpRequest request)
{
return request != null ? GetUrlRewriter(request.Headers, request) : null;
}
public static Uri Url(this HttpRequest request)
{
return request != null ? new Uri(request.GetDisplayUrl()) : null;
}
/*public static Uri GetUrlRewriter(this HttpRequestBase request)
{
return request != null ? GetUrlRewriter(request.Headers, request.Url) : null;
}*/
public static Uri GetUrlRewriter(IHeaderDictionary headers, HttpRequest request)
{
if (headers != null)
{
var h = headers[UrlRewriterHeader];
var rewriterUri = !string.IsNullOrEmpty(h) ? ParseRewriterUrl(h) : null;
if (request != null && rewriterUri != null)
{
var result = new UriBuilder()
{
Scheme = rewriterUri.Scheme,
Host = rewriterUri.Host,
Port = rewriterUri.Port
};
result.Query = request.QueryString.Value;
result.Path = request.Path.Value;
return result.Uri;
}
}
namespace System.Web;
if (request != null && request.Query != null)
{
var h = request.Query[UrlRewriterHeader];
var rewriterUri = !string.IsNullOrEmpty(h) ? ParseRewriterUrl(h) : null;
if (rewriterUri != null)
{
var result = new UriBuilder()
{
Scheme = rewriterUri.Scheme,
Host = rewriterUri.Host,
Port = rewriterUri.Port
};
result.Query = request.QueryString.Value;
result.Path = request.Path.Value;
return result.Uri;
}
}
return request.Url();
}
public static Uri PushRewritenUri(this HttpContext context)
{
return context != null ? PushRewritenUri(context, GetUrlRewriter(context.Request)) : null;
}
public static Uri PushRewritenUri(this HttpContext context, Uri rewrittenUri)
{
Uri oldUri = null;
if (context != null)
{
var request = context.Request;
var url = new Uri(request.GetDisplayUrl());
if (url != rewrittenUri)
{
var requestUri = url;
try
{
//Push it
request.Headers.SetCommaSeparatedValues("HTTPS", rewrittenUri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase) ? "on" : "off");
request.Headers.SetCommaSeparatedValues("SERVER_NAME", rewrittenUri.Host);
request.Headers.SetCommaSeparatedValues("SERVER_PORT",
rewrittenUri.Port.ToString(CultureInfo.InvariantCulture));
if (rewrittenUri.IsDefaultPort)
{
request.Headers.SetCommaSeparatedValues("HTTP_HOST",
rewrittenUri.Host);
}
else
{
request.Headers.SetCommaSeparatedValues("HTTP_HOST",
rewrittenUri.Host + ":" + requestUri.Port);
}
//Hack:
typeof(HttpRequest).InvokeMember("_url",
BindingFlags.NonPublic | BindingFlags.SetField |
BindingFlags.Instance,
null, request,
new object[] { null });
oldUri = requestUri;
context.Items["oldUri"] = oldUri;
}
catch (Exception)
{
}
}
}
return oldUri;
}
public static Uri PopRewritenUri(this HttpContext context)
{
if (context != null && context.Items["oldUri"] != null)
{
var rewriteTo = context.Items["oldUri"] as Uri;
if (rewriteTo != null)
{
return PushRewritenUri(context, rewriteTo);
}
}
return null;
}
public static bool DesktopApp(this HttpRequest request)
public static class HttpRequestExtensions
{
public static readonly string UrlRewriterHeader = "X-REWRITER-URL";
public static Uri GetUrlRewriter(this HttpRequest request)
{
return request != null ? GetUrlRewriter(request.Headers, request) : null;
}
public static Uri Url(this HttpRequest request)
{
return request != null ? new Uri(request.GetDisplayUrl()) : null;
}
/*public static Uri GetUrlRewriter(this HttpRequestBase request)
{
return request != null ? GetUrlRewriter(request.Headers, request.Url) : null;
}*/
public static Uri GetUrlRewriter(IHeaderDictionary headers, HttpRequest request)
{
if (headers != null)
{
return request != null
&& (!string.IsNullOrEmpty(request.Query["desktop"])
|| !string.IsNullOrEmpty(request.Headers[HeaderNames.UserAgent]) && request.Headers[HeaderNames.UserAgent].ToString().Contains("AscDesktopEditor"));
}
public static bool SailfishApp(this HttpRequest request)
{
return request != null
&& (!string.IsNullOrEmpty(request.Headers["sailfish"])
|| !string.IsNullOrEmpty(request.Headers[HeaderNames.UserAgent]) && request.Headers[HeaderNames.UserAgent].ToString().Contains("SailfishOS"));
}
private static Uri ParseRewriterUrl(string s)
{
if (string.IsNullOrEmpty(s))
{
return null;
}
const StringComparison cmp = StringComparison.OrdinalIgnoreCase;
if (0 < s.Length && (s.StartsWith("0", cmp)))
{
s = Uri.UriSchemeHttp + s.Substring(1);
}
else if (3 < s.Length && s.StartsWith("OFF", cmp))
{
s = Uri.UriSchemeHttp + s.Substring(3);
}
else if (0 < s.Length && (s.StartsWith("1", cmp)))
{
s = Uri.UriSchemeHttps + s.Substring(1);
}
else if (2 < s.Length && s.StartsWith("ON", cmp))
{
s = Uri.UriSchemeHttps + s.Substring(2);
}
else if (s.StartsWith(Uri.UriSchemeHttp + "%3A%2F%2F", cmp) || s.StartsWith(Uri.UriSchemeHttps + "%3A%2F%2F", cmp))
{
s = HttpUtility.UrlDecode(s);
}
Uri.TryCreate(s, UriKind.Absolute, out var result);
return result;
}
public static string GetUserHostAddress(this HttpRequest request)
{
return request.HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress.ToString();
}
}
}
var h = headers[UrlRewriterHeader];
var rewriterUri = !string.IsNullOrEmpty(h) ? ParseRewriterUrl(h) : null;
if (request != null && rewriterUri != null)
{
var result = new UriBuilder()
{
Scheme = rewriterUri.Scheme,
Host = rewriterUri.Host,
Port = rewriterUri.Port
};
result.Query = request.QueryString.Value;
result.Path = request.Path.Value;
return result.Uri;
}
}
if (request != null && request.Query != null)
{
var h = request.Query[UrlRewriterHeader];
var rewriterUri = !string.IsNullOrEmpty(h) ? ParseRewriterUrl(h) : null;
if (rewriterUri != null)
{
var result = new UriBuilder()
{
Scheme = rewriterUri.Scheme,
Host = rewriterUri.Host,
Port = rewriterUri.Port
};
result.Query = request.QueryString.Value;
result.Path = request.Path.Value;
return result.Uri;
}
}
return request.Url();
}
public static Uri PushRewritenUri(this HttpContext context)
{
return context != null ? PushRewritenUri(context, GetUrlRewriter(context.Request)) : null;
}
public static Uri PushRewritenUri(this HttpContext context, Uri rewrittenUri)
{
Uri oldUri = null;
if (context != null)
{
var request = context.Request;
var url = new Uri(request.GetDisplayUrl());
if (url != rewrittenUri)
{
var requestUri = url;
try
{
//Push it
request.Headers.SetCommaSeparatedValues("HTTPS", rewrittenUri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase) ? "on" : "off");
request.Headers.SetCommaSeparatedValues("SERVER_NAME", rewrittenUri.Host);
request.Headers.SetCommaSeparatedValues("SERVER_PORT",
rewrittenUri.Port.ToString(CultureInfo.InvariantCulture));
if (rewrittenUri.IsDefaultPort)
{
request.Headers.SetCommaSeparatedValues("HTTP_HOST",
rewrittenUri.Host);
}
else
{
request.Headers.SetCommaSeparatedValues("HTTP_HOST",
rewrittenUri.Host + ":" + requestUri.Port);
}
//Hack:
typeof(HttpRequest).InvokeMember("_url",
BindingFlags.NonPublic | BindingFlags.SetField |
BindingFlags.Instance,
null, request,
new object[] { null });
oldUri = requestUri;
context.Items["oldUri"] = oldUri;
}
catch (Exception) { }
}
}
return oldUri;
}
public static Uri PopRewritenUri(this HttpContext context)
{
if (context != null && context.Items["oldUri"] != null)
{
var rewriteTo = context.Items["oldUri"] as Uri;
if (rewriteTo != null)
{
return PushRewritenUri(context, rewriteTo);
}
}
return null;
}
public static bool DesktopApp(this HttpRequest request)
{
return request != null
&& (!string.IsNullOrEmpty(request.Query["desktop"])
|| !string.IsNullOrEmpty(request.Headers[HeaderNames.UserAgent]) && request.Headers[HeaderNames.UserAgent].ToString().Contains("AscDesktopEditor"));
}
public static bool SailfishApp(this HttpRequest request)
{
return request != null
&& (!string.IsNullOrEmpty(request.Headers["sailfish"])
|| !string.IsNullOrEmpty(request.Headers[HeaderNames.UserAgent]) && request.Headers[HeaderNames.UserAgent].ToString().Contains("SailfishOS"));
}
public static string GetUserHostAddress(this HttpRequest request)
{
return request.HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress.ToString();
}
private static Uri ParseRewriterUrl(string s)
{
if (string.IsNullOrEmpty(s))
{
return null;
}
const StringComparison cmp = StringComparison.OrdinalIgnoreCase;
if (0 < s.Length && s.StartsWith('0'))
{
s = Uri.UriSchemeHttp + s.Substring(1);
}
else if (3 < s.Length && s.StartsWith("OFF", cmp))
{
s = Uri.UriSchemeHttp + s.Substring(3);
}
else if (0 < s.Length && s.StartsWith('1'))
{
s = Uri.UriSchemeHttps + s.Substring(1);
}
else if (2 < s.Length && s.StartsWith("ON", cmp))
{
s = Uri.UriSchemeHttps + s.Substring(2);
}
else if (s.StartsWith(Uri.UriSchemeHttp + "%3A%2F%2F", cmp) || s.StartsWith(Uri.UriSchemeHttps + "%3A%2F%2F", cmp))
{
s = HttpUtility.UrlDecode(s);
}
Uri.TryCreate(s, UriKind.Absolute, out var result);
return result;
}
}

View File

@ -27,70 +27,69 @@
using Formatting = Newtonsoft.Json.Formatting;
using IJsonSerializer = JWT.IJsonSerializer;
namespace ASC.Web.Core.Files
namespace ASC.Web.Core.Files;
public static class JsonWebToken
{
public class JsonWebToken
public static string Encode(object payload, string key)
{
public static string Encode(object payload, string key)
{
var (serializer, algorithm, urlEncoder) = GetSettings();
var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
var (serializer, algorithm, urlEncoder) = GetSettings();
var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
return encoder.Encode(payload, key);
}
public static string Decode(string token, string key, bool verify = true, bool baseSerializer = false)
{
var (serializer, algorithm, urlEncoder) = GetSettings(baseSerializer);
var provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
var decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
return decoder.Decode(token, key, verify);
}
private static (IJsonSerializer, IJwtAlgorithm, IBase64UrlEncoder) GetSettings(bool baseSerializer = false)
{
return (baseSerializer ? (IJsonSerializer)new JsonNetSerializer() : new JwtSerializer(), new HMACSHA256Algorithm(), new JwtBase64UrlEncoder());
}
return encoder.Encode(payload, key);
}
public class JwtSerializer : IJsonSerializer
public static string Decode(string token, string key, bool verify = true, bool baseSerializer = false)
{
private class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
{
var contract = base.CreateDictionaryContract(objectType);
var (serializer, algorithm, urlEncoder) = GetSettings(baseSerializer);
contract.DictionaryKeyResolver = propertyName => propertyName;
var provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
return contract;
}
}
var decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
public string Serialize(object obj)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCaseExceptDictionaryKeysResolver(),
NullValueHandling = NullValueHandling.Ignore,
};
return decoder.Decode(token, key, verify);
}
return JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
}
public T Deserialize<T>(string json)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCaseExceptDictionaryKeysResolver(),
NullValueHandling = NullValueHandling.Ignore,
};
return JsonConvert.DeserializeObject<T>(json, settings);
}
private static (IJsonSerializer, IJwtAlgorithm, IBase64UrlEncoder) GetSettings(bool baseSerializer = false)
{
return (baseSerializer ? (IJsonSerializer)new JsonNetSerializer() : new JwtSerializer(), new HMACSHA256Algorithm(), new JwtBase64UrlEncoder());
}
}
public class JwtSerializer : IJsonSerializer
{
private class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
{
var contract = base.CreateDictionaryContract(objectType);
contract.DictionaryKeyResolver = propertyName => propertyName;
return contract;
}
}
public string Serialize(object obj)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCaseExceptDictionaryKeysResolver(),
NullValueHandling = NullValueHandling.Ignore,
};
return JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
}
public T Deserialize<T>(string json)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCaseExceptDictionaryKeysResolver(),
NullValueHandling = NullValueHandling.Ignore,
};
return JsonConvert.DeserializeObject<T>(json, settings);
}
}

View File

@ -23,46 +23,48 @@
*
*/
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
public static class MailAddressUtils
{
public static class MailAddressUtils
public static MailAddress Create(string address)
{
public static MailAddress Create(string address)
if (!string.IsNullOrEmpty(address))
{
if (!string.IsNullOrEmpty(address))
var firstPos = address.IndexOf('"');
var lastPos = address.LastIndexOf('"');
if (firstPos != -1 && firstPos < lastPos && address.IndexOf('"', firstPos + 1, lastPos - firstPos - 1) != -1)
{
var firstPos = address.IndexOf('"');
var lastPos = address.LastIndexOf('"');
if (firstPos != -1 && firstPos < lastPos && address.IndexOf('"', firstPos + 1, lastPos - firstPos - 1) != -1)
{
address = new StringBuilder(address).Replace("\"", string.Empty, firstPos + 1, lastPos - firstPos - 1).ToString();
}
address = new StringBuilder(address).Replace("\"", string.Empty, firstPos + 1, lastPos - firstPos - 1).ToString();
}
return new MailAddress(address);
}
public static MailAddress Create(string address, string displayName)
return new MailAddress(address);
}
public static MailAddress Create(string address, string displayName)
{
if (!string.IsNullOrEmpty(displayName))
{
if (!string.IsNullOrEmpty(displayName))
displayName = displayName.Replace("\"", string.Empty);
if (125 < displayName.Length)
{
displayName = displayName.Replace("\"", string.Empty);
if (125 < displayName.Length)
{
displayName = displayName.Substring(0, 125);
}
displayName = displayName.Substring(0, 125);
}
return Create(ToSmtpAddress(address, displayName));
}
public static string ToEncodedString(this MailAddress m)
{
return ToSmtpAddress(m.Address, MimeHeaderUtils.EncodeMime(m.DisplayName));
}
return Create(ToSmtpAddress(address, displayName));
}
public static string ToEncodedString(this MailAddress m)
{
return ToSmtpAddress(m.Address, MimeHeaderUtils.EncodeMime(m.DisplayName));
}
private static string ToSmtpAddress(string address, string displayName)
{
return string.Format("\"{0}\" <{1}>", displayName, address);
}
private static string ToSmtpAddress(string address, string displayName)
{
return $"\"{displayName}\" <{address}>";
}
}

Some files were not shown because too many files have changed in this diff Show More