Skip to content

Commit 2b8c5f9

Browse files
authored
Merge pull request #408 from Resgrid/develop
RE1-T117 Bug fixes
2 parents 674eae9 + 2288bd6 commit 2b8c5f9

7 files changed

Lines changed: 48 additions & 12 deletions

File tree

Core/Resgrid.Services/AuditService.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Data.SqlTypes;
34
using System.Linq;
45
using System.Threading;
56
using System.Threading.Tasks;
@@ -43,7 +44,13 @@ public async Task<List<AuditLog>> GetAuditLogsForDepartmentPagedAsync(int depart
4344
var safePage = page < 1 ? 1 : page;
4445
var safePageSize = pageSize < 1 ? 1 : (pageSize > 1000 ? 1000 : pageSize);
4546

46-
var logs = await _auditLogsRepository.GetAuditLogsForDepartmentPagedAsync(departmentId, startDate, endDate, (int?)logType, safePage, safePageSize);
47+
// Normalize the time window so callers that leave a bound unset (DateTime.MinValue) don't
48+
// crash or silently return nothing. Floor the inclusive start at the SQL datetime minimum,
49+
// and default the exclusive end to "now" when it is unset or precedes the start.
50+
var safeStart = startDate < (DateTime)SqlDateTime.MinValue ? (DateTime)SqlDateTime.MinValue : startDate;
51+
var safeEnd = (endDate == default(DateTime) || endDate < safeStart) ? DateTime.UtcNow : endDate;
52+
53+
var logs = await _auditLogsRepository.GetAuditLogsForDepartmentPagedAsync(departmentId, safeStart, safeEnd, (int?)logType, safePage, safePageSize);
4754
return logs.ToList();
4855
}
4956

Providers/Resgrid.Providers.Bus.Rabbit/RabbitConnection.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public static async Task<bool> VerifyAndCreateClients(string clientName)
2222
{
2323
if (_connection != null && !_connection.IsOpen)
2424
{
25-
_connection.Dispose();
25+
await _connection.DisposeAsync();
2626
_connection = null;
2727
_factory = null;
2828
RaiseConnectionReset();
@@ -82,7 +82,9 @@ public static async Task<bool> VerifyAndCreateClients(string clientName)
8282
{
8383
try
8484
{
85-
using var channel = await _connection.CreateChannelAsync();
85+
// await using to close the channel via DisposeAsync and release its channel number; a
86+
// synchronous Dispose() on a v7 IChannel skips the async close handshake and leaks channels.
87+
await using var channel = await _connection.CreateChannelAsync();
8688

8789
await channel.QueueDeclareAsync(queue: SetQueueNameForEnv(ServiceBusConfig.SystemQueueName),
8890
durable: true,
@@ -180,9 +182,13 @@ public static async Task<IConnection> CreateConnection(string clientName)
180182
if (_connection == null)
181183
await VerifyAndCreateClients(clientName);
182184

183-
if (!_connection.IsOpen)
185+
// _connection can still be null here if VerifyAndCreateClients failed to connect (e.g. primary
186+
// host down and no fallback host configured), so guard before accessing IsOpen to avoid an NRE.
187+
if (_connection == null || !_connection.IsOpen)
184188
{
185-
_connection.Dispose();
189+
if (_connection != null)
190+
await _connection.DisposeAsync();
191+
186192
_connection = null;
187193
_factory = null;
188194
RaiseConnectionReset();

Providers/Resgrid.Providers.Bus.Rabbit/RabbitInboundQueueProvider.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,9 @@ private async Task<bool> RetryQueueItem(BasicDeliverEventArgs ea, Exception mex)
652652
var connection = await RabbitConnection.CreateConnection(_clientName);
653653
if (connection != null)
654654
{
655-
using (var channel = await connection.CreateChannelAsync())
655+
// await using to close the channel via DisposeAsync and release its channel number; the
656+
// synchronous Dispose() on a v7 IChannel skips the async close handshake and leaks channels.
657+
await using (var channel = await connection.CreateChannelAsync())
656658
{
657659
var props = new BasicProperties();
658660
props.DeliveryMode = DeliveryModes.Persistent;

Providers/Resgrid.Providers.Bus.Rabbit/RabbitOutboundQueueProvider.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,11 @@ private async Task<bool> SendMessage(string queueName, string message, bool dura
120120
var connection = await RabbitConnection.CreateConnection(_clientName);
121121
if (connection != null)
122122
{
123-
using (var channel = await connection.CreateChannelAsync())
123+
// await using so the channel is closed via DisposeAsync(): the synchronous Dispose() on a
124+
// v7 IChannel skips the async Channel.Close/CloseOk handshake that releases the channel
125+
// number back to the SessionManager, leaking channels until the connection hits its limit
126+
// (ChannelAllocationException: "The connection cannot support any more channels").
127+
await using (var channel = await connection.CreateChannelAsync())
124128
{
125129
if (channel != null)
126130
{

Providers/Resgrid.Providers.Bus.Rabbit/RabbitTopicProvider.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ private static async Task<bool> VerifyAndCreateClients(string clientName)
131131

132132
if (connection != null)
133133
{
134-
using (var channel = await connection.CreateChannelAsync())
134+
// await using to close the channel via DisposeAsync and release its channel number (see SendMessage).
135+
await using (var channel = await connection.CreateChannelAsync())
135136
{
136137
await channel.ExchangeDeclareAsync(RabbitConnection.SetQueueNameForEnv(Topics.EventingTopic), "fanout");
137138
}
@@ -157,7 +158,11 @@ private async Task<bool> SendMessage(string topicName, string message)
157158
var connection = await RabbitConnection.CreateConnection(_clientName);
158159
if (connection != null)
159160
{
160-
using (var channel = await connection.CreateChannelAsync())
161+
// await using so the channel is closed via DisposeAsync(): the synchronous Dispose() on a
162+
// v7 IChannel skips the async Channel.Close/CloseOk handshake that releases the channel
163+
// number back to the SessionManager, leaking channels until the connection hits its limit
164+
// (ChannelAllocationException: "The connection cannot support any more channels").
165+
await using (var channel = await connection.CreateChannelAsync())
161166
{
162167
await channel.BasicPublishAsync(exchange: RabbitConnection.SetQueueNameForEnv(topicName),
163168
routingKey: "",

Repositories/Resgrid.Repositories.DataRepository/AuditLogsRepository.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Data;
34
using System.Data.Common;
45
using System.Threading.Tasks;
56
using Dapper;
@@ -37,8 +38,12 @@ public async Task<IEnumerable<AuditLog>> GetAuditLogsForDepartmentPagedAsync(int
3738
{
3839
var dynamicParameters = new DynamicParametersExtension();
3940
dynamicParameters.Add("DepartmentId", departmentId);
40-
dynamicParameters.Add("StartDate", startDate);
41-
dynamicParameters.Add("EndDate", endDate);
41+
// Bind the bounds as DateTime2 so out-of-SqlDateTime-range values (e.g. DateTime.MinValue
42+
// from an unset start filter) don't trigger "SqlDateTime overflow". datetime2 covers
43+
// 0001-9999 on SQL Server (vs datetime's 1753 floor) and maps to timestamp on PostgreSQL,
44+
// comparing correctly against the loggedon column either way.
45+
dynamicParameters.Add("StartDate", startDate, DbType.DateTime2);
46+
dynamicParameters.Add("EndDate", endDate, DbType.DateTime2);
4247
dynamicParameters.Add("Offset", (page - 1) * pageSize);
4348
dynamicParameters.Add("PageSize", pageSize);
4449

Repositories/Resgrid.Repositories.DataRepository/Stores/IdentityUserStore.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,9 @@ public Task<string> GetNormalizedUserNameAsync(IdentityUser user, CancellationTo
393393
if (user == null)
394394
throw new ArgumentNullException(nameof(user));
395395

396-
return Task.FromResult(user.UserName);
396+
// Prefer the stored normalized name; fall back to UserName.ToUpperInvariant() for legacy
397+
// rows whose NormalizedUserName was never populated (see SetNormalizedUserNameAsync).
398+
return Task.FromResult(user.NormalizedUserName ?? user.UserName?.ToUpperInvariant());
397399
}
398400

399401
public Task<string> GetPasswordHashAsync(IdentityUser user, CancellationToken cancellationToken)
@@ -806,6 +808,11 @@ public Task SetNormalizedUserNameAsync(IdentityUser user, string normalizedName,
806808
if (user == null)
807809
throw new ArgumentNullException(nameof(user));
808810

811+
// Persist the normalized name so new users (created via UserManager.CreateAsync during
812+
// department/account signup) get NormalizedUserName populated; otherwise it inserts as NULL
813+
// and lookups keyed on normalizedusername (= UserName.ToUpperInvariant()) can't find the user.
814+
user.NormalizedUserName = normalizedName ?? user.UserName?.ToUpperInvariant();
815+
809816
return Task.FromResult(0);
810817
}
811818

0 commit comments

Comments
 (0)