Skip to content

Commit adfca04

Browse files
authored
Merge pull request #7 from Boriszn/release/1.0.0
Release/1.0.0
2 parents 2d3619e + a802281 commit adfca04

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1815
-2
lines changed

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/.vs/DeviceManagerApi/v15/.suo
2+
src/DeviceManagerApi/bin/
3+
src/DeviceManagerApi/obj/
4+
/.vs/config/applicationhost.config
5+
src/DeviceManager.Api/bin/
6+
src/DeviceManager.Api/obj/
7+
test/DeviceManager.Api.UnitTests/bin/
8+
test/DeviceManager.Api.UnitTests/obj/
9+
.vs/

DeviceManagerApi.sln

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.26430.14
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeviceManager.Api", "src\DeviceManager.Api\DeviceManager.Api.csproj", "{3580C09D-2A45-4898-BDEB-1207E06DD9D0}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceManager.Api.UnitTests", "test\DeviceManager.Api.UnitTests\DeviceManager.Api.UnitTests.csproj", "{006A6BEB-0CAD-40C9-8643-CACD71DA32EF}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Release|Any CPU = Release|Any CPU
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{3580C09D-2A45-4898-BDEB-1207E06DD9D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17+
{3580C09D-2A45-4898-BDEB-1207E06DD9D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{3580C09D-2A45-4898-BDEB-1207E06DD9D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
19+
{3580C09D-2A45-4898-BDEB-1207E06DD9D0}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{006A6BEB-0CAD-40C9-8643-CACD71DA32EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{006A6BEB-0CAD-40C9-8643-CACD71DA32EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{006A6BEB-0CAD-40C9-8643-CACD71DA32EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{006A6BEB-0CAD-40C9-8643-CACD71DA32EF}.Release|Any CPU.Build.0 = Release|Any CPU
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
EndGlobal

README.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,29 @@
1-
# DeviceManager.Api
2-
Web API Solution demonstrates mutliteant architecture, using Entity Framework, UnityOfWork, Repository patterns
1+
# DeviceManager.Api [![Build status](https://ci.appveyor.com/api/projects/status/x1whwie6v68l8200?svg=true)](https://ci.appveyor.com/project/Boriszn/devicemanager-api)
2+
3+
Web API Solution demonstrates mutliteantcy architecture, using Entity Framework, UnitOfWork, Repository patterns
4+
5+
## Installation
6+
7+
1. Clone repository
8+
2. Apply Entity Framework migration. Run: `Update-DataBase`.
9+
* (For Multitenancy testing) Change `DefaultConnection` to `;Database=DeviceDb-ten2;` in `appsettings.json`. Run EF migration `Update-DataBase`. It will create another database.
10+
* **Tenants Dabase configuration stored in [DataBaseManager](src/DeviceManager.Api/Data/Management/DataBaseManager.cs) (`tenantConfigurationDictionary`)**.
11+
3. Fill up valid database connection string configuration option in `appsettings.json`.
12+
4. Run UnitTests.
13+
5. Build / Run.
14+
15+
## Contributing
16+
17+
1. Fork it!
18+
2. Create your feature branch: `git checkout -b my-new-feature`
19+
3. Commit your changes: `git commit -am 'Add some feature'`
20+
4. Push to the branch: `git push origin my-new-feature`
21+
5. Submit a pull request
22+
23+
## History
24+
25+
All changes can be easily found in [RELEASENOTES](ReleaseNotes.md)
26+
27+
## License
28+
29+
This project is licensed under the MIT License

ReleaseNotes.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Change Log
2+
3+
All notable changes to this project will be documented in this file.
4+
The format is based on [Keep a Changelog](http://keepachangelog.com/)
5+
6+
## 1.0.0 - 11.02.2018
7+
8+
### Added
9+
10+
- [RD-2] Add multi-tenancy feature
11+
- [DM-1] Created base project structure (inc Web api, UoW+Repository); Add libraries and update references
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System.Collections.Generic;
2+
using Swashbuckle.AspNetCore.Swagger;
3+
using Swashbuckle.AspNetCore.SwaggerGen;
4+
5+
namespace DeviceManager.Api.ActionFilters
6+
{
7+
/// <summary>
8+
/// Adds Tenant Id field to API endpoints
9+
/// </summary>
10+
/// <seealso cref="Swashbuckle.AspNetCore.SwaggerGen.IOperationFilter" />
11+
public class TenantHeaderOperationFilter : IOperationFilter
12+
{
13+
/// <summary>
14+
/// Applies the specified operation.
15+
/// </summary>
16+
/// <param name="operation">The operation.</param>
17+
/// <param name="context">The context.</param>
18+
public void Apply(Operation operation, OperationFilterContext context)
19+
{
20+
if (operation.Parameters == null)
21+
{
22+
operation.Parameters = new List<IParameter>();
23+
}
24+
25+
operation.Parameters.Add(new NonBodyParameter
26+
{
27+
28+
Name = "tenantid",
29+
In = "header",
30+
Description = "tenantid",
31+
Required = true,
32+
Type = "string",
33+
});
34+
35+
}
36+
}
37+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using System.Reflection;
4+
using Microsoft.AspNetCore.Mvc.Controllers;
5+
using Microsoft.AspNetCore.Mvc.Filters;
6+
7+
namespace DeviceManager.Api.ActionFilters
8+
{
9+
/// <inheritdoc />
10+
public class ValidateActionParametersAttribute : ActionFilterAttribute
11+
{
12+
private const string RequiredAttributeKey = "RequiredAttribute";
13+
14+
/// <inheritdoc />
15+
public override void OnActionExecuting(ActionExecutingContext context)
16+
{
17+
var descriptor = context.ActionDescriptor as ControllerActionDescriptor;
18+
19+
if (descriptor != null)
20+
{
21+
var parameters = descriptor.MethodInfo.GetParameters();
22+
23+
CheckParameterRequired(context, parameters);
24+
}
25+
26+
base.OnActionExecuting(context);
27+
}
28+
29+
private static void CheckParameterRequired(ActionExecutingContext context, IEnumerable<ParameterInfo> parameters)
30+
{
31+
foreach (var parameter in parameters)
32+
{
33+
if (parameter.CustomAttributes.Any() && parameter.CustomAttributes.Select(item => item.AttributeType
34+
.ToString()
35+
.Contains(RequiredAttributeKey)).Any())
36+
{
37+
if (!context.ActionArguments.Keys.Contains(parameter.Name))
38+
{
39+
context.ModelState.AddModelError(parameter.Name, $"Parameter {parameter.Name} is required");
40+
}
41+
}
42+
}
43+
}
44+
}
45+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using DeviceManager.Api.Configuration.Settings;
2+
using Microsoft.Extensions.Configuration;
3+
using Microsoft.Extensions.DependencyInjection;
4+
5+
namespace DeviceManager.Api.Configuration
6+
{
7+
public static class ConfigurationOptions
8+
{
9+
/// <summary>
10+
/// Configures the service.
11+
/// </summary>
12+
/// <param name="services">The services.</param>
13+
/// <param name="configuration">The configuration.</param>
14+
public static void ConfigureService(IServiceCollection services, IConfigurationRoot configuration)
15+
{
16+
services.Configure<ConnectionSettings>(configuration.GetSection("ConnectionStrings"));
17+
}
18+
}
19+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using DeviceManager.Api.Data;
2+
using Microsoft.EntityFrameworkCore;
3+
using Microsoft.Extensions.Configuration;
4+
using Microsoft.Extensions.DependencyInjection;
5+
6+
namespace DeviceManager.Api.Configuration
7+
{
8+
public static class EntityFrameworkConfiguration
9+
{
10+
/// <summary>
11+
/// Configures the service.
12+
/// </summary>
13+
/// <param name="services">The services.</param>
14+
/// <param name="configuration">The configuration.</param>
15+
public static void ConfigureService(IServiceCollection services, IConfigurationRoot configuration)
16+
{
17+
string connectionString = configuration.GetConnectionString("DefaultConnection");
18+
19+
// Entity framework configuration
20+
services.AddDbContext<DeviceContext>(options =>
21+
options.UseSqlServer(connectionString));
22+
23+
services.AddScoped<IDbContext, DeviceContext>();
24+
}
25+
}
26+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using DeviceManager.Api.Data.Management;
2+
using DeviceManager.Api.Services;
3+
using Microsoft.AspNetCore.Http;
4+
using Microsoft.Extensions.Configuration;
5+
using Microsoft.Extensions.DependencyInjection;
6+
7+
namespace DeviceManager.Api.Configuration
8+
{
9+
/// <summary>
10+
/// IOC contaner start-up configuration
11+
/// </summary>
12+
public static class IocContainerConfiguration
13+
{
14+
/// <summary>
15+
/// Configures the service.
16+
/// </summary>
17+
/// <param name="services">The services.</param>
18+
/// <param name="configuration">The configuration.</param>
19+
public static void ConfigureService(IServiceCollection services, IConfigurationRoot configuration)
20+
{
21+
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
22+
23+
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
24+
25+
services.AddTransient<IDeviceService, DeviceService>();
26+
27+
services.AddTransient<IDataBaseManager, DataBaseManager>();
28+
services.AddTransient<IContextFactory, ContextFactory>();
29+
30+
services.AddTransient<IUnitOfWork, UnitOfWork>();
31+
}
32+
}
33+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace DeviceManager.Api.Configuration.Settings
2+
{
3+
/// <summary>
4+
/// Connection configuration options
5+
/// </summary>
6+
public class ConnectionSettings
7+
{
8+
/// <summary>
9+
/// Gets or sets the default connection.
10+
/// </summary>
11+
/// <value>
12+
/// The default connection.
13+
/// </value>
14+
public string DefaultConnection { get; set; }
15+
}
16+
}

0 commit comments

Comments
 (0)