Skip to content

Commit

Permalink
chore: improve XML comments for all public facing types and methods (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewTriesToCode committed Apr 28, 2024
1 parent ef2c4c1 commit e567a69
Show file tree
Hide file tree
Showing 17 changed files with 308 additions and 31 deletions.
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

0 comments on commit e567a69

Please sign in to comment.