mirror of https://github.com/abpframework/abp.git
15 changed files with 327 additions and 3 deletions
@ -0,0 +1,15 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.MultiTenancy |
||||
|
{ |
||||
|
[DependsOn(typeof(AbpMultiTenancyModule), typeof(AbpAspNetCoreModule))] |
||||
|
public class AbpAspNetMultiTenancyModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(IServiceCollection services) |
||||
|
{ |
||||
|
services.AddAssemblyOf<AbpAspNetMultiTenancyModule>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.MultiTenancy |
||||
|
{ |
||||
|
public class AbpMultiTenancyModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(IServiceCollection services) |
||||
|
{ |
||||
|
services.AddAssemblyOf<AbpMultiTenancyModule>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
using Newtonsoft.Json.Serialization; |
||||
|
|
||||
|
namespace Volo.Abp.Json |
||||
|
{ |
||||
|
public static class JsonExtensions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Converts given object to JSON string.
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public static string ToJsonString(this object obj, bool camelCase = false, bool indented = false) |
||||
|
{ |
||||
|
var options = new JsonSerializerSettings(); |
||||
|
|
||||
|
if (camelCase) |
||||
|
{ |
||||
|
options.ContractResolver = new CamelCasePropertyNamesContractResolver(); |
||||
|
} |
||||
|
|
||||
|
if (indented) |
||||
|
{ |
||||
|
options.Formatting = Formatting.Indented; |
||||
|
} |
||||
|
|
||||
|
//options.Converters.Insert(0, new AbpDateTimeConverter()); //TODO: AbpDateTimeConverter?
|
||||
|
|
||||
|
return JsonConvert.SerializeObject(obj, options); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System.Reflection; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
// General Information about an assembly is controlled through the following
|
||||
|
// set of attributes. Change these attribute values to modify the information
|
||||
|
// associated with an assembly.
|
||||
|
[assembly: AssemblyConfiguration("")] |
||||
|
[assembly: AssemblyCompany("")] |
||||
|
[assembly: AssemblyProduct("Volo.Abp.AspNetCore.MultiTenancy.Tests")] |
||||
|
[assembly: AssemblyTrademark("")] |
||||
|
|
||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
|
// to COM components. If you need to access a type in this assembly from
|
||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||
|
[assembly: ComVisible(false)] |
||||
|
|
||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
|
[assembly: Guid("2c282467-2cd5-4750-be1f-ca8bd8ecc6ea")] |
||||
@ -0,0 +1,23 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
|
<PropertyGroup> |
||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion> |
||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> |
||||
|
</PropertyGroup> |
||||
|
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" /> |
||||
|
<PropertyGroup Label="Globals"> |
||||
|
<ProjectGuid>2c282467-2cd5-4750-be1f-ca8bd8ecc6ea</ProjectGuid> |
||||
|
<RootNamespace> |
||||
|
</RootNamespace> |
||||
|
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath> |
||||
|
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> |
||||
|
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup> |
||||
|
<SchemaVersion>2.0</SchemaVersion> |
||||
|
</PropertyGroup> |
||||
|
<ItemGroup> |
||||
|
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" /> |
||||
|
</ItemGroup> |
||||
|
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> |
||||
|
</Project> |
||||
@ -0,0 +1,33 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using Microsoft.AspNetCore.Builder; |
||||
|
using Microsoft.AspNetCore.Http; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.AspNetCore.Modularity; |
||||
|
using Volo.Abp.AspNetCore.MultiTenancy; |
||||
|
using Volo.Abp.Json; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.App |
||||
|
{ |
||||
|
[DependsOn(typeof(AbpAspNetMultiTenancyModule))] |
||||
|
public class AppModule : AbpModule |
||||
|
{ |
||||
|
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
||||
|
{ |
||||
|
var app = context.GetApplicationBuilder(); |
||||
|
|
||||
|
app.Run(async (ctx) => |
||||
|
{ |
||||
|
var manager = ctx.RequestServices.GetRequiredService<IMultiTenancyManager>(); |
||||
|
|
||||
|
var dictionary = new Dictionary<string, string> |
||||
|
{ |
||||
|
["TenantName"] = manager.CurrentTenant?.Name ?? "<host>" |
||||
|
}; |
||||
|
|
||||
|
await ctx.Response.WriteAsync(dictionary.ToJsonString()); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using System.Net; |
||||
|
using System.Net.Http; |
||||
|
using System.Threading.Tasks; |
||||
|
using Newtonsoft.Json; |
||||
|
using Newtonsoft.Json.Serialization; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.AspNetCore.TestBase; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.App |
||||
|
{ |
||||
|
public abstract class AppTestBase : AbpAspNetCoreIntegratedTestBase<Startup> |
||||
|
{ |
||||
|
protected virtual async Task<T> GetResponseAsObjectAsync<T>(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) |
||||
|
{ |
||||
|
var strResponse = await GetResponseAsStringAsync(url, expectedStatusCode); |
||||
|
return JsonConvert.DeserializeObject<T>(strResponse, new JsonSerializerSettings |
||||
|
{ |
||||
|
ContractResolver = new CamelCasePropertyNamesContractResolver() |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<string> GetResponseAsStringAsync(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) |
||||
|
{ |
||||
|
var response = await GetResponseAsync(url, expectedStatusCode); |
||||
|
return await response.Content.ReadAsStringAsync(); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<HttpResponseMessage> GetResponseAsync(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) |
||||
|
{ |
||||
|
var response = await Client.GetAsync(url); |
||||
|
response.StatusCode.ShouldBe(expectedStatusCode); |
||||
|
return response; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using Microsoft.AspNetCore.Builder; |
||||
|
using Microsoft.AspNetCore.Hosting; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.App |
||||
|
{ |
||||
|
public class Startup |
||||
|
{ |
||||
|
public void ConfigureServices(IServiceCollection services) |
||||
|
{ |
||||
|
services.AddApplication<AppModule>(); |
||||
|
} |
||||
|
|
||||
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) |
||||
|
{ |
||||
|
app.InitializeApplication(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.AspNetCore.App; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.MultiTenancy |
||||
|
{ |
||||
|
public class AspNetCoreMultiTenancy_Tests : AppTestBase |
||||
|
{ |
||||
|
private const string FakeUrl = "http://abp.io"; |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_Use_Host_If_Tenant_Is_Not_Specified() |
||||
|
{ |
||||
|
var result = await GetResponseAsObjectAsync<Dictionary<string, string>>(FakeUrl); |
||||
|
result["TenantName"].ShouldBe("<host>"); |
||||
|
} |
||||
|
|
||||
|
//TODO: Specify tenant in the header, cookie, url, querystring and so on...
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,80 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Net.Http; |
||||
|
using Microsoft.AspNetCore.Hosting; |
||||
|
using Microsoft.AspNetCore.Routing; |
||||
|
using Microsoft.AspNetCore.TestHost; |
||||
|
using Volo.ExtensionMethods; |
||||
|
using Volo.ExtensionMethods.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.TestBase |
||||
|
{ |
||||
|
public abstract class AbpAspNetCoreIntegratedTestBase<TStartup> |
||||
|
where TStartup : class |
||||
|
{ |
||||
|
protected TestServer Server { get; } |
||||
|
|
||||
|
protected HttpClient Client { get; } |
||||
|
|
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
|
protected AbpAspNetCoreIntegratedTestBase() |
||||
|
{ |
||||
|
var builder = CreateWebHostBuilder(); |
||||
|
Server = CreateTestServer(builder); |
||||
|
Client = Server.CreateClient(); |
||||
|
|
||||
|
ServiceProvider = Server.Host.Services; |
||||
|
} |
||||
|
|
||||
|
protected virtual IWebHostBuilder CreateWebHostBuilder() |
||||
|
{ |
||||
|
return new WebHostBuilder() |
||||
|
.UseStartup<TStartup>(); |
||||
|
} |
||||
|
|
||||
|
protected virtual TestServer CreateTestServer(IWebHostBuilder builder) |
||||
|
{ |
||||
|
return new TestServer(builder); |
||||
|
} |
||||
|
|
||||
|
#region GetUrl
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets default URL for given controller type.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TController">The type of the controller.</typeparam>
|
||||
|
protected virtual string GetUrl<TController>() |
||||
|
{ |
||||
|
return "/" + typeof(TController).Name.RemovePostFix("Controller", "AppService", "ApplicationService", "Service"); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets default URL for given controller type's given action.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TController">The type of the controller.</typeparam>
|
||||
|
protected virtual string GetUrl<TController>(string actionName) |
||||
|
{ |
||||
|
return GetUrl<TController>() + "/" + actionName; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets default URL for given controller type's given action with query string parameters (as anonymous object).
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TController">The type of the controller.</typeparam>
|
||||
|
protected virtual string GetUrl<TController>(string actionName, object queryStringParamsAsAnonymousObject) |
||||
|
{ |
||||
|
var url = GetUrl<TController>(actionName); |
||||
|
|
||||
|
var dictionary = new RouteValueDictionary(queryStringParamsAsAnonymousObject); |
||||
|
if (dictionary.Any()) |
||||
|
{ |
||||
|
url += "?" + dictionary.Select(d => $"{d.Key}={d.Value}").JoinAsString("&"); |
||||
|
} |
||||
|
|
||||
|
return url; |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
{ |
||||
|
"version": "1.0.0-*", |
||||
|
|
||||
|
"testRunner": "xunit", |
||||
|
|
||||
|
"dependencies": { |
||||
|
"AbpTestBase": "1.0.0-*", |
||||
|
"Volo.Abp.AspNetCore.MultiTenancy": "1.0.0-*", |
||||
|
"Microsoft.AspNetCore.TestHost": "1.1.0", |
||||
|
"Microsoft.AspNetCore.Routing.Abstractions": "1.1.0" |
||||
|
}, |
||||
|
|
||||
|
"frameworks": { |
||||
|
"netcoreapp1.1": { |
||||
|
"dependencies": { |
||||
|
"Microsoft.NETCore.App": { |
||||
|
"type": "platform", |
||||
|
"version": "1.1.0" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue