Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v3.27.2 #127

Merged
merged 1 commit into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

Represents the **NuGet** versions.

## v3.27.2
- *Fixed:* The `IServiceCollection.AddCosmosDb` extension method was registering as a singleton; this has been corrected to register as scoped. The dependent `CosmosClient` should remain a singleton as is [best practice](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/best-practice-dotnet).

## v3.27.1
- *Fixed:* Updated `Microsoft.Extensions.Caching.Memory` package depenedency to latest (including related); resolve [Microsoft Security Advisory CVE-2024-43483](https://github.com/advisories/GHSA-qj66-m88j-hmgj).
- *Fixed:* Fixed the `ExecutionContext.UserIsAuthorized` to have base implementation similar to `UserIsInRole`.
Expand Down
2 changes: 1 addition & 1 deletion Common.targets
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>3.27.1</Version>
<Version>3.27.2</Version>
<LangVersion>preview</LangVersion>
<Authors>Avanade</Authors>
<Company>Avanade</Company>
Expand Down
2 changes: 1 addition & 1 deletion samples/My.Hr/My.Hr.Api/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public void ConfigureServices(IServiceCollection services)
.AddAzureServiceBusSender()
.AddAzureServiceBusPurger()
.AddJsonMergePatch()
.AddWebApi((_, c) => c.UnhandledExceptionAsync = (ex, _, _) => Task.FromResult(ex is DbUpdateConcurrencyException efex ? WebApiBase.CreateActionResultFromExtendedException(new ConcurrencyException()) : null))
.AddWebApi((_, webapi) => webapi.UnhandledExceptionAsync = (ex, _, _) => Task.FromResult(ex is DbUpdateConcurrencyException efex ? webapi.CreateActionResultFromExtendedException(new ConcurrencyException()) : null))
.AddReferenceDataContentWebApi()
.AddRequestCache();

Expand Down
2 changes: 1 addition & 1 deletion samples/My.Hr/My.Hr.Functions/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public override void Configure(IFunctionsHostBuilder builder)
.AddEventPublisher()
.AddSingleton(sp => new Az.ServiceBusClient(sp.GetRequiredService<HrSettings>().ServiceBusConnection__fullyQualifiedNamespace))
.AddAzureServiceBusSender()
.AddWebApi((_, c) => c.UnhandledExceptionAsync = (ex, _, _) => Task.FromResult(ex is DbUpdateConcurrencyException efex ? WebApiBase.CreateActionResultFromExtendedException(new ConcurrencyException()) : null))
.AddWebApi((_, webapi) => webapi.UnhandledExceptionAsync = (ex, _, _) => Task.FromResult(ex is DbUpdateConcurrencyException efex ? webapi.CreateActionResultFromExtendedException(new ConcurrencyException()) : null))
.AddJsonMergePatch()
.AddWebApiPublisher()
.AddAzureServiceBusSubscriber();
Expand Down
19 changes: 17 additions & 2 deletions src/CoreEx.AspNetCore/WebApis/WebApiBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ public abstract class WebApiBase(ExecutionContext executionContext, SettingsBase
/// <remarks>Searches the <see cref="HttpRequest.Headers"/> for <see cref="HttpConsts.CorrelationIdHeaderName"/> or one of the other <see cref="SecondaryCorrelationIdNames"/> to determine the <see cref="ExecutionContext.CorrelationId"/> (uses first value found in sequence).</remarks>
public IEnumerable<string> SecondaryCorrelationIdNames { get; set; } = ["x-ms-client-tracking-id"];

/// <summary>
/// Gets or sets the <see cref="IExtendedException"/> <see cref="IActionResult"/> creator function used by <see cref="CreateActionResultFromExtendedException(IExtendedException)"/>.
/// </summary>
/// <remarks>This allows an alternate serialization or handling as required. Defaults to the <see cref="DefaultExtendedExceptionActionResultCreator"/>.</remarks>
public Func<IExtendedException, IActionResult> ExtendedExceptionActionResultCreator { get; set; } = DefaultExtendedExceptionActionResultCreator;

/// <summary>
/// Gets the list of correlation identifier names, being <see cref="HttpConsts.CorrelationIdHeaderName"/> and <see cref="SecondaryCorrelationIdNames"/> (inclusive).
/// </summary>
Expand Down Expand Up @@ -183,7 +189,9 @@ public static async Task<IActionResult> CreateActionResultFromExceptionAsync(Web
if (eex.ShouldBeLogged)
logger.LogError(exception, "{Error}", exception.Message);

ar = CreateActionResultFromExtendedException(eex);
ar = owner is null
? DefaultExtendedExceptionActionResultCreator(eex)
: owner.CreateActionResultFromExtendedException(eex);
}
else
{
Expand All @@ -204,7 +212,14 @@ public static async Task<IActionResult> CreateActionResultFromExceptionAsync(Web
/// Creates an <see cref="IActionResult"/> from an <paramref name="extendedException"/>.
/// </summary>
/// <param name="extendedException">The <see cref="IExtendedException"/>.</param>
public static IActionResult CreateActionResultFromExtendedException(IExtendedException extendedException)
public IActionResult CreateActionResultFromExtendedException(IExtendedException extendedException) => ExtendedExceptionActionResultCreator(extendedException);

/// <summary>
/// The default <see cref="ExtendedExceptionActionResultCreator"/>.
/// </summary>
/// <param name="extendedException">The <see cref="IExtendedException"/>.</param>
/// <returns>The resulting <see cref="IActionResult"/>.</returns>
public static IActionResult DefaultExtendedExceptionActionResultCreator(IExtendedException extendedException)
{
if (extendedException is ValidationException vex && vex.Messages is not null && vex.Messages.Count > 0)
{
Expand Down
7 changes: 6 additions & 1 deletion src/CoreEx.Cosmos/CosmosDb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ namespace CoreEx.Cosmos
/// <param name="database">The <see cref="Microsoft.Azure.Cosmos.Database"/>.</param>
/// <param name="mapper">The <see cref="IMapper"/>.</param>
/// <param name="invoker">Enables the <see cref="Invoker"/> to be overridden; defaults to <see cref="CosmosDbInvoker"/>.</param>
/// <remarks>It is recommended that the <see cref="CosmosDb"/> is registered as a scoped service to enable capabilities such as <see cref="CosmosDbArgs.FilterByTenantId"/> that <i>must</i> be scoped.
/// Use <see cref="Microsoft.Extensions.DependencyInjection.CosmosDbServiceCollectionExtensions.AddCosmosDb{TCosmosDb}(Microsoft.Extensions.DependencyInjection.IServiceCollection, Func{IServiceProvider, TCosmosDb}, string?)"/> to
/// register the scoped <see cref="CosmosDb"/> instance.
/// <para>The dependent <see cref="CosmosClient"/> should however be registered as a singleton as is <see href="https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/best-practice-dotnet">best practice</see>.</para></remarks>
public class CosmosDb(Database database, IMapper mapper, CosmosDbInvoker? invoker = null) : ICosmosDb
{
private static CosmosDbInvoker? _invoker;
Expand Down Expand Up @@ -181,7 +185,8 @@ public async Task<Result> SelectMultiSetWithResultAsync(PartitionKey partitionKe

if (multiSetList.Any(x => !x.Container.IsCosmosDbValueModel))
throw new ArgumentException($"All {nameof(IMultiSetArgs)} containers must be of type CosmosDbValueContainer.", nameof(multiSetArgs));


// Build the Cosmos SQL statement.
var container = multiSetList[0].Container;
var types = new Dictionary<string, IMultiSetArgs>([ new KeyValuePair<string, IMultiSetArgs>(container.ModelType.Name, multiSetList[0]) ]);
var sb = string.IsNullOrEmpty(sql) ? new StringBuilder($"SELECT * FROM c WHERE c.type in (\"{container.ModelType.Name}\"") : null;
Expand Down
8 changes: 4 additions & 4 deletions src/CoreEx.Cosmos/CosmosDbServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Microsoft.Extensions.DependencyInjection
public static class CosmosDbServiceCollectionExtensions
{
/// <summary>
/// Adds an <see cref="ICosmosDb"/> as a singleton service.
/// Adds an <see cref="ICosmosDb"/> as a scoped service.
/// </summary>
/// <typeparam name="TCosmosDb">The <see cref="ICosmosDb"/> <see cref="Type"/>.</typeparam>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
Expand All @@ -23,15 +23,15 @@ public static class CosmosDbServiceCollectionExtensions
/// <returns>The <see cref="IServiceCollection"/> to support fluent-style method-chaining.</returns>
public static IServiceCollection AddCosmosDb<TCosmosDb>(this IServiceCollection services, Func<IServiceProvider, TCosmosDb> create, bool healthCheck = true) where TCosmosDb : class, ICosmosDb
{
services.ThrowIfNull(nameof(services)).AddSingleton(sp => create.ThrowIfNull(nameof(create)).Invoke(sp));
services.ThrowIfNull(nameof(services)).AddScoped(sp => create.ThrowIfNull(nameof(create)).Invoke(sp));
if (healthCheck)
services.AddHealthChecks().AddCosmosDbHealthCheck<TCosmosDb>();

return services;
}

/// <summary>
/// Adds an <see cref="ICosmosDb"/> as a singleton service including a corresponding health check.
/// Adds an <see cref="ICosmosDb"/> as a scoped service including a corresponding health check.
/// </summary>
/// <typeparam name="TCosmosDb">The <see cref="ICosmosDb"/> <see cref="Type"/>.</typeparam>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
Expand All @@ -40,7 +40,7 @@ public static IServiceCollection AddCosmosDb<TCosmosDb>(this IServiceCollection
/// <returns>The <see cref="IServiceCollection"/> to support fluent-style method-chaining.</returns>
public static IServiceCollection AddCosmosDb<TCosmosDb>(this IServiceCollection services, Func<IServiceProvider, TCosmosDb> create, string? healthCheckName) where TCosmosDb : class, ICosmosDb
{
services.ThrowIfNull(nameof(services)).AddSingleton(sp => create.ThrowIfNull(nameof(create)).Invoke(sp));
services.ThrowIfNull(nameof(services)).AddScoped(sp => create.ThrowIfNull(nameof(create)).Invoke(sp));
services.AddHealthChecks().AddCosmosDbHealthCheck<TCosmosDb>(healthCheckName);
return services;
}
Expand Down
2 changes: 1 addition & 1 deletion src/CoreEx/Events/EventDataFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public virtual void Format(EventData @event)
var value = @event.Value;

@event.Id ??= Guid.NewGuid().ToString();
@event.Timestamp ??= new DateTimeOffset(ExecutionContext.SystemTime.UtcNow);
@event.Timestamp ??= new DateTimeOffset(ExecutionContext.HasCurrent ? ExecutionContext.Current.Timestamp : ExecutionContext.SystemTime.UtcNow);

if (PropertySelection.HasFlag(EventDataProperty.Key))
{
Expand Down
1 change: 0 additions & 1 deletion src/CoreEx/ExecutionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace CoreEx
Expand Down
Loading