diff --git a/TechTest/AddCustomers.sql b/TechTest/AddCustomers.sql
new file mode 100644
index 0000000..8aae7ae
--- /dev/null
+++ b/TechTest/AddCustomers.sql
@@ -0,0 +1,17 @@
+USE [Customers]
+GO
+
+-- The initial customer table
+IF (NOT EXISTS (SELECT *
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA = 'dbo'
+ AND TABLE_NAME = 'Customer'))
+BEGIN
+ CREATE TABLE [dbo].[Customer]
+ (
+ [CustomerId] INT NOT NULL PRIMARY KEY IDENTITY(1,1),
+ [Name] NVARCHAR(100) NOT NULL,
+ [Country] VARCHAR(2) NOT NULL,
+ [DateOfBirth] DATETIME NOT NULL
+ )
+END
\ No newline at end of file
diff --git a/TechTest/AddOrders.sql b/TechTest/AddOrders.sql
new file mode 100644
index 0000000..3c75b18
--- /dev/null
+++ b/TechTest/AddOrders.sql
@@ -0,0 +1,25 @@
+USE [Orders]
+GO
+
+-- base table
+IF (NOT EXISTS (SELECT *
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA = 'dbo'
+ AND TABLE_NAME = 'Orders'))
+BEGIN
+ CREATE TABLE [dbo].[Orders]
+ (
+ [OrderId] INT NOT NULL PRIMARY KEY,
+ [Amount] DECIMAL(10, 2) NOT NULL,
+ [VAT] DECIMAL(10, 2) NOT NULL
+ )
+END
+
+-- first migration
+IF NOT EXISTS(SELECT 1 FROM sys.columns
+ WHERE Name = N'CustomerId'
+ AND Object_ID = Object_ID(N'dbo.Orders'))
+BEGIN
+ ALTER TABLE dbo.Orders
+ ADD CustomerId INT NOT NULL DEFAULT 0;
+END
\ No newline at end of file
diff --git a/TechTest/AnyCompany.Data.Contract/AnyCompany.Data.Contract.csproj b/TechTest/AnyCompany.Data.Contract/AnyCompany.Data.Contract.csproj
new file mode 100644
index 0000000..88f0629
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Contract/AnyCompany.Data.Contract.csproj
@@ -0,0 +1,55 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {7F4D6121-26EF-48A2-A2F4-BBD5D114D8E7}
+ Library
+ Properties
+ AnyCompany.Data.Contract
+ AnyCompany.Data.Contract
+ v4.6.1
+ 512
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {695D4D06-2336-4B91-BA68-4A4924CF4729}
+ AnyCompany.Models
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany.Data.Contract/Properties/AssemblyInfo.cs b/TechTest/AnyCompany.Data.Contract/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..326c08d
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Contract/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+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: AssemblyTitle("AnyCompany.Data.Contract")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AnyCompany.Data.Contract")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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("7f4d6121-26ef-48a2-a2f4-bbd5d114d8e7")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/TechTest/AnyCompany.Data.Contract/Repositories/ICustomerRepository.cs b/TechTest/AnyCompany.Data.Contract/Repositories/ICustomerRepository.cs
new file mode 100644
index 0000000..433c46f
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Contract/Repositories/ICustomerRepository.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+using AnyCompany.Models;
+
+namespace AnyCompany.Data.Contract.Repositories
+{
+ public interface ICustomerRepository
+ {
+ Customer Load(int customerId);
+ IEnumerable GetList();
+ }
+}
diff --git a/TechTest/AnyCompany.Data.Contract/Repositories/IOrderRepository.cs b/TechTest/AnyCompany.Data.Contract/Repositories/IOrderRepository.cs
new file mode 100644
index 0000000..6bcb6a5
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Contract/Repositories/IOrderRepository.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+using AnyCompany.Models;
+
+namespace AnyCompany.Data.Contract.Repositories
+{
+ public interface IOrderRepository
+ {
+ void Add(Order order);
+ IEnumerable GetList();
+ }
+}
diff --git a/TechTest/AnyCompany.Data.Dapper/AnyCompany.Data.Dapper.csproj b/TechTest/AnyCompany.Data.Dapper/AnyCompany.Data.Dapper.csproj
new file mode 100644
index 0000000..1a615fe
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Dapper/AnyCompany.Data.Dapper.csproj
@@ -0,0 +1,81 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {CEF90CEA-CEDF-44B4-9203-9B9ADF9A15CE}
+ Library
+ Properties
+ AnyCompany.Data.Dapper
+ AnyCompany.Data.Dapper
+ v4.6.1
+ 512
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\Dapper.1.60.6\lib\net451\Dapper.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ SqlStatements.resx
+
+
+
+
+ {7F4D6121-26EF-48A2-A2F4-BBD5D114D8E7}
+ AnyCompany.Data.Contract
+
+
+ {695D4D06-2336-4B91-BA68-4A4924CF4729}
+ AnyCompany.Models
+
+
+
+
+
+
+
+ ResXFileCodeGenerator
+ SqlStatements.Designer.cs
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany.Data.Dapper/Enums/ConnectionType.cs b/TechTest/AnyCompany.Data.Dapper/Enums/ConnectionType.cs
new file mode 100644
index 0000000..339f0fb
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Dapper/Enums/ConnectionType.cs
@@ -0,0 +1,8 @@
+namespace AnyCompany.Data.Dapper.Enums
+{
+ public enum ConnectionType
+ {
+ CustomerDb = 0,
+ OrderDb = 1
+ }
+}
diff --git a/TechTest/AnyCompany.Data.Dapper/Factories/ConnectionFactory.cs b/TechTest/AnyCompany.Data.Dapper/Factories/ConnectionFactory.cs
new file mode 100644
index 0000000..b03d61d
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Dapper/Factories/ConnectionFactory.cs
@@ -0,0 +1,27 @@
+using System.Data;
+using System.Data.SqlClient;
+using AnyCompany.Data.Dapper.Enums;
+
+namespace AnyCompany.Data.Dapper.Factories
+{
+ public class ConnectionFactory : IConnectionFactory
+ {
+ private readonly string _customerConnectionString;
+ private readonly string _orderDbConnectionString;
+
+ public ConnectionFactory(string customerConnectionString, string orderDbConnectionString)
+ {
+ _customerConnectionString = customerConnectionString;
+ _orderDbConnectionString = orderDbConnectionString;
+ }
+
+ public IDbConnection Create(ConnectionType connectionType)
+ {
+ var connectionString = connectionType == ConnectionType.CustomerDb
+ ? _customerConnectionString
+ : _orderDbConnectionString;
+
+ return new SqlConnection(connectionString);
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Data.Dapper/Factories/IConnectionFactory.cs b/TechTest/AnyCompany.Data.Dapper/Factories/IConnectionFactory.cs
new file mode 100644
index 0000000..ee5e551
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Dapper/Factories/IConnectionFactory.cs
@@ -0,0 +1,10 @@
+using System.Data;
+using AnyCompany.Data.Dapper.Enums;
+
+namespace AnyCompany.Data.Dapper.Factories
+{
+ public interface IConnectionFactory
+ {
+ IDbConnection Create(ConnectionType connectionType);
+ }
+}
diff --git a/TechTest/AnyCompany.Data.Dapper/Properties/AssemblyInfo.cs b/TechTest/AnyCompany.Data.Dapper/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..032cea6
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Dapper/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+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: AssemblyTitle("AnyCompany.Data.Dapper")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AnyCompany.Data.Dapper")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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("cef90cea-cedf-44b4-9203-9b9adf9a15ce")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/TechTest/AnyCompany.Data.Dapper/Repositories/CustomerRepository.cs b/TechTest/AnyCompany.Data.Dapper/Repositories/CustomerRepository.cs
new file mode 100644
index 0000000..3fb998d
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Dapper/Repositories/CustomerRepository.cs
@@ -0,0 +1,23 @@
+using System.Configuration;
+using System.Data.SqlClient;
+using System.Linq;
+using AnyCompany.Data.Dapper.Sql;
+using AnyCompany.Models;
+using Dapper;
+
+namespace AnyCompany.Data.Dapper.Repositories
+{
+ public static class CustomerRepository
+ {
+ public static Customer Load(int customerId)
+ {
+ var connectionString = ConfigurationManager.ConnectionStrings["CustomerConnectionString"].ConnectionString;
+ using (var connection = new SqlConnection(connectionString))
+ {
+ connection.Open();
+ return connection.Query(SqlStatements.LoadCustomerById,
+ new {CustomerId = customerId}).FirstOrDefault();
+ }
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Data.Dapper/Repositories/CustomerRepositoryWrapper.cs b/TechTest/AnyCompany.Data.Dapper/Repositories/CustomerRepositoryWrapper.cs
new file mode 100644
index 0000000..e42be70
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Dapper/Repositories/CustomerRepositoryWrapper.cs
@@ -0,0 +1,37 @@
+using System.Collections.Generic;
+using System.Linq;
+using AnyCompany.Data.Contract.Repositories;
+using AnyCompany.Data.Dapper.Enums;
+using AnyCompany.Data.Dapper.Factories;
+using AnyCompany.Data.Dapper.Sql;
+using AnyCompany.Models;
+using Dapper;
+
+namespace AnyCompany.Data.Dapper.Repositories
+{
+ public class CustomerRepositoryWrapper : ICustomerRepository
+ {
+ private readonly IConnectionFactory _connectionFactory;
+
+ public CustomerRepositoryWrapper(IConnectionFactory connectionFactory)
+ {
+ _connectionFactory = connectionFactory;
+ }
+
+ // using this to act as a proxy to the static CustomerRepository - I assumed this was legacy that
+ // we're trying to abstract and eventually replace
+ public Customer Load(int customerId)
+ {
+ return CustomerRepository.Load(customerId);
+ }
+
+ public IEnumerable GetList()
+ {
+ using (var connection = _connectionFactory.Create(ConnectionType.CustomerDb))
+ {
+ connection.Open();
+ return connection.Query(SqlStatements.GetAllCustomers).ToList();
+ }
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Data.Dapper/Repositories/OrderRepository.cs b/TechTest/AnyCompany.Data.Dapper/Repositories/OrderRepository.cs
new file mode 100644
index 0000000..3320c23
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Dapper/Repositories/OrderRepository.cs
@@ -0,0 +1,52 @@
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using AnyCompany.Data.Contract.Repositories;
+using AnyCompany.Data.Dapper.Enums;
+using AnyCompany.Data.Dapper.Factories;
+using AnyCompany.Data.Dapper.Sql;
+using AnyCompany.Models;
+using Dapper;
+
+namespace AnyCompany.Data.Dapper.Repositories
+{
+ public class OrderRepository : IOrderRepository
+ {
+ private readonly IConnectionFactory _connectionFactory;
+
+ public OrderRepository(IConnectionFactory connectionFactory)
+ {
+ _connectionFactory = connectionFactory;
+ }
+
+ public void Add(Order order)
+ {
+ using (var connection = CreateConnection())
+ {
+ connection.Open();
+ connection.Execute(SqlStatements.InsertOrder,
+ new
+ {
+ OrderId = order.OrderId,
+ Amount = order.Amount,
+ VAT = order.VAT,
+ CustomerId = order.CustomerId
+ });
+ }
+ }
+
+ public IEnumerable GetList()
+ {
+ using (var connection = CreateConnection())
+ {
+ connection.Open();
+ return connection.Query(SqlStatements.GetAllOrders).ToList();
+ }
+ }
+
+ private IDbConnection CreateConnection()
+ {
+ return _connectionFactory.Create(ConnectionType.OrderDb);
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Data.Dapper/Sql/SqlStatements.Designer.cs b/TechTest/AnyCompany.Data.Dapper/Sql/SqlStatements.Designer.cs
new file mode 100644
index 0000000..a085ca9
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Dapper/Sql/SqlStatements.Designer.cs
@@ -0,0 +1,99 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace AnyCompany.Data.Dapper.Sql {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class SqlStatements {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal SqlStatements() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AnyCompany.Data.Dapper.Sql.SqlStatements", typeof(SqlStatements).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to SELECT CustomerId, Country, DateOfBirth, Name from dbo.Customer.
+ ///
+ internal static string GetAllCustomers {
+ get {
+ return ResourceManager.GetString("GetAllCustomers", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to SELECT OrderId, Amount, VAT, CustomerId from dbo.Orders.
+ ///
+ internal static string GetAllOrders {
+ get {
+ return ResourceManager.GetString("GetAllOrders", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to INSERT INTO Orders VALUES (@OrderId, @Amount, @VAT, @CustomerId).
+ ///
+ internal static string InsertOrder {
+ get {
+ return ResourceManager.GetString("InsertOrder", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to SELECT * FROM Customer WHERE CustomerId = @CustomerId.
+ ///
+ internal static string LoadCustomerById {
+ get {
+ return ResourceManager.GetString("LoadCustomerById", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Data.Dapper/Sql/SqlStatements.resx b/TechTest/AnyCompany.Data.Dapper/Sql/SqlStatements.resx
new file mode 100644
index 0000000..8f6fc44
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Dapper/Sql/SqlStatements.resx
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ SELECT CustomerId, Country, DateOfBirth, Name from dbo.Customer
+
+
+ SELECT OrderId, Amount, VAT, CustomerId from dbo.Orders
+
+
+ INSERT INTO Orders VALUES (@OrderId, @Amount, @VAT, @CustomerId)
+
+
+ SELECT * FROM Customer WHERE CustomerId = @CustomerId
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany.Data.Dapper/packages.config b/TechTest/AnyCompany.Data.Dapper/packages.config
new file mode 100644
index 0000000..b6f2e13
--- /dev/null
+++ b/TechTest/AnyCompany.Data.Dapper/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany.IntegrationTests/AnyCompany.IntegrationTests.csproj b/TechTest/AnyCompany.IntegrationTests/AnyCompany.IntegrationTests.csproj
new file mode 100644
index 0000000..5670f60
--- /dev/null
+++ b/TechTest/AnyCompany.IntegrationTests/AnyCompany.IntegrationTests.csproj
@@ -0,0 +1,109 @@
+
+
+
+
+
+ Debug
+ AnyCPU
+ {DF80D016-3AFE-43B3-BC8F-3CEC313B4C91}
+ Library
+ Properties
+ AnyCompany.IntegrationTests
+ AnyCompany.IntegrationTests
+ v4.6.1
+ 512
+ true
+
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll
+
+
+ ..\packages\Castle.Windsor.5.0.0\lib\net45\Castle.Windsor.dll
+
+
+ ..\packages\Dapper.1.60.6\lib\net451\Dapper.dll
+
+
+ ..\packages\Dapper.Extension.1.0.0.1\lib\net45\Dapper.Extension.dll
+
+
+ ..\packages\DapperExtensions.1.6.3\lib\net45\DapperExtensions.dll
+
+
+ ..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {7F4D6121-26EF-48A2-A2F4-BBD5D114D8E7}
+ AnyCompany.Data.Contract
+
+
+ {CEF90CEA-CEDF-44B4-9203-9B9ADF9A15CE}
+ AnyCompany.Data.Dapper
+
+
+ {BE9D1186-D67F-4BA0-9A94-CE529CC1FEFA}
+ AnyCompany.Ioc
+
+
+ {695D4D06-2336-4B91-BA68-4A4924CF4729}
+ AnyCompany.Models
+
+
+ {c7e15594-7d8f-4c18-9dd7-14f3fbb1572d}
+ AnyCompany.Services
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany.IntegrationTests/App.config b/TechTest/AnyCompany.IntegrationTests/App.config
new file mode 100644
index 0000000..a9be8d4
--- /dev/null
+++ b/TechTest/AnyCompany.IntegrationTests/App.config
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany.IntegrationTests/CustomerServiceIntegrationTests.cs b/TechTest/AnyCompany.IntegrationTests/CustomerServiceIntegrationTests.cs
new file mode 100644
index 0000000..8206a2c
--- /dev/null
+++ b/TechTest/AnyCompany.IntegrationTests/CustomerServiceIntegrationTests.cs
@@ -0,0 +1,71 @@
+
+using System;
+using System.Linq;
+using AnyCompany.IntegrationTests.DataHelpers;
+using AnyCompany.Ioc;
+using AnyCompany.Models;
+using AnyCompany.Services.Services;
+using Castle.Windsor;
+using NUnit.Framework;
+
+namespace AnyCompany.IntegrationTests
+{
+ [TestFixture]
+ public class CustomerServiceIntegrationTests
+ {
+ private IWindsorContainer _container;
+
+ [SetUp]
+ public void SetupFixture()
+ {
+ _container = Bootstrapper.GetContainer();
+ }
+
+ [Test]
+ public void GetAllCustomersWithOrders_ShouldReturnCustomersAndOrders()
+ {
+ // Arrange.
+ var customerOne = CustomerDataHelper.Add(GetCustomer("UK"));
+ var orderOne = OrderDataHelper.AddOrder(GetOrder(customerOne.CustomerId));
+ var orderTwo = OrderDataHelper.AddOrder(GetOrder(customerOne.CustomerId));
+
+ var customerTwo = CustomerDataHelper.Add(GetCustomer("FR"));
+ var orderThree = OrderDataHelper.AddOrder(GetOrder(customerTwo.CustomerId));
+
+ var customerOrderService = _container.Resolve();
+
+ // Act.
+ var results = customerOrderService.GetAllCustomerWithOrders();
+ var customerOneResult = results.First(c => c.Customer.CustomerId == customerOne.CustomerId);
+ var customerTwoResult = results.First(c => c.Customer.CustomerId == customerTwo.CustomerId);
+
+ // Assert.
+ Assert.AreEqual(2, customerOneResult.Orders.Count());
+ Assert.AreEqual(1, customerTwoResult.Orders.Count());
+ Assert.IsTrue(customerOneResult.Orders.Any(o => o.OrderId == orderOne.OrderId));
+ Assert.IsTrue(customerOneResult.Orders.Any(o => o.OrderId == orderTwo.OrderId));
+ Assert.IsTrue(customerTwoResult.Orders.Any(o => o.OrderId == orderThree.OrderId));
+ }
+
+ private Order GetOrder(int customerId)
+ {
+ return new Order
+ {
+ OrderId = new Random().Next(1, 200000000),
+ Amount = 100,
+ CustomerId = customerId,
+ VAT = 0
+ };
+ }
+
+ private Customer GetCustomer(string country)
+ {
+ return new Customer
+ {
+ Country = country,
+ DateOfBirth = DateTime.UtcNow.AddDays(-20),
+ Name = "John Smith"
+ };
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.IntegrationTests/DataHelpers/CustomerDataHelper.cs b/TechTest/AnyCompany.IntegrationTests/DataHelpers/CustomerDataHelper.cs
new file mode 100644
index 0000000..1be92a3
--- /dev/null
+++ b/TechTest/AnyCompany.IntegrationTests/DataHelpers/CustomerDataHelper.cs
@@ -0,0 +1,27 @@
+using System.Configuration;
+using System.Data.SqlClient;
+using AnyCompany.Models;
+using DapperExtensions;
+
+namespace AnyCompany.IntegrationTests.DataHelpers
+{
+ public static class CustomerDataHelper
+ {
+ public static Customer Add(Customer customer)
+ {
+ using (var connection = new SqlConnection(GetConnectionString()))
+ {
+ connection.Open();
+ int id = connection.Insert(customer);
+
+ customer.CustomerId = id;
+ return customer;
+ }
+ }
+
+ private static string GetConnectionString()
+ {
+ return ConfigurationManager.ConnectionStrings["CustomerConnectionString"].ConnectionString;
+ }
+ }
+}
\ No newline at end of file
diff --git a/TechTest/AnyCompany.IntegrationTests/DataHelpers/OrderDataHelper.cs b/TechTest/AnyCompany.IntegrationTests/DataHelpers/OrderDataHelper.cs
new file mode 100644
index 0000000..a1bd397
--- /dev/null
+++ b/TechTest/AnyCompany.IntegrationTests/DataHelpers/OrderDataHelper.cs
@@ -0,0 +1,46 @@
+using System.Configuration;
+using System.Data.Odbc;
+using System.Data.SqlClient;
+using System.Linq;
+using AnyCompany.Models;
+using Dapper;
+
+namespace AnyCompany.IntegrationTests.DataHelpers
+{
+ public static class OrderDataHelper
+ {
+ public static Order GetOrder(int id)
+ {
+ using (var connection = new SqlConnection(GetConnectionString()))
+ {
+ connection.Open();
+ return connection.Query(
+ "SELECT * FROM dbo.Orders WHERE OrderId = @OrderId",
+ new { OrderId = id }).First();
+ }
+ }
+
+ public static Order AddOrder(Order order)
+ {
+ using (var connection = new SqlConnection(GetConnectionString()))
+ {
+ connection.Open();
+ connection.Query(@"INSERT INTO Orders VALUES (@OrderId, @Amount, @VAT, @CustomerId)",
+ new
+ {
+ OrderId = order.OrderId,
+ Amount = order.Amount,
+ VAT = order.VAT,
+ CustomerId = order.CustomerId
+ });
+
+ return order;
+ }
+ }
+
+ private static string GetConnectionString()
+ {
+ return ConfigurationManager.ConnectionStrings["OrderConnectionString"].ConnectionString;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.IntegrationTests/OrderServiceIntegrationTests.cs b/TechTest/AnyCompany.IntegrationTests/OrderServiceIntegrationTests.cs
new file mode 100644
index 0000000..307db03
--- /dev/null
+++ b/TechTest/AnyCompany.IntegrationTests/OrderServiceIntegrationTests.cs
@@ -0,0 +1,65 @@
+using System;
+using AnyCompany.IntegrationTests.DataHelpers;
+using AnyCompany.Ioc;
+using AnyCompany.Models;
+using AnyCompany.Services.Constants;
+using AnyCompany.Services.Dtos;
+using AnyCompany.Services.Services;
+using Castle.Windsor;
+using NUnit.Framework;
+
+namespace AnyCompany.IntegrationTests
+{
+ [TestFixture]
+ public class OrderServiceIntegrationTests
+ {
+ private IWindsorContainer _container;
+
+ [SetUp]
+ public void SetupFixture()
+ {
+ _container = Bootstrapper.GetContainer();
+ }
+
+ [TestCase("UK", VatConstants.UkVat)]
+ [TestCase("FR", VatConstants.RowVat)]
+ public void PlaceOrder_ShouldInsertAnOrder_AndReturnTrue(string country, double expectedVat)
+ {
+ // Arrange.
+ var customer = CustomerDataHelper.Add(GetCustomer(country));
+ var order = GetOrderDto();
+ var orderService = _container.Resolve();
+
+ // Act.
+ var result = orderService.PlaceOrder(order, customer.CustomerId);
+ var insertedOrder = OrderDataHelper.GetOrder(order.OrderId);
+
+ // Assert.
+ Assert.IsTrue(result);
+ Assert.IsNotNull(insertedOrder);
+ Assert.AreEqual(customer.CustomerId, insertedOrder.CustomerId);
+ Assert.AreEqual(order.OrderId, insertedOrder.OrderId);
+ Assert.AreEqual(order.Amount, insertedOrder.Amount);
+ Assert.AreEqual(expectedVat, insertedOrder.VAT);
+ }
+
+ private OrderDto GetOrderDto()
+ {
+ return new OrderDto
+ {
+ OrderId = new Random().Next(1, 200000000), // generate a random Id since the OrderId column is not an IDENTITY column
+ Amount = 200.99d
+ };
+ }
+
+ private Customer GetCustomer(string country)
+ {
+ return new Customer
+ {
+ Country = country,
+ DateOfBirth = DateTime.UtcNow.AddYears(-41),
+ Name = "John Smith"
+ };
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.IntegrationTests/Properties/AssemblyInfo.cs b/TechTest/AnyCompany.IntegrationTests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..98f6cd7
--- /dev/null
+++ b/TechTest/AnyCompany.IntegrationTests/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+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: AssemblyTitle("AnyCompany.IntegrationTests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AnyCompany.IntegrationTests")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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("df80d016-3afe-43b3-bc8f-3cec313b4c91")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/TechTest/AnyCompany.IntegrationTests/packages.config b/TechTest/AnyCompany.IntegrationTests/packages.config
new file mode 100644
index 0000000..9a9ebea
--- /dev/null
+++ b/TechTest/AnyCompany.IntegrationTests/packages.config
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany.Ioc/AnyCompany.Ioc.csproj b/TechTest/AnyCompany.Ioc/AnyCompany.Ioc.csproj
new file mode 100644
index 0000000..3808873
--- /dev/null
+++ b/TechTest/AnyCompany.Ioc/AnyCompany.Ioc.csproj
@@ -0,0 +1,75 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {BE9D1186-D67F-4BA0-9A94-CE529CC1FEFA}
+ Library
+ Properties
+ AnyCompany.Ioc
+ AnyCompany.Ioc
+ v4.6.1
+ 512
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll
+
+
+ ..\packages\Castle.Windsor.5.0.0\lib\net45\Castle.Windsor.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {7F4D6121-26EF-48A2-A2F4-BBD5D114D8E7}
+ AnyCompany.Data.Contract
+
+
+ {CEF90CEA-CEDF-44B4-9203-9B9ADF9A15CE}
+ AnyCompany.Data.Dapper
+
+
+ {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}
+ AnyCompany.Services
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany.Ioc/Bootstrapper.cs b/TechTest/AnyCompany.Ioc/Bootstrapper.cs
new file mode 100644
index 0000000..4e1f915
--- /dev/null
+++ b/TechTest/AnyCompany.Ioc/Bootstrapper.cs
@@ -0,0 +1,29 @@
+using Castle.Windsor;
+
+namespace AnyCompany.Ioc
+{
+ public static class Bootstrapper
+ {
+ private static object _objLock = new object();
+
+ private static WindsorContainer _container;
+
+ public static WindsorContainer GetContainer()
+ {
+ if (_container != null)
+ return _container;
+
+ lock (_objLock)
+ {
+ if (_container != null)
+ return _container;
+
+ var container = new WindsorContainer();
+ container.Install(new DependencyInstaller());
+
+ _container = container;
+ return _container;
+ }
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Ioc/Container.cs b/TechTest/AnyCompany.Ioc/Container.cs
new file mode 100644
index 0000000..251ebc7
--- /dev/null
+++ b/TechTest/AnyCompany.Ioc/Container.cs
@@ -0,0 +1,29 @@
+using Castle.Windsor;
+
+namespace AnyCompany.Ioc
+{
+ public static class Container
+ {
+ private static object _objLock = new object();
+
+ private static WindsorContainer _container;
+
+ public static WindsorContainer GetContainer()
+ {
+ if (_container != null)
+ return _container;
+
+ lock (_objLock)
+ {
+ if (_container != null)
+ return _container;
+
+ var container = new WindsorContainer();
+ container.Install(new DependencyInstaller());
+
+ _container = container;
+ return _container;
+ }
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Ioc/DependencyInstaller.cs b/TechTest/AnyCompany.Ioc/DependencyInstaller.cs
new file mode 100644
index 0000000..f474f33
--- /dev/null
+++ b/TechTest/AnyCompany.Ioc/DependencyInstaller.cs
@@ -0,0 +1,40 @@
+using System.Configuration;
+using AnyCompany.Data.Contract.Repositories;
+using AnyCompany.Data.Dapper.Factories;
+using AnyCompany.Data.Dapper.Repositories;
+using AnyCompany.Services.Services;
+using Castle.MicroKernel;
+using Castle.MicroKernel.Registration;
+using Castle.MicroKernel.SubSystems.Configuration;
+using Castle.Windsor;
+
+namespace AnyCompany.Ioc
+{
+ public class DependencyInstaller : IWindsorInstaller
+ {
+ public void Install(IWindsorContainer container, IConfigurationStore store)
+ {
+ container.Register(
+ Component.For());
+
+ container.Register(
+ Component.For());
+
+ container.Register(
+ Component.For());
+
+ container.Register(
+ Component.For());
+
+ container.Register(
+ Component.For().UsingFactoryMethod(CreateConnectionFactory));
+ }
+
+ private IConnectionFactory CreateConnectionFactory(IKernel kernel)
+ {
+ return new ConnectionFactory(
+ ConfigurationManager.ConnectionStrings["CustomerConnectionString"].ConnectionString,
+ ConfigurationManager.ConnectionStrings["OrderConnectionString"].ConnectionString);
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Ioc/Properties/AssemblyInfo.cs b/TechTest/AnyCompany.Ioc/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..133d763
--- /dev/null
+++ b/TechTest/AnyCompany.Ioc/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+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: AssemblyTitle("AnyCompany.Ioc")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AnyCompany.Ioc")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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("be9d1186-d67f-4ba0-9a94-ce529cc1fefa")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/TechTest/AnyCompany.Ioc/packages.config b/TechTest/AnyCompany.Ioc/packages.config
new file mode 100644
index 0000000..927252c
--- /dev/null
+++ b/TechTest/AnyCompany.Ioc/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany/AnyCompany.csproj b/TechTest/AnyCompany.Models/AnyCompany.Models.csproj
similarity index 87%
rename from TechTest/AnyCompany/AnyCompany.csproj
rename to TechTest/AnyCompany.Models/AnyCompany.Models.csproj
index 5b0498d..49e3a75 100644
--- a/TechTest/AnyCompany/AnyCompany.csproj
+++ b/TechTest/AnyCompany.Models/AnyCompany.Models.csproj
@@ -4,13 +4,14 @@
Debug
AnyCPU
- {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}
+ {695D4D06-2336-4B91-BA68-4A4924CF4729}
Library
Properties
- AnyCompany
- AnyCompany
+ AnyCompany.Models
+ AnyCompany.Models
v4.6.1
512
+ true
true
@@ -41,10 +42,7 @@
-
-
-
diff --git a/TechTest/AnyCompany/Customer.cs b/TechTest/AnyCompany.Models/Customer.cs
similarity index 72%
rename from TechTest/AnyCompany/Customer.cs
rename to TechTest/AnyCompany.Models/Customer.cs
index aa994b6..e0fbd3f 100644
--- a/TechTest/AnyCompany/Customer.cs
+++ b/TechTest/AnyCompany.Models/Customer.cs
@@ -1,9 +1,11 @@
using System;
-namespace AnyCompany
+namespace AnyCompany.Models
{
public class Customer
{
+ public int CustomerId { get; set; }
+
public string Country { get; set; }
public DateTime DateOfBirth { get; set; }
diff --git a/TechTest/AnyCompany/Order.cs b/TechTest/AnyCompany.Models/Order.cs
similarity index 68%
rename from TechTest/AnyCompany/Order.cs
rename to TechTest/AnyCompany.Models/Order.cs
index fec8e7b..14420a2 100644
--- a/TechTest/AnyCompany/Order.cs
+++ b/TechTest/AnyCompany.Models/Order.cs
@@ -1,9 +1,10 @@
-namespace AnyCompany
+namespace AnyCompany.Models
{
public class Order
{
public int OrderId { get; set; }
public double Amount { get; set; }
public double VAT { get; set; }
+ public int CustomerId { get; set; }
}
}
diff --git a/TechTest/AnyCompany.Models/Properties/AssemblyInfo.cs b/TechTest/AnyCompany.Models/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..71be66d
--- /dev/null
+++ b/TechTest/AnyCompany.Models/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+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: AssemblyTitle("AnyCompany.Models")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AnyCompany.Models")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 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("695d4d06-2336-4b91-ba68-4a4924cf4729")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/TechTest/AnyCompany.Services/AnyCompany.Services.csproj b/TechTest/AnyCompany.Services/AnyCompany.Services.csproj
new file mode 100644
index 0000000..8186b56
--- /dev/null
+++ b/TechTest/AnyCompany.Services/AnyCompany.Services.csproj
@@ -0,0 +1,68 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}
+ Library
+ Properties
+ AnyCompany.Services
+ AnyCompany.Services
+ v4.6.1
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {7F4D6121-26EF-48A2-A2F4-BBD5D114D8E7}
+ AnyCompany.Data.Contract
+
+
+ {695D4D06-2336-4B91-BA68-4A4924CF4729}
+ AnyCompany.Models
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany.Services/Constants/VatConstants.cs b/TechTest/AnyCompany.Services/Constants/VatConstants.cs
new file mode 100644
index 0000000..ecca404
--- /dev/null
+++ b/TechTest/AnyCompany.Services/Constants/VatConstants.cs
@@ -0,0 +1,8 @@
+namespace AnyCompany.Services.Constants
+{
+ public static class VatConstants
+ {
+ public const double UkVat = 0.2d;
+ public const double RowVat = 0;
+ }
+}
diff --git a/TechTest/AnyCompany.Services/Dtos/CustomerDto.cs b/TechTest/AnyCompany.Services/Dtos/CustomerDto.cs
new file mode 100644
index 0000000..b75328b
--- /dev/null
+++ b/TechTest/AnyCompany.Services/Dtos/CustomerDto.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace AnyCompany.Services.Dtos
+{
+ public class CustomerDto
+ {
+ public int CustomerId { get; set; }
+
+ public string Country { get; set; }
+
+ public DateTime DateOfBirth { get; set; }
+
+ public string Name { get; set; }
+ }
+}
diff --git a/TechTest/AnyCompany.Services/Dtos/CustomerOrdersDto.cs b/TechTest/AnyCompany.Services/Dtos/CustomerOrdersDto.cs
new file mode 100644
index 0000000..5ff7144
--- /dev/null
+++ b/TechTest/AnyCompany.Services/Dtos/CustomerOrdersDto.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+using AnyCompany.Models;
+
+namespace AnyCompany.Services.Dtos
+{
+ public class CustomerOrdersDto
+ {
+ public CustomerDto Customer { get; set; }
+
+ public IEnumerable Orders { get; set; }
+ }
+}
diff --git a/TechTest/AnyCompany.Services/Dtos/OrderDto.cs b/TechTest/AnyCompany.Services/Dtos/OrderDto.cs
new file mode 100644
index 0000000..01d89c1
--- /dev/null
+++ b/TechTest/AnyCompany.Services/Dtos/OrderDto.cs
@@ -0,0 +1,9 @@
+namespace AnyCompany.Services.Dtos
+{
+ public class OrderDto
+ {
+ public int OrderId { get; set; }
+ public double Amount { get; set; }
+ public double VAT { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/TechTest/AnyCompany.Services/Exceptions/CustomerNotFoundException.cs b/TechTest/AnyCompany.Services/Exceptions/CustomerNotFoundException.cs
new file mode 100644
index 0000000..6125841
--- /dev/null
+++ b/TechTest/AnyCompany.Services/Exceptions/CustomerNotFoundException.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace AnyCompany.Services.Exceptions
+{
+ public class CustomerNotFoundException : Exception
+ {
+ public CustomerNotFoundException()
+ {
+ }
+
+ public CustomerNotFoundException(string message) : base(message)
+ {
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Services/Helpers/VatCalculator.cs b/TechTest/AnyCompany.Services/Helpers/VatCalculator.cs
new file mode 100644
index 0000000..ad73735
--- /dev/null
+++ b/TechTest/AnyCompany.Services/Helpers/VatCalculator.cs
@@ -0,0 +1,13 @@
+using AnyCompany.Services.Constants;
+
+namespace AnyCompany.Services.Helpers
+{
+ internal static class VatCalculator
+ {
+ // small bit of logic so kept in a static helper method - could move behind an interface in the future
+ internal static double GetVat(string country)
+ {
+ return country == "UK" ? VatConstants.UkVat : VatConstants.RowVat;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Services/Mappers/CustomerMapper.cs b/TechTest/AnyCompany.Services/Mappers/CustomerMapper.cs
new file mode 100644
index 0000000..969c669
--- /dev/null
+++ b/TechTest/AnyCompany.Services/Mappers/CustomerMapper.cs
@@ -0,0 +1,19 @@
+using AnyCompany.Models;
+using AnyCompany.Services.Dtos;
+
+namespace AnyCompany.Services.Mappers
+{
+ public static class CustomerMapper
+ {
+ public static CustomerDto Map(Customer customer)
+ {
+ return new CustomerDto
+ {
+ CustomerId = customer.CustomerId,
+ Country = customer.Country,
+ DateOfBirth = customer.DateOfBirth,
+ Name = customer.Name
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/TechTest/AnyCompany.Services/Mappers/OrderMapper.cs b/TechTest/AnyCompany.Services/Mappers/OrderMapper.cs
new file mode 100644
index 0000000..5812f1f
--- /dev/null
+++ b/TechTest/AnyCompany.Services/Mappers/OrderMapper.cs
@@ -0,0 +1,28 @@
+using AnyCompany.Models;
+using AnyCompany.Services.Dtos;
+
+namespace AnyCompany.Services.Mappers
+{
+ public static class OrderMapper
+ {
+ public static Order Map(OrderDto orderDto)
+ {
+ return new Order
+ {
+ OrderId = orderDto.OrderId,
+ Amount = orderDto.Amount,
+ VAT = orderDto.VAT
+ };
+ }
+
+ public static OrderDto Map(Order order)
+ {
+ return new OrderDto
+ {
+ OrderId = order.OrderId,
+ Amount = order.Amount,
+ VAT = order.VAT
+ };
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/Properties/AssemblyInfo.cs b/TechTest/AnyCompany.Services/Properties/AssemblyInfo.cs
similarity index 100%
rename from TechTest/AnyCompany/Properties/AssemblyInfo.cs
rename to TechTest/AnyCompany.Services/Properties/AssemblyInfo.cs
diff --git a/TechTest/AnyCompany.Services/Services/CustomerOrderService.cs b/TechTest/AnyCompany.Services/Services/CustomerOrderService.cs
new file mode 100644
index 0000000..1e1e31d
--- /dev/null
+++ b/TechTest/AnyCompany.Services/Services/CustomerOrderService.cs
@@ -0,0 +1,43 @@
+using System.Collections.Generic;
+using System.Linq;
+using AnyCompany.Data.Contract.Repositories;
+using AnyCompany.Services.Dtos;
+using AnyCompany.Services.Mappers;
+
+namespace AnyCompany.Services.Services
+{
+ public class CustomerOrderService : ICustomerOrderService
+ {
+ private readonly ICustomerRepository _customerRepository;
+ private readonly IOrderRepository _orderRepository;
+
+ public CustomerOrderService(ICustomerRepository customerRepository, IOrderRepository orderRepository)
+ {
+ _customerRepository = customerRepository;
+ _orderRepository = orderRepository;
+ }
+
+ public IEnumerable GetAllCustomerWithOrders()
+ {
+ var customerOrderDtos = new List();
+
+ // load data
+ var customers = _customerRepository.GetList();
+ var orders = _orderRepository.GetList();
+
+ // map orders to the appropriate customer and return a dto
+ foreach (var customer in customers)
+ {
+ var customerOrderDto = new CustomerOrdersDto
+ {
+ Customer = CustomerMapper.Map(customer),
+ Orders = orders.Where(o => o.CustomerId == customer.CustomerId).Select(OrderMapper.Map)
+ };
+
+ customerOrderDtos.Add(customerOrderDto);
+ }
+
+ return customerOrderDtos;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Services/Services/ICustomerOrderService.cs b/TechTest/AnyCompany.Services/Services/ICustomerOrderService.cs
new file mode 100644
index 0000000..8fa937d
--- /dev/null
+++ b/TechTest/AnyCompany.Services/Services/ICustomerOrderService.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using AnyCompany.Services.Dtos;
+
+namespace AnyCompany.Services.Services
+{
+ public interface ICustomerOrderService
+ {
+ IEnumerable GetAllCustomerWithOrders();
+ }
+}
diff --git a/TechTest/AnyCompany.Services/Services/IOrderService.cs b/TechTest/AnyCompany.Services/Services/IOrderService.cs
new file mode 100644
index 0000000..227c155
--- /dev/null
+++ b/TechTest/AnyCompany.Services/Services/IOrderService.cs
@@ -0,0 +1,9 @@
+using AnyCompany.Services.Dtos;
+
+namespace AnyCompany.Services.Services
+{
+ public interface IOrderService
+ {
+ bool PlaceOrder(OrderDto order, int customerId);
+ }
+}
diff --git a/TechTest/AnyCompany.Services/Services/OrderService.cs b/TechTest/AnyCompany.Services/Services/OrderService.cs
new file mode 100644
index 0000000..aef7449
--- /dev/null
+++ b/TechTest/AnyCompany.Services/Services/OrderService.cs
@@ -0,0 +1,44 @@
+using AnyCompany.Data.Contract.Repositories;
+using AnyCompany.Models;
+using AnyCompany.Services.Dtos;
+using AnyCompany.Services.Exceptions;
+using AnyCompany.Services.Helpers;
+using AnyCompany.Services.Mappers;
+
+namespace AnyCompany.Services.Services
+{
+ public class OrderService : IOrderService
+ {
+ private readonly IOrderRepository _orderRepository;
+ private readonly ICustomerRepository _customerRepository;
+
+ public OrderService(IOrderRepository orderRepository, ICustomerRepository customerRepository)
+ {
+ _orderRepository = orderRepository;
+ _customerRepository = customerRepository;
+ }
+
+ public bool PlaceOrder(OrderDto orderDto, int customerId)
+ {
+ // load the customer
+ Customer customer = _customerRepository.Load(customerId);
+ if (customer == null)
+ throw new CustomerNotFoundException();
+
+ // do not proceed with order if amount is 0
+ if (orderDto.Amount == 0)
+ return false;
+
+ // get the appropriate vat for the customers country
+ orderDto.VAT = VatCalculator.GetVat(customer.Country);
+
+ // build and save the order
+ var order = OrderMapper.Map(orderDto);
+ order.CustomerId = customerId;
+
+ _orderRepository.Add(order);
+
+ return true;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj b/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj
index b537fc2..e9b4334 100644
--- a/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj
+++ b/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj
@@ -1,16 +1,19 @@
-
+
+
Debug
AnyCPU
- cd5d577e-bdc9-4dfc-ac6a-b1da474995f3
+ {CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3}
Library
Properties
AnyCompany.Tests
AnyCompany.Tests
v4.6.1
512
+
+
true
@@ -30,24 +33,58 @@
4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll
+
+
+ ..\packages\Moq.4.12.0\lib\net45\Moq.dll
+
+
+ ..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll
+
+
+
+
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+
+
+ ..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+ {7F4D6121-26EF-48A2-A2F4-BBD5D114D8E7}
+ AnyCompany.Data.Contract
+
+
+ {695D4D06-2336-4B91-BA68-4A4924CF4729}
+ AnyCompany.Models
+
+
+ {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}
+ AnyCompany.Services
+
+
-
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany.Tests/Class1.cs b/TechTest/AnyCompany.Tests/Class1.cs
deleted file mode 100644
index 5957505..0000000
--- a/TechTest/AnyCompany.Tests/Class1.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace AnyCompany.Tests
-{
- public class Class1
- {
- }
-}
diff --git a/TechTest/AnyCompany.Tests/CustomerOrderServiceTests.cs b/TechTest/AnyCompany.Tests/CustomerOrderServiceTests.cs
new file mode 100644
index 0000000..661eccd
--- /dev/null
+++ b/TechTest/AnyCompany.Tests/CustomerOrderServiceTests.cs
@@ -0,0 +1,101 @@
+using System.Collections.Generic;
+using System.Linq;
+using AnyCompany.Data.Contract.Repositories;
+using AnyCompany.Models;
+using AnyCompany.Services.Services;
+using Moq;
+using NUnit.Framework;
+
+namespace AnyCompany.Tests
+{
+ [TestFixture]
+ public class CustomerOrderServiceTests
+ {
+ private Mock _customerRepositoryMock;
+ private Mock _orderRepositoryMock;
+
+ [SetUp]
+ public void Setup()
+ {
+ _orderRepositoryMock = new Mock();
+ _customerRepositoryMock = new Mock();
+ }
+
+ [Test]
+ public void GetCustomersWithOrders_ShouldReturnAllOrders()
+ {
+ // Arrange.
+ const int CustomerOneId = 3;
+ const int CustomerTwoId = 4;
+
+ var customers = GetCustomers(CustomerOneId, CustomerTwoId);
+ _customerRepositoryMock.Setup(r => r.GetList()).Returns(customers);
+
+ var orders = GetOrders(CustomerOneId, CustomerTwoId);
+ _orderRepositoryMock.Setup(r => r.GetList()).Returns(orders);
+
+ var customerOrderService = GetService();
+
+ // Act.
+ var result = customerOrderService.GetAllCustomerWithOrders();
+
+ // Assert.
+ Assert.AreEqual(customers.Count(), result.Count());
+ Assert.AreEqual(customers.First().CustomerId, result.First().Customer.CustomerId);
+ Assert.AreEqual(customers.First().Country, result.First().Customer.Country);
+ Assert.AreEqual(customers.First().DateOfBirth, result.First().Customer.DateOfBirth);
+ Assert.AreEqual(customers.First().Name, result.First().Customer.Name);
+ Assert.AreEqual(orders.Count(o => o.CustomerId == customers.First().CustomerId), result.First().Orders.Count());
+ Assert.AreEqual(orders.First(o => o.CustomerId == customers.First().CustomerId).Amount, result.First().Orders.First().Amount);
+ Assert.AreEqual(orders.First(o => o.CustomerId == customers.First().CustomerId).VAT, result.First().Orders.First().VAT);
+ Assert.AreEqual(orders.First(o => o.CustomerId == customers.First().CustomerId).OrderId, result.First().Orders.First().OrderId);
+ }
+
+ private CustomerOrderService GetService()
+ {
+ return new CustomerOrderService(
+ _customerRepositoryMock.Object,
+ _orderRepositoryMock.Object);
+ }
+
+ private IEnumerable GetCustomers(int idOne, int idTwo)
+ {
+ return new List
+ {
+ GetCustomer(idOne),
+ GetCustomer(idTwo)
+ };
+ }
+
+ private IEnumerable GetOrders(int idOne, int idTwo)
+ {
+ return new List
+ {
+ GetOrder(33, idOne),
+ GetOrder(43, idTwo),
+ GetOrder(43, idOne),
+ };
+ }
+
+ private Customer GetCustomer(int id)
+ {
+ return new Customer
+ {
+ CustomerId = id,
+ Name = "John Smith",
+ Country = "UK"
+ };
+ }
+
+ private Order GetOrder(int id, int customerId)
+ {
+ return new Order
+ {
+ OrderId = id,
+ Amount = 20.99,
+ CustomerId = customerId,
+ VAT = 0.2d
+ };
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Tests/OrderServiceTests.cs b/TechTest/AnyCompany.Tests/OrderServiceTests.cs
new file mode 100644
index 0000000..6fc61e5
--- /dev/null
+++ b/TechTest/AnyCompany.Tests/OrderServiceTests.cs
@@ -0,0 +1,116 @@
+using System;
+using AnyCompany.Data.Contract.Repositories;
+using AnyCompany.Models;
+using AnyCompany.Services;
+using AnyCompany.Services.Dtos;
+using AnyCompany.Services.Exceptions;
+using AnyCompany.Services.Services;
+using Moq;
+using NUnit.Framework;
+
+namespace AnyCompany.Tests
+{
+ [TestFixture]
+ public class OrderServiceTests
+ {
+ private Mock _orderRepositoryMock;
+ private Mock _customerRepositoryMock;
+
+ [SetUp]
+ public void Setup()
+ {
+ _orderRepositoryMock = new Mock();
+ _customerRepositoryMock = new Mock();
+ }
+
+ [TestCase("UK", 0.2)]
+ [TestCase("FR", 0)]
+ public void PlaceOrder_ShouldLoadACustomerAndPlaceAnOrder_UK(string country, double vat)
+ {
+ // Arrange.
+ const int CustomerId = 23;
+ var orderDto = GetOrderDto();
+
+ var customer = GetCustomer(country);
+ _customerRepositoryMock.Setup(r => r.Load(CustomerId))
+ .Returns(customer);
+
+ Order inOrder = null;
+ _orderRepositoryMock.Setup(o => o.Add(It.IsAny()))
+ .Callback(o => inOrder = o);
+
+ var orderService = GetOrderService();
+
+ // Act.
+ var result = orderService.PlaceOrder(orderDto, CustomerId);
+
+ // Assert.
+ Assert.IsTrue(result);
+ Assert.AreEqual(orderDto.Amount, inOrder.Amount);
+ Assert.AreEqual(vat, inOrder.VAT);
+ Assert.AreEqual(CustomerId, inOrder.CustomerId);
+ }
+
+ [Test]
+ public void PlaceOrder_CustomerNotFound_ShouldThrowException()
+ {
+ // Arrange.
+ const int CustomerId = 44;
+
+ _customerRepositoryMock.Setup(r => r.Load(CustomerId))
+ .Returns((Customer)null);
+
+ var orderService = GetOrderService();
+
+ // Act/Assert.
+ Assert.Throws(() => orderService.PlaceOrder(GetOrderDto(), CustomerId));
+ }
+
+ [Test]
+ public void PlaceOrder_AmountIs0_ShouldReturnFalse()
+ {
+ // Arrange.
+ const int CustomerId = 23;
+ var orderDto = GetOrderDto();
+
+ var customer = GetCustomer("UK");
+ _customerRepositoryMock.Setup(r => r.Load(CustomerId))
+ .Returns(customer);
+
+ orderDto.Amount = 0;
+
+ var orderService = GetOrderService();
+
+ // Act.
+ var result = orderService.PlaceOrder(orderDto, CustomerId);
+
+ // Assert.
+ Assert.IsFalse(result);
+ }
+
+ private Customer GetCustomer(string country)
+ {
+ return new Customer
+ {
+ Name = "John Smith",
+ DateOfBirth = DateTime.UtcNow.AddYears(-31),
+ Country = country
+ };
+ }
+
+ private OrderService GetOrderService()
+ {
+ return new OrderService(
+ _orderRepositoryMock.Object,
+ _customerRepositoryMock.Object);
+ }
+
+ private OrderDto GetOrderDto()
+ {
+ return new OrderDto
+ {
+ Amount = 20,
+ };
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Tests/packages.config b/TechTest/AnyCompany.Tests/packages.config
new file mode 100644
index 0000000..bf0c6ae
--- /dev/null
+++ b/TechTest/AnyCompany.Tests/packages.config
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany/CustomerRepository.cs b/TechTest/AnyCompany/CustomerRepository.cs
deleted file mode 100644
index e3de9b7..0000000
--- a/TechTest/AnyCompany/CustomerRepository.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System;
-using System.Data.SqlClient;
-
-namespace AnyCompany
-{
- public static class CustomerRepository
- {
- private static string ConnectionString = @"Data Source=(local);Database=Customers;User Id=admin;Password=password;";
-
- public static Customer Load(int customerId)
- {
- Customer customer = new Customer();
-
- SqlConnection connection = new SqlConnection(ConnectionString);
- connection.Open();
-
- SqlCommand command = new SqlCommand("SELECT * FROM Customer WHERE CustomerId = " + customerId,
- connection);
- var reader = command.ExecuteReader();
-
- while (reader.Read())
- {
- customer.Name = reader["Name"].ToString();
- customer.DateOfBirth = DateTime.Parse(reader["DateOfBirth"].ToString());
- customer.Country = reader["Country"].ToString();
- }
-
- connection.Close();
-
- return customer;
- }
- }
-}
diff --git a/TechTest/AnyCompany/OrderRepository.cs b/TechTest/AnyCompany/OrderRepository.cs
deleted file mode 100644
index 3229885..0000000
--- a/TechTest/AnyCompany/OrderRepository.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System.Data.SqlClient;
-
-namespace AnyCompany
-{
- internal class OrderRepository
- {
- private static string ConnectionString = @"Data Source=(local);Database=Orders;User Id=admin;Password=password;";
-
- public void Save(Order order)
- {
- SqlConnection connection = new SqlConnection(ConnectionString);
- connection.Open();
-
- SqlCommand command = new SqlCommand("INSERT INTO Orders VALUES (@OrderId, @Amount, @VAT)", connection);
-
- command.Parameters.AddWithValue("@OrderId", order.OrderId);
- command.Parameters.AddWithValue("@Amount", order.Amount);
- command.Parameters.AddWithValue("@VAT", order.VAT);
-
- command.ExecuteNonQuery();
-
- connection.Close();
- }
- }
-}
diff --git a/TechTest/AnyCompany/OrderService.cs b/TechTest/AnyCompany/OrderService.cs
deleted file mode 100644
index ebfb103..0000000
--- a/TechTest/AnyCompany/OrderService.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-namespace AnyCompany
-{
- public class OrderService
- {
- private readonly OrderRepository orderRepository = new OrderRepository();
-
- public bool PlaceOrder(Order order, int customerId)
- {
- Customer customer = CustomerRepository.Load(customerId);
-
- if (order.Amount == 0)
- return false;
-
- if (customer.Country == "UK")
- order.VAT = 0.2d;
- else
- order.VAT = 0;
-
- orderRepository.Save(order);
-
- return true;
- }
- }
-}
diff --git a/TechTest/TechTest.sln b/TechTest/TechTest.sln
index 1c1c57a..ba64203 100644
--- a/TechTest/TechTest.sln
+++ b/TechTest/TechTest.sln
@@ -1,10 +1,8 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27004.2005
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.28917.181
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCompany", "AnyCompany\AnyCompany.csproj", "{C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCompany.Tests", "AnyCompany.Tests\AnyCompany.Tests.csproj", "{CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B6D3C1BB-2A37-4E17-9EE3-DEF28286E782}"
@@ -12,24 +10,79 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Instructions.txt = Instructions.txt
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Database Scaffolding Scripts", "Database Scaffolding Scripts", "{0372EDAB-809E-4632-A929-146E339E9EB0}"
+ ProjectSection(SolutionItems) = preProject
+ AddCustomers.sql = AddCustomers.sql
+ AddOrders.sql = AddOrders.sql
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1. Business Layer", "1. Business Layer", "{25F15798-EF39-43DD-B9A8-11DA2D8EB5EB}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4. Tests", "4. Tests", "{118DE10D-B767-428F-B9D3-3987DF71146A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCompany.IntegrationTests", "AnyCompany.IntegrationTests\AnyCompany.IntegrationTests.csproj", "{DF80D016-3AFE-43B3-BC8F-3CEC313B4C91}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2. Data Access Layer", "2. Data Access Layer", "{A38327A3-2391-4469-AB71-3AB3714531BB}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3. Framework", "3. Framework", "{DB29E18C-EE03-4193-857E-FD98D35D783A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCompany.Models", "AnyCompany.Models\AnyCompany.Models.csproj", "{695D4D06-2336-4B91-BA68-4A4924CF4729}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCompany.Services", "AnyCompany.Services\AnyCompany.Services.csproj", "{C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCompany.Data.Contract", "AnyCompany.Data.Contract\AnyCompany.Data.Contract.csproj", "{7F4D6121-26EF-48A2-A2F4-BBD5D114D8E7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCompany.Data.Dapper", "AnyCompany.Data.Dapper\AnyCompany.Data.Dapper.csproj", "{CEF90CEA-CEDF-44B4-9203-9B9ADF9A15CE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCompany.Ioc", "AnyCompany.Ioc\AnyCompany.Ioc.csproj", "{BE9D1186-D67F-4BA0-9A94-CE529CC1FEFA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}.Release|Any CPU.Build.0 = Release|Any CPU
{CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DF80D016-3AFE-43B3-BC8F-3CEC313B4C91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DF80D016-3AFE-43B3-BC8F-3CEC313B4C91}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DF80D016-3AFE-43B3-BC8F-3CEC313B4C91}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DF80D016-3AFE-43B3-BC8F-3CEC313B4C91}.Release|Any CPU.Build.0 = Release|Any CPU
+ {695D4D06-2336-4B91-BA68-4A4924CF4729}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {695D4D06-2336-4B91-BA68-4A4924CF4729}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {695D4D06-2336-4B91-BA68-4A4924CF4729}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {695D4D06-2336-4B91-BA68-4A4924CF4729}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7F4D6121-26EF-48A2-A2F4-BBD5D114D8E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7F4D6121-26EF-48A2-A2F4-BBD5D114D8E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7F4D6121-26EF-48A2-A2F4-BBD5D114D8E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7F4D6121-26EF-48A2-A2F4-BBD5D114D8E7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CEF90CEA-CEDF-44B4-9203-9B9ADF9A15CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CEF90CEA-CEDF-44B4-9203-9B9ADF9A15CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CEF90CEA-CEDF-44B4-9203-9B9ADF9A15CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CEF90CEA-CEDF-44B4-9203-9B9ADF9A15CE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BE9D1186-D67F-4BA0-9A94-CE529CC1FEFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BE9D1186-D67F-4BA0-9A94-CE529CC1FEFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BE9D1186-D67F-4BA0-9A94-CE529CC1FEFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BE9D1186-D67F-4BA0-9A94-CE529CC1FEFA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3} = {118DE10D-B767-428F-B9D3-3987DF71146A}
+ {DF80D016-3AFE-43B3-BC8F-3CEC313B4C91} = {118DE10D-B767-428F-B9D3-3987DF71146A}
+ {695D4D06-2336-4B91-BA68-4A4924CF4729} = {DB29E18C-EE03-4193-857E-FD98D35D783A}
+ {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D} = {25F15798-EF39-43DD-B9A8-11DA2D8EB5EB}
+ {7F4D6121-26EF-48A2-A2F4-BBD5D114D8E7} = {A38327A3-2391-4469-AB71-3AB3714531BB}
+ {CEF90CEA-CEDF-44B4-9203-9B9ADF9A15CE} = {A38327A3-2391-4469-AB71-3AB3714531BB}
+ {BE9D1186-D67F-4BA0-9A94-CE529CC1FEFA} = {DB29E18C-EE03-4193-857E-FD98D35D783A}
+ EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4D629674-23F9-49DA-971E-77A5D7A7C39D}
EndGlobalSection