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

feat: improve XML comments for all public facing types and methods #811

Merged
merged 1 commit into from
Apr 23, 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
1 change: 0 additions & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
<PackageTags>finbuckle;multitenant;multitenancy;aspnet;aspnetcore;entityframework;entityframework-core;efcore</PackageTags>
<PackageIcon>finbuckle-128x128.png</PackageIcon>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>CS1591</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@ namespace Finbuckle.MultiTenant.Abstractions;
/// </summary>
public interface IMultiTenantContextSetter
{
/// <summary>
/// Sets the MultiTenantContext.
/// </summary>
/// <value>
/// The MultiTenantContext to be set.
/// </value>
IMultiTenantContext MultiTenantContext { set; }
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@
namespace Finbuckle.MultiTenant;

/// <summary>
/// IServiceCollection extension methods for Finbuckle.MultiTenant.
/// This static class provides extension methods for the IServiceCollection interface.
/// These methods are used to configure Finbuckle.MultiTenant services for the application.
/// </summary>
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
public static class FinbuckleServiceCollectionExtensions
{
/// <summary>
/// Configure Finbuckle.MultiTenant services for the application.
/// Configures Finbuckle.MultiTenant services for the application.
/// </summary>
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
/// <param name="services">The <c>IServiceCollection</c> instance the extension method applies to.</param>
/// <param name="config">An action to configure the MultiTenantOptions instance.</param>
/// <returns>A new instance of MultiTenantBuilder.</returns>
Expand All @@ -31,7 +33,7 @@ public static MultiTenantBuilder<TTenantInfo> AddMultiTenant<TTenantInfo>(this I
{
services.AddScoped<ITenantResolver<TTenantInfo>, TenantResolver<TTenantInfo>>();
services.AddScoped<ITenantResolver>(
sp => (ITenantResolver)sp.GetRequiredService<ITenantResolver<TTenantInfo>>());
sp => sp.GetRequiredService<ITenantResolver<TTenantInfo>>());

services.AddSingleton<IMultiTenantContextAccessor<TTenantInfo>,
AsyncLocalMultiTenantContextAccessor<TTenantInfo>>();
Expand All @@ -48,17 +50,25 @@ public static MultiTenantBuilder<TTenantInfo> AddMultiTenant<TTenantInfo>(this I
}

/// <summary>
/// Configure Finbuckle.MultiTenant services for the application.
/// Configures Finbuckle.MultiTenant services for the application.
/// </summary>
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
/// <param name="services">The IServiceCollection instance the extension method applies to.</param>
/// <returns>An new instance of MultiTenantBuilder.</returns>
/// <returns>A new instance of MultiTenantBuilder.</returns>
public static MultiTenantBuilder<TTenantInfo> AddMultiTenant<TTenantInfo>(this IServiceCollection services)
where TTenantInfo : class, ITenantInfo, new()
{
return services.AddMultiTenant<TTenantInfo>(_ => { });
}

// TODO: better document and extract
/// <summary>
/// Decorates an existing service with a new implementation.
/// </summary>
/// <typeparam name="TService">The type of the service to be decorated.</typeparam>
/// <typeparam name="TImpl">The type of the new implementation.</typeparam>
/// <param name="services">The IServiceCollection instance the extension method applies to.</param>
/// <param name="parameters">Additional parameters for the new implementation.</param>
/// <returns>True if the decoration was successful, false otherwise.</returns>
public static bool DecorateService<TService, TImpl>(this IServiceCollection services, params object[] parameters)
{
var existingService = services.SingleOrDefault(s => s.ServiceType == typeof(TService));
Expand Down Expand Up @@ -146,7 +156,7 @@ public static IServiceCollection ConfigurePerTenant<TOptions, TTenantInfo>(
sp.GetRequiredService<IMultiTenantContextAccessor<TTenantInfo>>(),
(options, mtcAccessor) =>
{
var tenantInfo = mtcAccessor.MultiTenantContext?.TenantInfo;
var tenantInfo = mtcAccessor.MultiTenantContext.TenantInfo;
if (tenantInfo is not null)
configureOptions(options, tenantInfo);
}));
Expand Down Expand Up @@ -211,7 +221,7 @@ public static IServiceCollection PostConfigurePerTenant<TOptions, TTenantInfo>(
sp.GetRequiredService<IMultiTenantContextAccessor<TTenantInfo>>(),
(options, mtcAccessor) =>
{
var tenantInfo = mtcAccessor.MultiTenantContext?.TenantInfo;
var tenantInfo = mtcAccessor.MultiTenantContext.TenantInfo;
if (tenantInfo is not null)
configureOptions(options, tenantInfo);
}));
Expand Down
11 changes: 10 additions & 1 deletion src/Finbuckle.MultiTenant/MultiTenantException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,23 @@
namespace Finbuckle.MultiTenant;

/// <summary>
/// An exception generated by Finbuckle.MultiTenant.
/// Represents an exception that is thrown when an error occurs in the Finbuckle.MultiTenant library.
/// </summary>
public class MultiTenantException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="MultiTenantException"/> class with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public MultiTenantException(string? message) : base(message)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="MultiTenantException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
public MultiTenantException(string? message, Exception? innerException) : base(message, innerException)
{
}
Expand Down
16 changes: 15 additions & 1 deletion src/Finbuckle.MultiTenant/MultiTenantOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,23 @@

namespace Finbuckle.MultiTenant;

/// <summary>
/// Represents the options for a multi-tenant application.
/// </summary>
public class MultiTenantOptions
{
/// <summary>
/// Gets or sets the type of the tenant information.
/// </summary>
public Type? TenantInfoType { get; internal set; }

/// <summary>
/// Gets or sets the list of identifiers that should be ignored.
/// </summary>
public IList<string> IgnoredIdentifiers { get; set; } = new List<string>();
public MultiTenantEvents Events { get; set; } = new ();

/// <summary>
/// Gets or sets the events that can be used to customize the multi-tenant application behavior.
/// </summary>
public MultiTenantEvents Events { get; set; } = new();
}
8 changes: 4 additions & 4 deletions src/Finbuckle.MultiTenant/Options/MultiTenantOptionsCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public MultiTenantOptionsCache(IMultiTenantContextAccessor multiTenantContextAcc
/// </summary>
public void Clear()
{
var tenantId = multiTenantContextAccessor.MultiTenantContext?.TenantInfo?.Id ?? "";
var tenantId = multiTenantContextAccessor.MultiTenantContext.TenantInfo?.Id ?? "";
var cache = map.GetOrAdd(tenantId, new OptionsCache<TOptions>());

cache.Clear();
Expand Down Expand Up @@ -73,7 +73,7 @@ public TOptions GetOrAdd(string? name, Func<TOptions> createOptions)
}

name ??= Microsoft.Extensions.Options.Options.DefaultName;
var tenantId = multiTenantContextAccessor.MultiTenantContext?.TenantInfo?.Id ?? "";
var tenantId = multiTenantContextAccessor.MultiTenantContext.TenantInfo?.Id ?? "";
var cache = map.GetOrAdd(tenantId, new OptionsCache<TOptions>());

return cache.GetOrAdd(name, createOptions);
Expand All @@ -88,7 +88,7 @@ public TOptions GetOrAdd(string? name, Func<TOptions> createOptions)
public bool TryAdd(string? name, TOptions options)
{
name = name ?? Microsoft.Extensions.Options.Options.DefaultName;
var tenantId = multiTenantContextAccessor.MultiTenantContext?.TenantInfo?.Id ?? "";
var tenantId = multiTenantContextAccessor.MultiTenantContext.TenantInfo?.Id ?? "";
var cache = map.GetOrAdd(tenantId, new OptionsCache<TOptions>());

return cache.TryAdd(name, options);
Expand All @@ -102,7 +102,7 @@ public bool TryAdd(string? name, TOptions options)
public bool TryRemove(string? name)
{
name = name ?? Microsoft.Extensions.Options.Options.DefaultName;
var tenantId = multiTenantContextAccessor.MultiTenantContext?.TenantInfo?.Id ?? "";
var tenantId = multiTenantContextAccessor.MultiTenantContext.TenantInfo?.Id ?? "";
var cache = map.GetOrAdd(tenantId, new OptionsCache<TOptions>());

return cache.TryRemove(name);
Expand Down
11 changes: 11 additions & 0 deletions src/Finbuckle.MultiTenant/StoreInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,19 @@

namespace Finbuckle.MultiTenant;

/// <summary>
/// Represents the store information for a specific tenant.
/// </summary>
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
public class StoreInfo<TTenantInfo> where TTenantInfo : class, ITenantInfo, new()
{
/// <summary>
/// Gets or sets the type of the store.
/// </summary>
public Type? StoreType { get; internal set; }

/// <summary>
/// Gets or sets the multi-tenant store.
/// </summary>
public IMultiTenantStore<TTenantInfo>? Store { get; internal set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,30 @@

namespace Finbuckle.MultiTenant.Stores.HttpRemoteStore;

/// <summary>
/// The HttpRemoteStoreClient class is a generic class that is used to interact with a remote HTTP store.
/// </summary>
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
public class HttpRemoteStoreClient<TTenantInfo> where TTenantInfo : class, ITenantInfo, new()
{
private readonly IHttpClientFactory clientFactory;

/// <summary>
/// Initializes a new instance of the HttpRemoteStoreClient class.
/// </summary>
/// <param name="clientFactory">An instance of IHttpClientFactory.</param>
/// <exception cref="ArgumentNullException">Thrown when clientFactory is null.</exception>
public HttpRemoteStoreClient(IHttpClientFactory clientFactory)
{
this.clientFactory = clientFactory ?? throw new ArgumentNullException(nameof(clientFactory));
}

/// <summary>
/// Tries to get the tenant information by identifier from the remote HTTP store.
/// </summary>
/// <param name="endpointTemplate">The endpoint template to use when making the HTTP request.</param>
/// <param name="identifier">The identifier of the tenant.</param>
/// <returns>The tenant information if found; otherwise, null.</returns>
public async Task<TTenantInfo?> TryGetByIdentifierAsync(string endpointTemplate, string identifier)
{
var client = clientFactory.CreateClient(typeof(HttpRemoteStoreClient<TTenantInfo>).FullName!);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,20 @@

namespace Finbuckle.MultiTenant.Stores.InMemoryStore;

/// <summary>
/// Options for the InMemoryStore.
/// </summary>
/// <typeparam name="TTenantInfo">The ITenantInfo implementation type.</typeparam>
public class InMemoryStoreOptions<TTenantInfo>
where TTenantInfo : class, ITenantInfo, new()
{
/// <summary>
/// Gets or sets a value indicating whether the InMemoryStore should be case sensitive.
/// </summary>
public bool IsCaseSensitive { get; set; }

/// <summary>
/// Gets or sets the list of tenants to be stored in the InMemoryStore.
/// </summary>
public IList<TTenantInfo> Tenants { get; set; } = new List<TTenantInfo>();
}
13 changes: 13 additions & 0 deletions src/Finbuckle.MultiTenant/Strategies/DelegateStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,28 @@

namespace Finbuckle.MultiTenant.Strategies;

/// <summary>
/// The DelegateStrategy class implements the IMultiTenantStrategy interface and uses a delegate to determine the tenant identifier.
/// </summary>
public class DelegateStrategy : IMultiTenantStrategy
{
private readonly Func<object, Task<string?>> _doStrategy;

/// <summary>
/// Initializes a new instance of the DelegateStrategy class.
/// </summary>
/// <param name="doStrategy">A delegate that encapsulates a method to determine the tenant identifier.</param>
/// <exception cref="ArgumentNullException">Thrown when doStrategy is null.</exception>
public DelegateStrategy(Func<object, Task<string?>> doStrategy)
{
_doStrategy = doStrategy ?? throw new ArgumentNullException(nameof(doStrategy));
}

/// <summary>
/// Asynchronously determines the tenant identifier using the encapsulated delegate.
/// </summary>
/// <param name="context">The context used by the delegate to determine the tenant identifier.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the tenant identifier or null if not found.</returns>
public async Task<string?> GetIdentifierAsync(object context)
{
var identifier = await _doStrategy(context);
Expand Down
19 changes: 19 additions & 0 deletions src/Finbuckle.MultiTenant/Strategies/MultiTenantStrategyWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,37 @@

namespace Finbuckle.MultiTenant.Strategies;

/// <summary>
/// Wraps an IMultiTenantStrategy and logs exceptions.
/// </summary>
public class MultiTenantStrategyWrapper : IMultiTenantStrategy
{
/// <summary>
/// Gets the IMultiTenantStrategy instance that this wrapper is wrapping.
/// </summary>
public IMultiTenantStrategy Strategy { get; }

private readonly ILogger logger;

/// <summary>
/// Initializes a new instance of the MultiTenantStrategyWrapper class.
/// </summary>
/// <param name="strategy">The IMultiTenantStrategy instance to wrap.</param>
/// <param name="logger">An instance of ILogger.</param>
/// <exception cref="ArgumentNullException">Thrown when strategy or logger is null.</exception>
public MultiTenantStrategyWrapper(IMultiTenantStrategy strategy, ILogger logger)
{
this.Strategy = strategy ?? throw new ArgumentNullException(nameof(strategy));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

/// <summary>
/// Asynchronously determines the tenant identifier using the wrapped strategy.
/// </summary>
/// <param name="context">The context used by the strategy to determine the tenant identifier.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the tenant identifier.</returns>
/// <exception cref="ArgumentNullException">Thrown when context is null.</exception>
/// <exception cref="MultiTenantException">Thrown when an exception occurs in the wrapped strategy's GetIdentifierAsync method.</exception>
public async Task<string?> GetIdentifierAsync(object context)
{
if (context == null)
Expand Down
17 changes: 16 additions & 1 deletion src/Finbuckle.MultiTenant/Strategies/StaticStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,32 @@

namespace Finbuckle.MultiTenant.Strategies;

/// <summary>
/// The StaticStrategy class implements the IMultiTenantStrategy interface and provides a static identifier to determine the tenant.
/// </summary>
public class StaticStrategy : IMultiTenantStrategy
{
internal readonly string Identifier;

/// <summary>
/// Gets the priority of the strategy. Strategies with higher priority are evaluated first.
/// </summary>
public int Priority { get => -1000; }


/// <summary>
/// Initializes a new instance of the StaticStrategy class.
/// </summary>
/// <param name="identifier">The static identifier used to determine the tenant.</param>
public StaticStrategy(string identifier)
{
this.Identifier = identifier;
}

/// <summary>
/// Asynchronously determines the tenant identifier using the static identifier.
/// </summary>
/// <param name="context">The context used by the strategy to determine the tenant identifier. In this case, it's not used.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the tenant identifier.</returns>
public async Task<string?> GetIdentifierAsync(object context)
{
return await Task.FromResult(Identifier);
Expand Down
10 changes: 10 additions & 0 deletions src/Finbuckle.MultiTenant/StrategyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,18 @@

namespace Finbuckle.MultiTenant;

/// <summary>
/// Contextual information about the stategy used to resolve the tenant.
/// </summary>
public class StrategyInfo
{
/// <summary>
///
/// </summary>
public Type? StrategyType { get; internal set; }

/// <summary>
/// The strategy instance used to resolve the tenant.
/// </summary>
public IMultiTenantStrategy? Strategy { get; internal set; }
}
Loading
Loading