Esempio n. 1
0
 /// <summary>
 /// Adds a <see cref="DomainParser"/> to the collection of parsers for detecting the current tenant's canonical name by a custom domain name.
 /// </summary>
 /// <typeparam name="TTenant">The type representing a tenant.</typeparam>
 /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
 /// <param name="builder">Builder to add the <see cref="DomainParser"/> to.</param>
 /// <returns><paramref name="builder"/> for fluent API.</returns>
 public static TenancyBuilder <TTenant, TKey> AddDomainParser <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder)
     where TTenant : class, ITenanted <TKey>
     where TKey : IEquatable <TKey>
 {
     ArgCheck.NotNull(nameof(builder), builder);
     return(builder.AddRequestParser(sp => new DomainParser()));
 }
Esempio n. 2
0
 /// <summary>
 /// Adds a <see cref="HeaderParser"/> to the collection of parsers for detecting the current tenant's canonical name by an HTTP header.
 /// Eg. use "X-TENANT" for matching on X-TENANT = tenant1
 /// </summary>
 /// <typeparam name="TTenant">The type representing a tenant.</typeparam>
 /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
 /// <param name="builder">Builder to add the <see cref="HeaderParser"/> to.</param>
 /// <param name="headerName">The HTTP header name which will contain the tenant's canonical name of the request.</param>
 /// <returns><paramref name="parsers"/> for fluent API.</returns>
 public static TenancyBuilder <TTenant, TKey> AddHeaderParser <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder, string headerName)
     where TTenant : class, ITenanted <TKey>
     where TKey : IEquatable <TKey>
 {
     ArgCheck.NotNull(nameof(builder), builder);
     ArgCheck.NotNullOrEmpty(nameof(headerName), headerName);
     return(builder.AddRequestParser(sp => new HeaderParser()
     {
         HeaderName = headerName
     }));
 }
Esempio n. 3
0
 /// <summary>
 /// Adds a <see cref="PathParser"/> to the collection of parsers for detecting the current tenant's canonical name by using a regular expression on the request's path.
 /// Eg: use "^/tenants/([a-z0-9]+)(?:[/]?)$" for matching on multitenancyserver.io/tenants/tenant1 or multitenancyserver.io/tenants/tenant1/
 /// </summary>
 /// <typeparam name="TTenant">The type representing a tenant.</typeparam>
 /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
 /// <param name="builder">Builder to add the <see cref="PathParser"/> to.</param>
 /// <param name="pathPattern">A regular expression to retreive the tenant canonical name from the path of the request.</param>
 /// <returns><paramref name="parsers"/> for fluent API.</returns>
 public static TenancyBuilder <TTenant, TKey> AddPathParser <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder, string pathPattern)
     where TTenant : class, ITenanted <TKey>
     where TKey : IEquatable <TKey>
 {
     ArgCheck.NotNull(nameof(builder), builder);
     ArgCheck.NotNullOrEmpty(nameof(pathPattern), pathPattern);
     return(builder.AddRequestParser(sp => new PathParser()
     {
         PathPattern = pathPattern
     }));
 }
Esempio n. 4
0
 /// <summary>
 /// Adds a <see cref="CustomParser"/> to the collection of parsers for detecting the current tenant's canonical name
 /// from a custom function.
 /// </summary>
 /// <typeparam name="TTenant">The type representing a tenant.</typeparam>
 /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
 /// <param name="builder">Builder to add the <see cref="CustomParser"/> to.</param>
 /// <param name="parser">Async func that returns the tenant's canonical name from the current request.</param>
 /// <returns><paramref name="parsers"/> for fluent API.</returns>
 public static TenancyBuilder <TTenant, TKey> AddCustomParser <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder, Func <HttpContext, Task <string> > parser)
     where TTenant : class, ITenanted <TKey>
     where TKey : IEquatable <TKey>
 {
     ArgCheck.NotNull(nameof(builder), builder);
     ArgCheck.NotNull(nameof(parser), parser);
     return(builder.AddRequestParser(sp => new CustomParser()
     {
         Parser = parser
     }));
 }
Esempio n. 5
0
 /// <summary>
 /// Adds a <see cref="UserClaimParser"/> to the collection of parsers for detecting the current tenant's canonical name
 /// from a user claim on the authenticated user principal.
 /// Eg: claim type "http://schemas.microsoft.com/identity/claims/tenantid" or "tid".
 /// </summary>
 /// <typeparam name="TTenant">The type representing a tenant.</typeparam>
 /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
 /// <param name="builder">Builder to add the <see cref="UserClaimParser"/> to.</param>
 /// <param name="claimType">Claim type that contains the tenant canonical name as its value.</param>
 /// <returns><paramref name="parsers"/> for fluent API.</returns>
 public static TenancyBuilder <TTenant, TKey> AddClaimParser <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder, string claimType)
     where TTenant : class, ITenanted <TKey>
     where TKey : IEquatable <TKey>
 {
     ArgCheck.NotNull(nameof(builder), builder);
     ArgCheck.NotNullOrEmpty(nameof(claimType), claimType);
     return(builder.AddRequestParser(sp => new UserClaimParser()
     {
         ClaimType = claimType
     }));
 }
Esempio n. 6
0
 /// <summary>
 /// Adds a <see cref="QueryParser"/> to the collection of parsers for detecting the current tenant's canonical name by a query string parameter.
 /// Eg: use "tenant" for matching on ?tenant=tenant1
 /// </summary>
 /// <typeparam name="TTenant">The type representing a tenant.</typeparam>
 /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
 /// <param name="builder">Builder to add the <see cref="QueryParser"/> to.</param>
 /// <param name="queryName">The query string parameter name of the tenant canonical name.</param>
 /// <returns><paramref name="parsers"/> for fluent API.</returns>
 public static TenancyBuilder <TTenant, TKey> AddQueryParser <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder, string queryName)
     where TTenant : class
     where TKey : IEquatable <TKey>
 {
     ArgCheck.NotNull(nameof(builder), builder);
     ArgCheck.NotNullOrEmpty(nameof(queryName), queryName);
     return(builder.AddRequestParser(sp => new QueryParser()
     {
         QueryName = queryName
     }));
 }
 /// <summary>
 /// Adds an Entity Framework implementation of multi-tenancy information stores.
 /// </summary>
 /// <typeparam name="TContext">The Entity Framework database context to use.</typeparam>
 /// <typeparam name="TTenant">The type encapsulating a tenant.</typeparam>
 /// <typeparam name="TKey">Key of TenantId</typeparam>
 /// <param name="builder">The <see cref="TenancyBuilder{TTenant, TKey}"/> instance this method extends.</param>
 /// <param name="contextFactory">The context factory.</param>
 /// <returns>The <see cref="TenancyBuilder{TTenant, TKey}"/> instance this method extends.</returns>
 public static TenancyBuilder <TTenant, TKey> AddEntityFrameworkStore <TContext, TTenant, TKey>(
     this TenancyBuilder <TTenant, TKey> builder,
     Func <IServiceProvider, TContext> contextFactory = null)
     where TContext : DbContext, ITenantDbContext <TTenant, TKey>
     where TTenant : TenancyTenant <TKey>
     where TKey : IEquatable <TKey>
 {
     if (contextFactory != null)
     {
         builder.Services.TryAddScoped <ITenantStore <TTenant, TKey> >(sp =>
                                                                       new TenantStore <TTenant, TContext, TKey>(
                                                                           contextFactory(sp),
                                                                           sp.GetRequiredService <ILogger <TenantStore <TTenant, TContext, TKey> > >(),
                                                                           sp.GetService <TenancyErrorDescriber>()));
     }
     else
     {
         builder.Services.TryAddScoped <ITenantStore <TTenant, TKey>, TenantStore <TTenant, TContext, TKey> >();
     }
     return(builder);
 }
Esempio n. 8
0
 /// <summary>
 /// Adds a <see cref="HostParser"/> to the collection of parsers for detecting the current tenant's canonical name by a sub-domain host based on a parent domain.
 /// Eg: use ".tenants.multitenancyserver.io" to match on "tenant1.tenants.multitenancyserver.io"
 /// </summary>
 /// <typeparam name="TTenant">The type representing a tenant.</typeparam>
 /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
 /// <param name="builder">Builder to add the <see cref="HostParser"/> to.</param>
 /// <param name="parentHostSuffix">The parent hostname suffix which will contain the tenant's canonical name as its only sub-domain hostname of the request.</param>
 /// <returns><paramref name="parsers"/> for fluent API.</returns>
 public static TenancyBuilder <TTenant, TKey> AddSubdomainParser <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder, string parentHostSuffix)
     where TTenant : class, ITenanted <TKey>
     where TKey : IEquatable <TKey>
 {
     ArgCheck.NotNull(nameof(builder), builder);
     ArgCheck.NotNullOrEmpty(nameof(parentHostSuffix), parentHostSuffix);
     return(builder.AddHostnameParser($@"^([a-z0-9-]+){Regex.Escape(parentHostSuffix).Replace(@"\*", @"[a-z0-9-]+")}$"));
 }
Esempio n. 9
0
 /// <summary>
 /// Helper functions for parsing the tenant from an HTTP request.
 /// </summary>
 /// <param name="builder">Builder to add the <see cref="IRequestParser"/> to.</param>
 /// <typeparam name="TTenant">The type representing a tenant.</typeparam>
 /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
 public static TenancyBuilder <TTenant, TKey> AddRequestParser <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder, Func <IServiceProvider, IRequestParser> parserFactory)
     where TTenant : class, ITenanted <TKey>
     where TKey : IEquatable <TKey>
 {
     ArgCheck.NotNull(nameof(builder), builder);
     builder.Services.AddScoped(parserFactory);
     return(builder);
 }
Esempio n. 10
0
 /// <summary>
 /// Adds a <see cref="CustomParser"/> to the collection of parsers for detecting the current tenant's canonical name
 /// from a custom function.
 /// </summary>
 /// <typeparam name="TTenant">The type representing a tenant.</typeparam>
 /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
 /// <param name="builder">Builder to add the <see cref="CustomParser"/> to.</param>
 /// <param name="parser">Func that returns the tenant's canonical name from the current request.</param>
 /// <returns><paramref name="parsers"/> for fluent API.</returns>
 public static TenancyBuilder <TTenant, TKey> AddCustomParser <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder, Func <HttpContext, string> parser)
     where TTenant : class, ITenanted <TKey>
     where TKey : IEquatable <TKey>
 {
     return(builder.AddCustomParser(httpContext => Task.FromResult(parser(httpContext))));
 }
Esempio n. 11
0
 /// <summary>
 /// Adds a <see cref="PathParser"/> to the collection of parsers for detecting the current tenant's canonical name by a child path based on a parent path.
 /// Eg: use "/tenants/" for matching on multitenancyserver.io/tenants/tenant1
 /// </summary>
 /// <typeparam name="TTenant">The type representing a tenant.</typeparam>
 /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
 /// <param name="builder">Builder to add the <see cref="PathParser"/> to.</param>
 /// <param name="parentPathPrefix">The parent path prefix which will contain the tenant's canonical name as its child path segment of the request.</param>
 /// <returns><paramref name="parsers"/> for fluent API.</returns>
 public static TenancyBuilder <TTenant, TKey> AddChildPathParser <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder, string parentPathPrefix)
     where TTenant : class, ITenanted <TKey>
     where TKey : IEquatable <TKey>
 {
     ArgCheck.NotNull(nameof(builder), builder);
     ArgCheck.NotNullOrEmpty(nameof(parentPathPrefix), parentPathPrefix);
     return(builder.AddPathParser($@"^{Regex.Escape(parentPathPrefix).Replace(@"\*", @"[a-z0-9-]+")}([a-z0-9._~!$&'()*+,;=:@%-]+)(?:$|[#/?].*$)"));
 }
Esempio n. 12
0
 /// <summary>
 /// Adds a <see cref="HostParser"/> to the collection of parsers for detecting the current tenant's canonical name by using a regular expression on the request's hostname.
 /// Eg: use @"^([a-z0-9][a-z0-9-]*[a-z0-9])(?:\.[a-z][a-z])?\.tenants\.multitenancyserver\.io$" for
 /// matching on tenant1.eu.tenants.multitenancyserver.io where '.eu.' is an optional and dynamic two letter region code.
 /// The first group capture of a successful match is used, use anonymouse groups (?:) to avoid unwanted captures.
 /// </summary>
 /// <typeparam name="TTenant">The type representing a tenant.</typeparam>
 /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
 /// <param name="builder">Builder to add the <see cref="HostParser"/> to.</param>
 /// <param name="hostPattern">A regular expression to retreive the tenant canonical name from the full hostname (domain) of the request.</param>
 /// <returns><paramref name="parsers"/> for fluent API.</returns>
 public static TenancyBuilder <TTenant, TKey> AddHostnameParser <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder, string hostPattern)
     where TTenant : class
     where TKey : IEquatable <TKey>
 {
     ArgCheck.NotNull(nameof(builder), builder);
     ArgCheck.NotNullOrEmpty(nameof(hostPattern), hostPattern);
     return(builder.AddRequestParser(sp => new HostParser()
     {
         HostPattern = hostPattern
     }));
 }
Esempio n. 13
0
 /// <summary>
 /// Adds a <see cref="CustomParser"/> to the collection of parsers for detecting the current tenant's canonical name
 /// from a custom function.
 /// </summary>
 /// <typeparam name="TTenant">The type representing a tenant.</typeparam>
 /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
 /// <param name="builder">Builder to add the <see cref="CustomParser"/> to.</param>
 /// <param name="parser">Func that returns the tenant's canonical name from the current request.</param>
 /// <returns><paramref name="parsers"/> for fluent API.</returns>
 public static TenancyBuilder <TTenant, TKey> AddCustomParser <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder, Func <HttpContext, string> parser)
     where TTenant : class
     where TKey : IEquatable <TKey>
 {
     return(builder.AddCustomParser(httpContext => new ValueTask <string>(parser(httpContext))));
 }
        /// <summary>
        /// Adds the in-memory tenant store.
        /// </summary>
        /// <typeparam name="TTenant">The type representing a Tenant in the system.</typeparam>
        /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
        /// <param name="builder">The builder.</param>
        /// <param name="section">The configuration section containing the configuration data.</param>
        /// <returns></returns>
        public static TenancyBuilder <TTenant, TKey> AddInMemoryStore <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder, IConfigurationSection section)
            where TTenant : TenancyTenant <TKey>
            where TKey : IEquatable <TKey>
        {
            var tenants = new List <TTenant>();

            section.Bind(tenants);
            return(builder.AddInMemoryStore(tenants));
        }
 /// <summary>
 /// Adds the in-memory tenant store.
 /// </summary>
 /// <typeparam name="TTenant">The type representing a Tenant in the system.</typeparam>
 /// <typeparam name="TKey">The type of the primary key for a tenant.</typeparam>
 /// <param name="builder">The builder.</param>
 /// <param name="tenants">The tenants.</param>
 /// <returns></returns>
 public static TenancyBuilder <TTenant, TKey> AddInMemoryStore <TTenant, TKey>(this TenancyBuilder <TTenant, TKey> builder, IEnumerable <TTenant> tenants)
     where TTenant : TenancyTenant <TKey>
     where TKey : IEquatable <TKey>
 {
     builder.Services.AddSingleton(tenants);
     builder.AddTenantStore <InMemoryTenantStore <TTenant, TKey> >();
     return(builder);
 }