Skip to content
Permalink
Browse files

Merge pull request #40 from saaskit/dev

v1.14
  • Loading branch information
benfoster committed Jul 17, 2016
2 parents 03dfe3d + 8a8a1a9 commit b761ef9295331f9758c5347d8b50b9def7b3589b
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C3B2A3F2-5EF9-4128-8035-255A1AC1AF7B}"
ProjectSection(SolutionItems) = preProject
@@ -82,6 +82,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF

ClientId = clientId,
ClientSecret = clientSecret

});
}
});
@@ -93,9 +93,9 @@
"web.config"
]
},
"scripts": {
"prepublish": [ "bower install", "dotnet bundle" ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
},
"scripts": {
"prepublish": [ "bower install", "dotnet bundle" ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
},
"userSecretsId": "aspnet5-AspNetMvcAuthSample-20160229033356"
}

Some generated files are not rendered by default. Learn more.

@@ -0,0 +1 @@
// Write your Javascript code.
@@ -4,16 +4,18 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SaasKit.Multitenancy;

namespace AspNetMvcSample.Controllers
{
public class HomeController : Controller

public class HomeController : Controller
{
private AppTenant tenant;
private readonly AppTenant tenant;

public HomeController(AppTenant tenant)
public HomeController(ITenant<AppTenant> tenant)
{
this.tenant = tenant;
this.tenant = tenant?.Value;
}

public IActionResult Index()
@@ -88,8 +88,8 @@
"web.config"
]
},
"scripts": {
"prepublish": [ "bower install", "dotnet bundle" ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
"scripts": {
"prepublish": [ "bower install", "dotnet bundle" ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
}

Some generated files are not rendered by default. Learn more.

@@ -0,0 +1 @@
// Write your Javascript code.
@@ -27,6 +27,7 @@
}
},
"tools": {
"BundlerMinifier.Core": "2.0.238",
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
},
"buildOptions": {
@@ -50,6 +51,7 @@
]
},
"scripts": {
"prepublish": [ "bower install", "dotnet bundle" ],
"postpublish": "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%"
}
}
@@ -23,12 +23,13 @@
}
}
},
"tools": {
"Microsoft.AspNetCore.Server.IISIntegration.Tools": {
"version": "1.0.0-preview2-final",
"imports": "portable-net45+win8+dnxcore50"
}
},
"tools": {
"BundlerMinifier.Core": "2.0.238",
"Microsoft.AspNetCore.Server.IISIntegration.Tools": {
"version": "1.0.0-preview2-final",
"imports": "portable-net45+win8+dnxcore50"
}
},
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true
@@ -49,8 +50,8 @@
"web.config"
]
},
"scripts": {
"prepublish": [ "bower install", "dotnet bundle" ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
"scripts": {
"prepublish": [ "bower install", "dotnet bundle" ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
}
@@ -1,45 +1,49 @@
{
"version": "1.1.3",
"description": "Multi-tenancy support for ASP.NET Core using StructureMap.",
"authors": [ "Ben Foster" ],
"version": "1.1.4",
"description": "Multi-tenancy support for ASP.NET Core using StructureMap.",
"authors": [ "Ben Foster" ],
"packOptions": {
"authors": [ "Ben Foster" ],
"owners": [ "Ben Foster" ],
"tags": [ "Multi-tenancy", "Multi-tenant", "Saas", "StructureMap" ],
"releaseNotes": "Updated to support ASP.NET Core RC-2",
"tags": [ "Multi-tenancy", "Multitenant", "Multitenancy", "Multitenant", "Saas", "StructureMap" ],
"releaseNotes": "Updated to support ASP.NET Core RTM. Resolves an issue with MemoryCache cache dependencies.",
"projectUrl": "http://saaskit.net",
"licenseUrl": "https://github.com/saaskit/saaskit/blob/master/LICENSE.md",
"requireLicenseAcceptance": false,
"repository": {
"type": "git",
"url": "https://github.com/saaskit/saaskit/"
}
},
"dependencies": {
"NETStandard.Library": "1.6.0",
"Microsoft.AspNetCore.Http.Abstractions": "1.0.0",
"Microsoft.AspNetCore.Http.Extensions": "1.0.0",
"Microsoft.Extensions.Caching.Abstractions": "1.0.0",
"Microsoft.Extensions.Caching.Memory": "1.0.0",
"Microsoft.Extensions.Logging.Abstractions": "1.0.0",
"StructureMap.Dnx": "0.5.1-rc2-final",
"SaasKit.Multitenancy": { "target": "project" }
},
"frameworks": {
"net46": { },
"net452": { },
"net451": { },
"netstandard1.6": {
"dependencies": {
"Microsoft.CSharp": "4.0.1-rc2-*",
"System.Collections": "4.0.11-rc2-*",
"System.Linq": "4.1.0-rc2-*",
"System.Runtime": "4.1.0-rc2-*",
"System.Threading": "4.0.11-rc2-*"
},
"imports": [
"dotnet5.4",
"portable-net45+win8"
]
}
}
"dependencies": {
"NETStandard.Library": "1.6.0",
"Microsoft.AspNetCore.Http.Abstractions": "1.0.0",
"Microsoft.AspNetCore.Http.Extensions": "1.0.0",
"Microsoft.Extensions.Caching.Abstractions": "1.0.0",
"Microsoft.Extensions.Caching.Memory": "1.0.0",
"Microsoft.Extensions.Logging.Abstractions": "1.0.0",
"StructureMap.Dnx": "0.5.1-rc2-final",
"SaasKit.Multitenancy": { "target": "project" }
},
"frameworks": {
"net46": {},
"net452": {},
"net451": {},
"netstandard1.6": {
"dependencies": {
"Microsoft.CSharp": "4.0.1",
"System.Collections": "4.0.11",
"System.Linq": "4.1.0",
"System.Runtime": "4.1.0",
"System.Threading": "4.0.11"
},
"imports": [
"dotnet5.4",
"portable-net45+win8"
]
}
},
"buildOptions": {
"optimize": true
}
}
@@ -4,9 +4,12 @@

namespace SaasKit.Multitenancy
{
/// <summary>
using System.Diagnostics;

/// <summary>
/// Helper class that will throw exceptions when conditions are not satisfied.
/// </summary>
[DebuggerStepThrough]
public static class Ensure
{
/// <summary>
@@ -0,0 +1,11 @@
namespace SaasKit.Multitenancy
{
/// <summary>
/// Used to retreive configured TTenant instances.
/// </summary>
/// <typeparam name="TTenant">The type of tenant being requested.</typeparam>
public interface ITenant<out TTenant>
{
TTenant Value { get; }
}
}
@@ -4,7 +4,7 @@

namespace SaasKit.Multitenancy.Internal
{
public class TenantResolutionMiddleware<TTenant>
public class TenantResolutionMiddleware<TTenant>
{
private readonly RequestDelegate next;
private readonly ILogger log;
@@ -1,8 +1,10 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace SaasKit.Multitenancy
@@ -11,22 +13,28 @@ public abstract class MemoryCacheTenantResolver<TTenant> : ITenantResolver<TTena
{
protected readonly IMemoryCache cache;
protected readonly ILogger log;
protected readonly MemoryCacheTenantResolverOptions options;

public MemoryCacheTenantResolver(IMemoryCache cache, ILoggerFactory loggerFactory)
: this(cache, loggerFactory, new MemoryCacheTenantResolverOptions())
{
}

public MemoryCacheTenantResolver(IMemoryCache cache, ILoggerFactory loggerFactory, MemoryCacheTenantResolverOptions options)
{
Ensure.Argument.NotNull(cache, nameof(cache));
Ensure.Argument.NotNull(loggerFactory, nameof(loggerFactory));
Ensure.Argument.NotNull(options, nameof(options));

this.cache = cache;
this.log = loggerFactory.CreateLogger<MemoryCacheTenantResolver<TTenant>>();
this.options = options;
}

protected virtual MemoryCacheEntryOptions CreateCacheEntryOptions()
{
return new MemoryCacheEntryOptions()
.SetSlidingExpiration(new TimeSpan(1, 0, 0))
.RegisterPostEvictionCallback((key, value, reason, state)
=> DisposeTenantContext(key, value as TenantContext<TTenant>));
.SetSlidingExpiration(new TimeSpan(1, 0, 0));
}

protected virtual void DisposeTenantContext(object cacheKey, TenantContext<TTenant> tenantContext)
@@ -67,7 +75,7 @@ async Task<TenantContext<TTenant>> ITenantResolver<TTenant>.ResolveAsync(HttpCon

if (tenantIdentifiers != null)
{
var cacheEntryOptions = CreateCacheEntryOptions();
var cacheEntryOptions = GetCacheEntryOptions();

log.LogDebug("TenantContext:{id} resolved. Caching with keys \"{tenantIdentifiers}\".", tenantContext.Id, tenantIdentifiers);

@@ -85,5 +93,35 @@ async Task<TenantContext<TTenant>> ITenantResolver<TTenant>.ResolveAsync(HttpCon

return tenantContext;
}

private MemoryCacheEntryOptions GetCacheEntryOptions()
{
var cacheEntryOptions = CreateCacheEntryOptions();

if (options.EvictAllEntriesOnExpiry)
{
var tokenSource = new CancellationTokenSource();

cacheEntryOptions
.RegisterPostEvictionCallback(
(key, value, reason, state) =>
{
tokenSource.Cancel();
})
.AddExpirationToken(new CancellationChangeToken(tokenSource.Token));
}

if (options.DisposeOnEviction)
{
cacheEntryOptions
.RegisterPostEvictionCallback(
(key, value, reason, state) =>
{
DisposeTenantContext(key, value as TenantContext<TTenant>);
});
}

return cacheEntryOptions;
}
}
}
@@ -0,0 +1,29 @@
namespace SaasKit.Multitenancy
{
/// <summary>
/// Configuration options for <see cref="MemoryCacheTenantResolver{TTenant}"/>.
/// </summary>
public class MemoryCacheTenantResolverOptions
{
/// <summary>
/// Creates a new <see cref="MemoryCacheTenantResolverOptions"/> instance.
/// </summary>
public MemoryCacheTenantResolverOptions()
{
EvictAllEntriesOnExpiry = true;
DisposeOnEviction = true;
}

/// <summary>
/// Gets or sets a setting that determines whether all cache entries for a <see cref="TenantContext{TTenant}"/>
/// instance should be evicted when any of the entries expire. Default: True.
/// </summary>
public bool EvictAllEntriesOnExpiry { get; set; }

/// <summary>
/// Gets or sets a setting that determines whether cached tenant context instances should be disposed
/// when upon eviction from the cache. Default: True.
/// </summary>
public bool DisposeOnEviction { get; set; }
}
}
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection.Extensions;
using SaasKit.Multitenancy;
using SaasKit.Multitenancy.Internal;
using System.Reflection;

namespace Microsoft.Extensions.DependencyInjection
@@ -18,15 +19,15 @@ public static class MultitenancyServiceCollectionExtensions
// No longer registered by default as of ASP.NET Core RC2
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

// Make Tenant and TenantContext injectable
services.AddScoped(prov =>
prov.GetService<IHttpContextAccessor>()?.HttpContext?.GetTenant<TTenant>());
// Make Tenant and TenantContext injectable
services.AddScoped(prov => prov.GetService<IHttpContextAccessor>()?.HttpContext?.GetTenantContext<TTenant>());
services.AddScoped(prov => prov.GetService<TenantContext<TTenant>>()?.Tenant);

services.AddScoped(prov =>
prov.GetService<IHttpContextAccessor>()?.HttpContext?.GetTenantContext<TTenant>());
// Make ITenant injectable for handling null injection, similar to IOptions
services.AddScoped<ITenant<TTenant>>(prov => new TenantWrapper<TTenant>(prov.GetService<TTenant>()));

// Ensure caching is available for caching resolvers
var resolverType = typeof(TResolver);
// Ensure caching is available for caching resolvers
var resolverType = typeof(TResolver);
if (typeof(MemoryCacheTenantResolver<TTenant>).IsAssignableFrom(resolverType))
{
services.AddMemoryCache();

0 comments on commit b761ef9

Please sign in to comment.
You can’t perform that action at this time.