diff --git a/.gitignore b/.gitignore
index 13c5c5c..003a23f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -806,4 +806,5 @@ $RECYCLE.BIN/
# End of https://www.toptal.com/developers/gitignore/api/windows,linux,macos,visualstudio,visualstudiocode,rider,csharp,aspnetcore,dotnetcore
.editorconfig
-!linting/.editorconfig
\ No newline at end of file
+!linting/.editorconfig
+*.hash
diff --git a/Cogworks.AzureSearch.sln b/Cogworks.AzureSearch.sln
index 3a5020f..478cff6 100644
--- a/Cogworks.AzureSearch.sln
+++ b/Cogworks.AzureSearch.sln
@@ -9,11 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{B5DAEDD1
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{180E9BD6-30B9-4D88-B88C-9F289D316967}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cogworks.AzureSearch.UnitTests", "tests\UnitTests\Cogworks.AzureSearch.UnitTests\Cogworks.AzureSearch.UnitTests.csproj", "{37898883-18CD-47A7-BA59-E4FC1FD8B8E1}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cogworks.AzureSearch", "src\Cogworks.AzureSearch\Cogworks.AzureSearch.csproj", "{94F77E26-4E02-4ED5-BD54-45E3AAA70090}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9D0073AC-CE06-400A-B362-297CB9A332BE}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".solution-items", ".solution-items", "{9D0073AC-CE06-400A-B362-297CB9A332BE}"
ProjectSection(SolutionItems) = preProject
linting\.editorconfig = linting\.editorconfig
CHANGELOG.md = CHANGELOG.md
@@ -25,28 +21,158 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
linting\stylecop.json = linting\stylecop.json
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{A82EFC5A-0A90-4701-8106-2C5044592572}"
+ ProjectSection(SolutionItems) = preProject
+ .github\PULL_REQUEST_TEMPLATE.md = .github\PULL_REQUEST_TEMPLATE.md
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{43C9CC92-BE1A-4D4F-B82D-F973185F214C}"
+ ProjectSection(SolutionItems) = preProject
+ .github\workflows\build.yml = .github\workflows\build.yml
+ .github\workflows\changelog.yml = .github\workflows\changelog.yml
+ .github\workflows\gitflow.yml = .github\workflows\gitflow.yml
+ .github\workflows\pull-request.yml = .github\workflows\pull-request.yml
+ .github\workflows\release-github.yml = .github\workflows\release-github.yml
+ .github\workflows\release-nuget.yml = .github\workflows\release-nuget.yml
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cogworks.AzureSearch", "Cogworks.AzureSearch", "{9C3D9268-B066-4E34-929C-F45E801BD4B0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cogworks.AzureSearch", "src\Cogworks.AzureSearch\src\Cogworks.AzureSearch.csproj", "{350EEE42-DE3F-4C10-89BC-0422F6CC1069}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cogworks.AzureSearch.UnitTests", "src\Cogworks.AzureSearch\tests\UnitTests\Cogworks.AzureSearch.UnitTests\Cogworks.AzureSearch.UnitTests.csproj", "{CBA4193C-1363-42CD-8426-01729C61D432}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IoC.Providers", "IoC.Providers", "{0DD124A1-534B-4AFF-B252-D884CCCB9CC3}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cogworks.AzureSearch.IoC.Microsoft", "Cogworks.AzureSearch.IoC.Microsoft", "{9F1676F4-2441-4FC8-AB8D-3C019EA61853}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{965C0D6C-B421-48EF-9E02-82FF044B9CEA}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{99E4E02C-94B6-43AC-AB9B-F04BE5D8BC92}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{E0093B96-E28A-4471-8417-026A9B1101A8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cogworks.AzureSearch.IoC.Microsoft", "src\IoC.Providers\Cogworks.AzureSearch.IoC.Microsoft\src\Cogworks.AzureSearch.IoC.Microsoft.csproj", "{7666A8E8-4CD6-4BF1-AAED-277BE1E39BA2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cogworks.AzureSearch.IoC.Microsoft.UnitTests", "src\IoC.Providers\Cogworks.AzureSearch.IoC.Microsoft\tests\UnitTests\Cogworks.AzureSearch.IoC.Microsoft.UnitTests\Cogworks.AzureSearch.IoC.Microsoft.UnitTests.csproj", "{010ED38D-616E-467A-AC1B-3D409185171F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cogworks.AzureSearch.IoC.Autofac", "Cogworks.AzureSearch.IoC.Autofac", "{27EFEA7F-24A7-4D01-A888-712A3EBCD261}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A3AAC530-960E-4732-AB87-DBA9470B229D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{CD92425E-77AC-451B-9595-0A91D6661B6F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cogworks.AzureSearch.IoC.Autofac", "src\IoC.Providers\Cogworks.AzureSearch.IoC.Autofac\src\Cogworks.AzureSearch.IoC.Autofac.csproj", "{F74DA3A4-F44F-4484-A48C-416DEBDC73A7}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{EEBF1D25-F8B2-4D41-806E-E401961EEE35}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cogworks.AzureSearch.IoC.Autofac.UnitTests", "src\IoC.Providers\Cogworks.AzureSearch.IoC.Autofac\tests\UnitTests\Cogworks.AzureSearch.IoC.Autofac.UnitTests\Cogworks.AzureSearch.IoC.Autofac.UnitTests.csproj", "{72F59324-3859-4FE8-97F0-B57844848950}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cogworks.AzureSearch.IoC.LightInject", "Cogworks.AzureSearch.IoC.LightInject", "{F647B586-5EFB-46C0-A303-EF7022A6EDD0}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8CAFFC72-9B26-484D-98F4-0DF8D4D5FE6C}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0DC139DC-86BE-4EBC-8110-E78B39D02A05}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{CE0638CA-4C05-4DD7-AC83-3271F729B474}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cogworks.AzureSearch.IoC.LightInject", "src\IoC.Providers\Cogworks.AzureSearch.IoC.LightInject\src\Cogworks.AzureSearch.IoC.LightInject.csproj", "{6A574A2F-277E-4A77-8DD8-C4722631226E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cogworks.AzureSearch.IoC.LightInject.UnitTests", "src\IoC.Providers\Cogworks.AzureSearch.IoC.LightInject\tests\UnitTests\Cogworks.AzureSearch.IoC.LightInject.UnitTests\Cogworks.AzureSearch.IoC.LightInject.UnitTests.csproj", "{3DAFCE04-69C8-4BB1-B638-02606DC8480A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cogworks.AzureSearch.IoC.Umbraco", "Cogworks.AzureSearch.IoC.Umbraco", "{C8DAFC00-B22B-4CD6-A280-50C037DE0EFE}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C13DFF15-6FB7-4BA8-A82B-13F92287D332}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{3BC9DA9E-CB54-4799-A7DF-7F993BFA89E9}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{1F0E1693-8441-48D0-B4F6-37E816B5E898}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cogworks.AzureSearch.IoC.Umbraco", "src\IoC.Providers\Cogworks.AzureSearch.IoC.Umbraco\src\Cogworks.AzureSearch.IoC.Umbraco.csproj", "{C24EEC89-FDED-4AA1-AB44-26FD6D3D8533}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cogworks.AzureSearch.IoC.Umbraco.UnitTests", "src\IoC.Providers\Cogworks.AzureSearch.IoC.Umbraco\tests\UnitTests\Cogworks.AzureSearch.IoC.Umbraco.UnitTests\Cogworks.AzureSearch.IoC.Umbraco.UnitTests.csproj", "{723295D3-FD9C-47FC-AC58-2E075D7573A9}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {37898883-18CD-47A7-BA59-E4FC1FD8B8E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {37898883-18CD-47A7-BA59-E4FC1FD8B8E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {37898883-18CD-47A7-BA59-E4FC1FD8B8E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {37898883-18CD-47A7-BA59-E4FC1FD8B8E1}.Release|Any CPU.Build.0 = Release|Any CPU
- {94F77E26-4E02-4ED5-BD54-45E3AAA70090}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {94F77E26-4E02-4ED5-BD54-45E3AAA70090}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {94F77E26-4E02-4ED5-BD54-45E3AAA70090}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {94F77E26-4E02-4ED5-BD54-45E3AAA70090}.Release|Any CPU.Build.0 = Release|Any CPU
+ {350EEE42-DE3F-4C10-89BC-0422F6CC1069}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {350EEE42-DE3F-4C10-89BC-0422F6CC1069}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {350EEE42-DE3F-4C10-89BC-0422F6CC1069}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {350EEE42-DE3F-4C10-89BC-0422F6CC1069}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CBA4193C-1363-42CD-8426-01729C61D432}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CBA4193C-1363-42CD-8426-01729C61D432}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CBA4193C-1363-42CD-8426-01729C61D432}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CBA4193C-1363-42CD-8426-01729C61D432}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7666A8E8-4CD6-4BF1-AAED-277BE1E39BA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7666A8E8-4CD6-4BF1-AAED-277BE1E39BA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7666A8E8-4CD6-4BF1-AAED-277BE1E39BA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7666A8E8-4CD6-4BF1-AAED-277BE1E39BA2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {010ED38D-616E-467A-AC1B-3D409185171F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {010ED38D-616E-467A-AC1B-3D409185171F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {010ED38D-616E-467A-AC1B-3D409185171F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {010ED38D-616E-467A-AC1B-3D409185171F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F74DA3A4-F44F-4484-A48C-416DEBDC73A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F74DA3A4-F44F-4484-A48C-416DEBDC73A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F74DA3A4-F44F-4484-A48C-416DEBDC73A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F74DA3A4-F44F-4484-A48C-416DEBDC73A7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {72F59324-3859-4FE8-97F0-B57844848950}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {72F59324-3859-4FE8-97F0-B57844848950}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {72F59324-3859-4FE8-97F0-B57844848950}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {72F59324-3859-4FE8-97F0-B57844848950}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6A574A2F-277E-4A77-8DD8-C4722631226E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6A574A2F-277E-4A77-8DD8-C4722631226E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6A574A2F-277E-4A77-8DD8-C4722631226E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6A574A2F-277E-4A77-8DD8-C4722631226E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3DAFCE04-69C8-4BB1-B638-02606DC8480A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3DAFCE04-69C8-4BB1-B638-02606DC8480A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3DAFCE04-69C8-4BB1-B638-02606DC8480A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3DAFCE04-69C8-4BB1-B638-02606DC8480A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C24EEC89-FDED-4AA1-AB44-26FD6D3D8533}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C24EEC89-FDED-4AA1-AB44-26FD6D3D8533}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C24EEC89-FDED-4AA1-AB44-26FD6D3D8533}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C24EEC89-FDED-4AA1-AB44-26FD6D3D8533}.Release|Any CPU.Build.0 = Release|Any CPU
+ {723295D3-FD9C-47FC-AC58-2E075D7573A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {723295D3-FD9C-47FC-AC58-2E075D7573A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {723295D3-FD9C-47FC-AC58-2E075D7573A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {723295D3-FD9C-47FC-AC58-2E075D7573A9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{180E9BD6-30B9-4D88-B88C-9F289D316967} = {B5DAEDD1-13AF-4A74-BD24-42EBCB1A18D0}
- {37898883-18CD-47A7-BA59-E4FC1FD8B8E1} = {180E9BD6-30B9-4D88-B88C-9F289D316967}
- {94F77E26-4E02-4ED5-BD54-45E3AAA70090} = {B85EEFD6-B048-478E-A032-3CCE3F0B3093}
+ {43C9CC92-BE1A-4D4F-B82D-F973185F214C} = {A82EFC5A-0A90-4701-8106-2C5044592572}
+ {B85EEFD6-B048-478E-A032-3CCE3F0B3093} = {9C3D9268-B066-4E34-929C-F45E801BD4B0}
+ {B5DAEDD1-13AF-4A74-BD24-42EBCB1A18D0} = {9C3D9268-B066-4E34-929C-F45E801BD4B0}
+ {350EEE42-DE3F-4C10-89BC-0422F6CC1069} = {B85EEFD6-B048-478E-A032-3CCE3F0B3093}
+ {CBA4193C-1363-42CD-8426-01729C61D432} = {180E9BD6-30B9-4D88-B88C-9F289D316967}
+ {9F1676F4-2441-4FC8-AB8D-3C019EA61853} = {0DD124A1-534B-4AFF-B252-D884CCCB9CC3}
+ {965C0D6C-B421-48EF-9E02-82FF044B9CEA} = {9F1676F4-2441-4FC8-AB8D-3C019EA61853}
+ {99E4E02C-94B6-43AC-AB9B-F04BE5D8BC92} = {9F1676F4-2441-4FC8-AB8D-3C019EA61853}
+ {E0093B96-E28A-4471-8417-026A9B1101A8} = {99E4E02C-94B6-43AC-AB9B-F04BE5D8BC92}
+ {7666A8E8-4CD6-4BF1-AAED-277BE1E39BA2} = {965C0D6C-B421-48EF-9E02-82FF044B9CEA}
+ {010ED38D-616E-467A-AC1B-3D409185171F} = {E0093B96-E28A-4471-8417-026A9B1101A8}
+ {27EFEA7F-24A7-4D01-A888-712A3EBCD261} = {0DD124A1-534B-4AFF-B252-D884CCCB9CC3}
+ {A3AAC530-960E-4732-AB87-DBA9470B229D} = {27EFEA7F-24A7-4D01-A888-712A3EBCD261}
+ {CD92425E-77AC-451B-9595-0A91D6661B6F} = {27EFEA7F-24A7-4D01-A888-712A3EBCD261}
+ {F74DA3A4-F44F-4484-A48C-416DEBDC73A7} = {A3AAC530-960E-4732-AB87-DBA9470B229D}
+ {EEBF1D25-F8B2-4D41-806E-E401961EEE35} = {CD92425E-77AC-451B-9595-0A91D6661B6F}
+ {72F59324-3859-4FE8-97F0-B57844848950} = {EEBF1D25-F8B2-4D41-806E-E401961EEE35}
+ {F647B586-5EFB-46C0-A303-EF7022A6EDD0} = {0DD124A1-534B-4AFF-B252-D884CCCB9CC3}
+ {8CAFFC72-9B26-484D-98F4-0DF8D4D5FE6C} = {F647B586-5EFB-46C0-A303-EF7022A6EDD0}
+ {0DC139DC-86BE-4EBC-8110-E78B39D02A05} = {F647B586-5EFB-46C0-A303-EF7022A6EDD0}
+ {CE0638CA-4C05-4DD7-AC83-3271F729B474} = {0DC139DC-86BE-4EBC-8110-E78B39D02A05}
+ {6A574A2F-277E-4A77-8DD8-C4722631226E} = {8CAFFC72-9B26-484D-98F4-0DF8D4D5FE6C}
+ {3DAFCE04-69C8-4BB1-B638-02606DC8480A} = {CE0638CA-4C05-4DD7-AC83-3271F729B474}
+ {C8DAFC00-B22B-4CD6-A280-50C037DE0EFE} = {0DD124A1-534B-4AFF-B252-D884CCCB9CC3}
+ {C13DFF15-6FB7-4BA8-A82B-13F92287D332} = {C8DAFC00-B22B-4CD6-A280-50C037DE0EFE}
+ {3BC9DA9E-CB54-4799-A7DF-7F993BFA89E9} = {C8DAFC00-B22B-4CD6-A280-50C037DE0EFE}
+ {1F0E1693-8441-48D0-B4F6-37E816B5E898} = {3BC9DA9E-CB54-4799-A7DF-7F993BFA89E9}
+ {C24EEC89-FDED-4AA1-AB44-26FD6D3D8533} = {C13DFF15-6FB7-4BA8-A82B-13F92287D332}
+ {723295D3-FD9C-47FC-AC58-2E075D7573A9} = {1F0E1693-8441-48D0-B4F6-37E816B5E898}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DC813CF7-BD65-4CD5-B0B7-7B1F828A9909}
diff --git a/src/Cogworks.AzureSearch/Cogworks.AzureSearch.csproj b/src/Cogworks.AzureSearch/src/Cogworks.AzureSearch.csproj
similarity index 100%
rename from src/Cogworks.AzureSearch/Cogworks.AzureSearch.csproj
rename to src/Cogworks.AzureSearch/src/Cogworks.AzureSearch.csproj
diff --git a/src/Cogworks.AzureSearch/Cogworks.AzureSearch.nuspec b/src/Cogworks.AzureSearch/src/Cogworks.AzureSearch.nuspec
similarity index 100%
rename from src/Cogworks.AzureSearch/Cogworks.AzureSearch.nuspec
rename to src/Cogworks.AzureSearch/src/Cogworks.AzureSearch.nuspec
diff --git a/src/Cogworks.AzureSearch/Constants/StringConstants/Separators.cs b/src/Cogworks.AzureSearch/src/Constants/StringConstants/Separators.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Constants/StringConstants/Separators.cs
rename to src/Cogworks.AzureSearch/src/Constants/StringConstants/Separators.cs
diff --git a/src/Cogworks.AzureSearch/Constants/StringConstants/Terms.cs b/src/Cogworks.AzureSearch/src/Constants/StringConstants/Terms.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Constants/StringConstants/Terms.cs
rename to src/Cogworks.AzureSearch/src/Constants/StringConstants/Terms.cs
diff --git a/src/Cogworks.AzureSearch/Directory.Build.props b/src/Cogworks.AzureSearch/src/Directory.Build.props
similarity index 100%
rename from src/Cogworks.AzureSearch/Directory.Build.props
rename to src/Cogworks.AzureSearch/src/Directory.Build.props
diff --git a/src/Cogworks.AzureSearch/Directory.Build.targets b/src/Cogworks.AzureSearch/src/Directory.Build.targets
similarity index 100%
rename from src/Cogworks.AzureSearch/Directory.Build.targets
rename to src/Cogworks.AzureSearch/src/Directory.Build.targets
diff --git a/src/Cogworks.AzureSearch/Enums/QueryType.cs b/src/Cogworks.AzureSearch/src/Enums/QueryType.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Enums/QueryType.cs
rename to src/Cogworks.AzureSearch/src/Enums/QueryType.cs
diff --git a/src/Cogworks.AzureSearch/Enums/SearchModeType.cs b/src/Cogworks.AzureSearch/src/Enums/SearchModeType.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Enums/SearchModeType.cs
rename to src/Cogworks.AzureSearch/src/Enums/SearchModeType.cs
diff --git a/src/Cogworks.AzureSearch/Exceptions/DocumentsExceptions/AddOrUpdateDocumentException.cs b/src/Cogworks.AzureSearch/src/Exceptions/DocumentsExceptions/AddOrUpdateDocumentException.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Exceptions/DocumentsExceptions/AddOrUpdateDocumentException.cs
rename to src/Cogworks.AzureSearch/src/Exceptions/DocumentsExceptions/AddOrUpdateDocumentException.cs
diff --git a/src/Cogworks.AzureSearch/Exceptions/DocumentsExceptions/RemoveDocumentException.cs b/src/Cogworks.AzureSearch/src/Exceptions/DocumentsExceptions/RemoveDocumentException.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Exceptions/DocumentsExceptions/RemoveDocumentException.cs
rename to src/Cogworks.AzureSearch/src/Exceptions/DocumentsExceptions/RemoveDocumentException.cs
diff --git a/src/Cogworks.AzureSearch/Exceptions/DomainException.cs b/src/Cogworks.AzureSearch/src/Exceptions/DomainException.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Exceptions/DomainException.cs
rename to src/Cogworks.AzureSearch/src/Exceptions/DomainException.cs
diff --git a/src/Cogworks.AzureSearch/Exceptions/IndexExceptions/IndexClearException.cs b/src/Cogworks.AzureSearch/src/Exceptions/IndexExceptions/IndexClearException.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Exceptions/IndexExceptions/IndexClearException.cs
rename to src/Cogworks.AzureSearch/src/Exceptions/IndexExceptions/IndexClearException.cs
diff --git a/src/Cogworks.AzureSearch/Exceptions/IndexExceptions/IndexCreateOrUpdateException.cs b/src/Cogworks.AzureSearch/src/Exceptions/IndexExceptions/IndexCreateOrUpdateException.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Exceptions/IndexExceptions/IndexCreateOrUpdateException.cs
rename to src/Cogworks.AzureSearch/src/Exceptions/IndexExceptions/IndexCreateOrUpdateException.cs
diff --git a/src/Cogworks.AzureSearch/Exceptions/IndexExceptions/IndexDeleteException.cs b/src/Cogworks.AzureSearch/src/Exceptions/IndexExceptions/IndexDeleteException.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Exceptions/IndexExceptions/IndexDeleteException.cs
rename to src/Cogworks.AzureSearch/src/Exceptions/IndexExceptions/IndexDeleteException.cs
diff --git a/src/Cogworks.AzureSearch/Exceptions/IndexExceptions/IndexExistsException.cs b/src/Cogworks.AzureSearch/src/Exceptions/IndexExceptions/IndexExistsException.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Exceptions/IndexExceptions/IndexExistsException.cs
rename to src/Cogworks.AzureSearch/src/Exceptions/IndexExceptions/IndexExistsException.cs
diff --git a/src/Cogworks.AzureSearch/Exceptions/IndexExceptions/IndexInitializerException.cs b/src/Cogworks.AzureSearch/src/Exceptions/IndexExceptions/IndexInitializerException.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Exceptions/IndexExceptions/IndexInitializerException.cs
rename to src/Cogworks.AzureSearch/src/Exceptions/IndexExceptions/IndexInitializerException.cs
diff --git a/src/Cogworks.AzureSearch/Extensions/EnumerableExtensions.cs b/src/Cogworks.AzureSearch/src/Extensions/EnumerableExtensions.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Extensions/EnumerableExtensions.cs
rename to src/Cogworks.AzureSearch/src/Extensions/EnumerableExtensions.cs
diff --git a/src/Cogworks.AzureSearch/Extensions/StringExtensions.cs b/src/Cogworks.AzureSearch/src/Extensions/StringExtensions.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Extensions/StringExtensions.cs
rename to src/Cogworks.AzureSearch/src/Extensions/StringExtensions.cs
diff --git a/src/Cogworks.AzureSearch/Filters/ArrayOperationsFilter.cs b/src/Cogworks.AzureSearch/src/Filters/ArrayOperationsFilter.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Filters/ArrayOperationsFilter.cs
rename to src/Cogworks.AzureSearch/src/Filters/ArrayOperationsFilter.cs
diff --git a/src/Cogworks.AzureSearch/Filters/LiteralsOperationsFilter.cs b/src/Cogworks.AzureSearch/src/Filters/LiteralsOperationsFilter.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Filters/LiteralsOperationsFilter.cs
rename to src/Cogworks.AzureSearch/src/Filters/LiteralsOperationsFilter.cs
diff --git a/src/Cogworks.AzureSearch/Filters/LogicOperationsFilter.cs b/src/Cogworks.AzureSearch/src/Filters/LogicOperationsFilter.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Filters/LogicOperationsFilter.cs
rename to src/Cogworks.AzureSearch/src/Filters/LogicOperationsFilter.cs
diff --git a/src/Cogworks.AzureSearch/Filters/RangeFilter.cs b/src/Cogworks.AzureSearch/src/Filters/RangeFilter.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Filters/RangeFilter.cs
rename to src/Cogworks.AzureSearch/src/Filters/RangeFilter.cs
diff --git a/src/Cogworks.AzureSearch/Indexes/Index.cs b/src/Cogworks.AzureSearch/src/Indexes/Index.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Indexes/Index.cs
rename to src/Cogworks.AzureSearch/src/Indexes/Index.cs
diff --git a/src/Cogworks.AzureSearch/Initializers/Initializer.cs b/src/Cogworks.AzureSearch/src/Initializers/Initializer.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Initializers/Initializer.cs
rename to src/Cogworks.AzureSearch/src/Initializers/Initializer.cs
diff --git a/src/Cogworks.AzureSearch/Interfaces/Builder/IContainerBuilder.cs b/src/Cogworks.AzureSearch/src/Interfaces/Builder/IContainerBuilder.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Interfaces/Builder/IContainerBuilder.cs
rename to src/Cogworks.AzureSearch/src/Interfaces/Builder/IContainerBuilder.cs
diff --git a/src/Cogworks.AzureSearch/Interfaces/Indexes/IIndex.cs b/src/Cogworks.AzureSearch/src/Interfaces/Indexes/IIndex.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Interfaces/Indexes/IIndex.cs
rename to src/Cogworks.AzureSearch/src/Interfaces/Indexes/IIndex.cs
diff --git a/src/Cogworks.AzureSearch/Interfaces/Initializers/IInitializer.cs b/src/Cogworks.AzureSearch/src/Interfaces/Initializers/IInitializer.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Interfaces/Initializers/IInitializer.cs
rename to src/Cogworks.AzureSearch/src/Interfaces/Initializers/IInitializer.cs
diff --git a/src/Cogworks.AzureSearch/Interfaces/Operations/IDocumentOperation.cs b/src/Cogworks.AzureSearch/src/Interfaces/Operations/IDocumentOperation.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Interfaces/Operations/IDocumentOperation.cs
rename to src/Cogworks.AzureSearch/src/Interfaces/Operations/IDocumentOperation.cs
diff --git a/src/Cogworks.AzureSearch/Interfaces/Operations/IIndexOperation.cs b/src/Cogworks.AzureSearch/src/Interfaces/Operations/IIndexOperation.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Interfaces/Operations/IIndexOperation.cs
rename to src/Cogworks.AzureSearch/src/Interfaces/Operations/IIndexOperation.cs
diff --git a/src/Cogworks.AzureSearch/Interfaces/Repositories/IRepository.cs b/src/Cogworks.AzureSearch/src/Interfaces/Repositories/IRepository.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Interfaces/Repositories/IRepository.cs
rename to src/Cogworks.AzureSearch/src/Interfaces/Repositories/IRepository.cs
diff --git a/src/Cogworks.AzureSearch/Interfaces/Searches/ISearcher.cs b/src/Cogworks.AzureSearch/src/Interfaces/Searches/ISearcher.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Interfaces/Searches/ISearcher.cs
rename to src/Cogworks.AzureSearch/src/Interfaces/Searches/ISearcher.cs
diff --git a/src/Cogworks.AzureSearch/Interfaces/Wrappers/IDocumentOperationWrapper.cs b/src/Cogworks.AzureSearch/src/Interfaces/Wrappers/IDocumentOperationWrapper.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Interfaces/Wrappers/IDocumentOperationWrapper.cs
rename to src/Cogworks.AzureSearch/src/Interfaces/Wrappers/IDocumentOperationWrapper.cs
diff --git a/src/Cogworks.AzureSearch/Interfaces/Wrappers/IIndexOperationWrapper.cs b/src/Cogworks.AzureSearch/src/Interfaces/Wrappers/IIndexOperationWrapper.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Interfaces/Wrappers/IIndexOperationWrapper.cs
rename to src/Cogworks.AzureSearch/src/Interfaces/Wrappers/IIndexOperationWrapper.cs
diff --git a/src/Cogworks.AzureSearch/Mappers/ParametersMapper.cs b/src/Cogworks.AzureSearch/src/Mappers/ParametersMapper.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Mappers/ParametersMapper.cs
rename to src/Cogworks.AzureSearch/src/Mappers/ParametersMapper.cs
diff --git a/src/Cogworks.AzureSearch/Mappers/SearchResultMapper.cs b/src/Cogworks.AzureSearch/src/Mappers/SearchResultMapper.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Mappers/SearchResultMapper.cs
rename to src/Cogworks.AzureSearch/src/Mappers/SearchResultMapper.cs
diff --git a/src/Cogworks.AzureSearch/Models/Dtos/BatchDocumentsOperationResult.cs b/src/Cogworks.AzureSearch/src/Models/Dtos/BatchDocumentsOperationResult.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Models/Dtos/BatchDocumentsOperationResult.cs
rename to src/Cogworks.AzureSearch/src/Models/Dtos/BatchDocumentsOperationResult.cs
diff --git a/src/Cogworks.AzureSearch/Models/Dtos/DocumentOperationResult.cs b/src/Cogworks.AzureSearch/src/Models/Dtos/DocumentOperationResult.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Models/Dtos/DocumentOperationResult.cs
rename to src/Cogworks.AzureSearch/src/Models/Dtos/DocumentOperationResult.cs
diff --git a/src/Cogworks.AzureSearch/Models/Dtos/IndexOperationResult.cs b/src/Cogworks.AzureSearch/src/Models/Dtos/IndexOperationResult.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Models/Dtos/IndexOperationResult.cs
rename to src/Cogworks.AzureSearch/src/Models/Dtos/IndexOperationResult.cs
diff --git a/src/Cogworks.AzureSearch/Models/Dtos/SearchResult.cs b/src/Cogworks.AzureSearch/src/Models/Dtos/SearchResult.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Models/Dtos/SearchResult.cs
rename to src/Cogworks.AzureSearch/src/Models/Dtos/SearchResult.cs
diff --git a/src/Cogworks.AzureSearch/Models/Dtos/SearchResultItem.cs b/src/Cogworks.AzureSearch/src/Models/Dtos/SearchResultItem.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Models/Dtos/SearchResultItem.cs
rename to src/Cogworks.AzureSearch/src/Models/Dtos/SearchResultItem.cs
diff --git a/src/Cogworks.AzureSearch/Models/IModel.cs b/src/Cogworks.AzureSearch/src/Models/IModel.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Models/IModel.cs
rename to src/Cogworks.AzureSearch/src/Models/IModel.cs
diff --git a/src/Cogworks.AzureSearch/Models/IModelIdentity.cs b/src/Cogworks.AzureSearch/src/Models/IModelIdentity.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Models/IModelIdentity.cs
rename to src/Cogworks.AzureSearch/src/Models/IModelIdentity.cs
diff --git a/src/Cogworks.AzureSearch/Models/IndexDefinition.cs b/src/Cogworks.AzureSearch/src/Models/IndexDefinition.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Models/IndexDefinition.cs
rename to src/Cogworks.AzureSearch/src/Models/IndexDefinition.cs
diff --git a/src/Cogworks.AzureSearch/Models/SearchParameters.cs b/src/Cogworks.AzureSearch/src/Models/SearchParameters.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Models/SearchParameters.cs
rename to src/Cogworks.AzureSearch/src/Models/SearchParameters.cs
diff --git a/src/Cogworks.AzureSearch/Operations/DocumentOperation.cs b/src/Cogworks.AzureSearch/src/Operations/DocumentOperation.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Operations/DocumentOperation.cs
rename to src/Cogworks.AzureSearch/src/Operations/DocumentOperation.cs
diff --git a/src/Cogworks.AzureSearch/Operations/IndexOperation.cs b/src/Cogworks.AzureSearch/src/Operations/IndexOperation.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Operations/IndexOperation.cs
rename to src/Cogworks.AzureSearch/src/Operations/IndexOperation.cs
diff --git a/src/Cogworks.AzureSearch/Options/ClientOption.cs b/src/Cogworks.AzureSearch/src/Options/ClientOption.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Options/ClientOption.cs
rename to src/Cogworks.AzureSearch/src/Options/ClientOption.cs
diff --git a/src/Cogworks.AzureSearch/Options/IndexOption.cs b/src/Cogworks.AzureSearch/src/Options/IndexOption.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Options/IndexOption.cs
rename to src/Cogworks.AzureSearch/src/Options/IndexOption.cs
diff --git a/src/Cogworks.AzureSearch/Repositories/Repository.cs b/src/Cogworks.AzureSearch/src/Repositories/Repository.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Repositories/Repository.cs
rename to src/Cogworks.AzureSearch/src/Repositories/Repository.cs
diff --git a/src/Cogworks.AzureSearch/Searchers/BaseDomainSearch.cs b/src/Cogworks.AzureSearch/src/Searchers/BaseDomainSearch.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Searchers/BaseDomainSearch.cs
rename to src/Cogworks.AzureSearch/src/Searchers/BaseDomainSearch.cs
diff --git a/src/Cogworks.AzureSearch/Searchers/Searcher.cs b/src/Cogworks.AzureSearch/src/Searchers/Searcher.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Searchers/Searcher.cs
rename to src/Cogworks.AzureSearch/src/Searchers/Searcher.cs
diff --git a/src/Cogworks.AzureSearch/Wrappers/DocumentOperationWrapper.cs b/src/Cogworks.AzureSearch/src/Wrappers/DocumentOperationWrapper.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Wrappers/DocumentOperationWrapper.cs
rename to src/Cogworks.AzureSearch/src/Wrappers/DocumentOperationWrapper.cs
diff --git a/src/Cogworks.AzureSearch/Wrappers/IndexOperationWrapper.cs b/src/Cogworks.AzureSearch/src/Wrappers/IndexOperationWrapper.cs
similarity index 100%
rename from src/Cogworks.AzureSearch/Wrappers/IndexOperationWrapper.cs
rename to src/Cogworks.AzureSearch/src/Wrappers/IndexOperationWrapper.cs
diff --git a/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Cogworks.AzureSearch.UnitTests.csproj b/src/Cogworks.AzureSearch/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Cogworks.AzureSearch.UnitTests.csproj
similarity index 98%
rename from tests/UnitTests/Cogworks.AzureSearch.UnitTests/Cogworks.AzureSearch.UnitTests.csproj
rename to src/Cogworks.AzureSearch/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Cogworks.AzureSearch.UnitTests.csproj
index b1ab222..af3a3ab 100644
--- a/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Cogworks.AzureSearch.UnitTests.csproj
+++ b/src/Cogworks.AzureSearch/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Cogworks.AzureSearch.UnitTests.csproj
@@ -46,6 +46,6 @@
-
+
\ No newline at end of file
diff --git a/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Models/TestDocumentModel.cs b/src/Cogworks.AzureSearch/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Models/TestDocumentModel.cs
similarity index 100%
rename from tests/UnitTests/Cogworks.AzureSearch.UnitTests/Models/TestDocumentModel.cs
rename to src/Cogworks.AzureSearch/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Models/TestDocumentModel.cs
diff --git a/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Models/TestResponse.cs b/src/Cogworks.AzureSearch/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Models/TestResponse.cs
similarity index 100%
rename from tests/UnitTests/Cogworks.AzureSearch.UnitTests/Models/TestResponse.cs
rename to src/Cogworks.AzureSearch/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Models/TestResponse.cs
diff --git a/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Operations/DocumentOperationTests.cs b/src/Cogworks.AzureSearch/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Operations/DocumentOperationTests.cs
similarity index 100%
rename from tests/UnitTests/Cogworks.AzureSearch.UnitTests/Operations/DocumentOperationTests.cs
rename to src/Cogworks.AzureSearch/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Operations/DocumentOperationTests.cs
diff --git a/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Operations/IndexOperationTests.cs b/src/Cogworks.AzureSearch/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Operations/IndexOperationTests.cs
similarity index 100%
rename from tests/UnitTests/Cogworks.AzureSearch.UnitTests/Operations/IndexOperationTests.cs
rename to src/Cogworks.AzureSearch/tests/UnitTests/Cogworks.AzureSearch.UnitTests/Operations/IndexOperationTests.cs
diff --git a/tests/UnitTests/Cogworks.AzureSearch.UnitTests/TestBase.cs b/src/Cogworks.AzureSearch/tests/UnitTests/Cogworks.AzureSearch.UnitTests/TestBase.cs
similarity index 100%
rename from tests/UnitTests/Cogworks.AzureSearch.UnitTests/TestBase.cs
rename to src/Cogworks.AzureSearch/tests/UnitTests/Cogworks.AzureSearch.UnitTests/TestBase.cs
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/src/Builders/ContainerBuilder.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/src/Builders/ContainerBuilder.cs
new file mode 100644
index 0000000..f15b89c
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/src/Builders/ContainerBuilder.cs
@@ -0,0 +1,157 @@
+using Autofac;
+using Azure.Search.Documents.Indexes.Models;
+using Cogworks.AzureSearch.Indexes;
+using Cogworks.AzureSearch.Initializers;
+using Cogworks.AzureSearch.Interfaces.Builder;
+using Cogworks.AzureSearch.Interfaces.Indexes;
+using Cogworks.AzureSearch.Interfaces.Initializers;
+using Cogworks.AzureSearch.Interfaces.Operations;
+using Cogworks.AzureSearch.Interfaces.Repositories;
+using Cogworks.AzureSearch.Interfaces.Searches;
+using Cogworks.AzureSearch.Interfaces.Wrappers;
+using Cogworks.AzureSearch.Models;
+using Cogworks.AzureSearch.Operations;
+using Cogworks.AzureSearch.Options;
+using Cogworks.AzureSearch.Repositories;
+using Cogworks.AzureSearch.Searchers;
+using Cogworks.AzureSearch.Wrappers;
+using AutofacContainerBuilder = Autofac.ContainerBuilder;
+
+namespace Cogworks.AzureSearch.IoC.Autofac.Builders
+{
+
+ public class ContainerBuilder : IContainerBuilder
+ {
+ private readonly AutofacContainerBuilder _builder;
+
+ public ContainerBuilder(AutofacContainerBuilder builder)
+ => _builder = builder;
+
+ internal ContainerBuilder RegisterInitializers()
+ {
+ _builder.RegisterGeneric(typeof(Initializer<>))
+ .As(typeof(IInitializer<>))
+ .InstancePerDependency();
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterIndexOptions(bool recreate, bool recreateOnUpdateFailure = false)
+ {
+ _ = _builder.Register(_ => new IndexOption(recreate, recreateOnUpdateFailure))
+ .AsSelf()
+ .SingleInstance();
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterClientOptions(string serviceName, string credentials,
+ string serviceEndpointUrl, bool searchHeaders = false)
+ {
+ _ = _builder.Register(_ => new ClientOption(
+ serviceName,
+ credentials,
+ serviceEndpointUrl))
+ .AsSelf()
+ .SingleInstance();
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterIndexDefinitions(string indexName)
+ where TDocument : class, IModel, new()
+ {
+ _ = _builder.Register(_ => new IndexDefinition(indexName))
+ .AsSelf()
+ .SingleInstance();
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterIndexDefinitions(SearchIndex customIndex)
+ where TDocument : class, IModel, new()
+ {
+ _ = _builder.Register(_ => new IndexDefinition(customIndex))
+ .AsSelf()
+ .SingleInstance();
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterIndexes()
+ {
+ _ = _builder.RegisterGeneric(typeof(Index<>))
+ .As(typeof(IIndex<>))
+ .InstancePerDependency();
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterWrappers()
+ {
+ _ = _builder.RegisterGeneric(typeof(DocumentOperationWrapper<>))
+ .As(typeof(IDocumentOperationWrapper<>))
+ .InstancePerDependency();
+
+ _ = _builder.RegisterType()
+ .AsImplementedInterfaces()
+ .InstancePerDependency();
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterRepositories()
+ {
+ _ = _builder.RegisterGeneric(typeof(Repository<>))
+ .As(typeof(IRepository<>))
+ .InstancePerDependency();
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterSearchers()
+ {
+ _ = _builder.RegisterGeneric(typeof(Searcher<>))
+ .As(typeof(ISearcher<>))
+ .InstancePerDependency();
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterOperations()
+ {
+ _ = _builder.RegisterGeneric(typeof(DocumentOperation<>))
+ .As(typeof(IDocumentOperation<>))
+ .InstancePerDependency();
+
+ _ = _builder.RegisterGeneric(typeof(IndexOperation<>))
+ .As(typeof(IIndexOperation<>))
+ .InstancePerDependency();
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterDomainSearcher()
+ where TDocument : class, IModel, new()
+ where TSearcher : BaseDomainSearch, TSearcherType
+ where TSearcherType : class
+ {
+ _ = _builder.RegisterType()
+ .As()
+ .AsSelf()
+ .SingleInstance();
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterDomainSearcher(TSearcherType instance)
+ where TDocument : class, IModel, new()
+ where TSearcher : BaseDomainSearch, TSearcherType
+ where TSearcherType : class
+ {
+ _ = _builder.RegisterInstance(instance).As();
+
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/src/Cogworks.AzureSearch.IoC.Autofac.csproj b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/src/Cogworks.AzureSearch.IoC.Autofac.csproj
new file mode 100644
index 0000000..e6100b7
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/src/Cogworks.AzureSearch.IoC.Autofac.csproj
@@ -0,0 +1,13 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/src/Cogworks.AzureSearch.IoC.Autofac.nuspec b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/src/Cogworks.AzureSearch.IoC.Autofac.nuspec
new file mode 100644
index 0000000..1969f39
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/src/Cogworks.AzureSearch.IoC.Autofac.nuspec
@@ -0,0 +1,27 @@
+
+
+
+ Cogworks.AzureSearch.IoC.Autofac
+ $version$
+ Cogworks.AzureSearch.IoC.Autofac
+ Cogworks
+ Cogworks
+ https://github.com/thecogworks/Cogworks.AzureSearch.IoC.Autofac
+
+ Apache-2.0
+ false
+ An Autofac extension to Cogworks.AzureSearch.
+ The Cogworks Limited $CopyrightYear$
+ Azure Search, Autofac, container, IoC
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/src/Extensions/AutofacExtensions.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/src/Extensions/AutofacExtensions.cs
new file mode 100644
index 0000000..576ffca
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/src/Extensions/AutofacExtensions.cs
@@ -0,0 +1,17 @@
+using Cogworks.AzureSearch.IoC.Autofac.Builders;
+using AutofacContainerBuilder = Autofac.ContainerBuilder;
+
+namespace Cogworks.AzureSearch.IoC.Autofac.Extensions
+{
+ public static class AutofacExtensions
+ {
+ public static ContainerBuilder RegisterAzureSearch(this AutofacContainerBuilder builder)
+ => new ContainerBuilder(builder)
+ .RegisterRepositories()
+ .RegisterIndexes()
+ .RegisterSearchers()
+ .RegisterInitializers()
+ .RegisterWrappers()
+ .RegisterOperations();
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/AutofacIocExtensionTests.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/AutofacIocExtensionTests.cs
new file mode 100644
index 0000000..8094262
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/AutofacIocExtensionTests.cs
@@ -0,0 +1,223 @@
+using System;
+using Autofac;
+using Azure.Search.Documents.Indexes.Models;
+using Cogworks.AzureSearch.Interfaces.Builder;
+using Cogworks.AzureSearch.Interfaces.Indexes;
+using Cogworks.AzureSearch.Interfaces.Initializers;
+using Cogworks.AzureSearch.Interfaces.Operations;
+using Cogworks.AzureSearch.Interfaces.Repositories;
+using Cogworks.AzureSearch.Interfaces.Searches;
+using Cogworks.AzureSearch.IoC.Autofac.Extensions;
+using Cogworks.AzureSearch.IoC.Autofac.UnitTests.Models;
+using Cogworks.AzureSearch.IoC.Autofac.UnitTests.Searchers;
+using Cogworks.AzureSearch.Models;
+using NSubstitute;
+using Xunit;
+using AutofacContainerBuilder = Autofac.ContainerBuilder;
+
+namespace Cogworks.AzureSearch.IoC.Autofac.UnitTests
+{
+ public class AutofacIocExtensionTests
+ {
+ private readonly IContainerBuilder _containerBuilder;
+ private readonly AutofacContainerBuilder _autofacContainerBuilder;
+
+ private const string FirstDocumentIndexName = "first-test-document";
+ private const string SecondDocumentIndexName = "second-test-document";
+ private const string ThirdDocumentIndexName = "third-test-document";
+
+ public AutofacIocExtensionTests()
+ {
+ _autofacContainerBuilder = new AutofacContainerBuilder();
+
+ _containerBuilder = _autofacContainerBuilder.RegisterAzureSearch()
+ .RegisterClientOptions("test", "test", "https://localhost")
+ .RegisterIndexOptions(false, false)
+ .RegisterIndexDefinitions(FirstDocumentIndexName)
+ .RegisterIndexDefinitions(SecondDocumentIndexName)
+ .RegisterIndexDefinitions(customIndex: new SearchIndex(ThirdDocumentIndexName));
+ }
+
+ [Theory]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ public void Should_ReturnDedicatedRepositoryInstance(Type desiredObjectType)
+ {
+ // Arrange
+
+ // ReSharper disable once PossibleNullReferenceException
+ using (var scope = _autofacContainerBuilder.Build().BeginLifetimeScope().BeginLifetimeScope())
+ {
+ // Act
+ var instance = scope.Resolve(desiredObjectType);
+
+ // Assert
+ Assert.NotNull(instance);
+ Assert.True(desiredObjectType.IsInstanceOfType(instance));
+ Assert.NotEmpty(instance.GetType().GenericTypeArguments);
+ Assert.Equal(desiredObjectType.GenericTypeArguments[0], instance.GetType().GenericTypeArguments[0]);
+ }
+ }
+
+ [Theory]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ public void Should_Not_ThrowException_When_IndexRegistered(Type desiredObjectType)
+ {
+ // Arrange
+ // Act
+ var exceptionRecord = Record.Exception(() => Should_ReturnDedicatedRepositoryInstance(desiredObjectType));
+
+ // Assert
+ Assert.Null(exceptionRecord);
+ }
+
+ [Theory]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ public void Should_ThrowException_When_IndexNotRegistered(Type desiredObjectType)
+ {
+ // NotRegisteredTestDocumentModel
+ // Arrange
+
+ // Act
+ var exceptionRecord = Record.Exception(() =>
+ {
+ // ReSharper disable once PossibleNullReferenceException
+ using (var scope = _autofacContainerBuilder.Build().BeginLifetimeScope())
+ {
+ // Act
+ _ = scope.Resolve(desiredObjectType);
+ }
+ });
+
+ // Assert
+ Assert.NotNull(exceptionRecord);
+ }
+
+ [Fact]
+ public void Should_Not_ThrowException_When_GettingCustomSearchService()
+ {
+ // Arrange
+ // Act
+ var exceptionRecord = Record.Exception(Should_ReturnCustomSearchService);
+
+ // Assert
+ Assert.Null(exceptionRecord);
+ }
+
+ [Fact]
+ public void Should_ReturnCustomSearchService()
+ {
+ // Arrange
+ _containerBuilder.RegisterDomainSearcher();
+
+ // ReSharper disable once PossibleNullReferenceException
+ using (var scope = _autofacContainerBuilder.Build().BeginLifetimeScope())
+ {
+
+ var customTestSearch = scope.Resolve();
+
+ // Assert
+ Assert.NotNull(customTestSearch);
+
+
+ }
+ }
+
+ [Fact]
+ public void Should_InvokeCustomSearchServiceDomainMethod()
+ {
+ // Arrange
+ var mockedCustomTestSearch = Substitute.For();
+
+ _containerBuilder.RegisterDomainSearcher(mockedCustomTestSearch);
+
+ // ReSharper disable once PossibleNullReferenceException
+ using (var scope = _autofacContainerBuilder.Build().BeginLifetimeScope())
+ {
+ var customTestSearch = scope.Resolve();
+
+ customTestSearch.SomeCustomSearchExample();
+
+ // Assert
+ Assert.NotNull(customTestSearch);
+
+ mockedCustomTestSearch.Received(1).SomeCustomSearchExample();
+
+ customTestSearch.SomeCustomSearchExample();
+
+ mockedCustomTestSearch.Received(2).SomeCustomSearchExample();
+ }
+ }
+
+ [Fact]
+ public void Should_Not_ThrowException_When_GettingDedicatedIndexWithProperName()
+ {
+ // Arrange
+ // Act
+ var exceptionRecord = Record.Exception(Should_GetDedicatedIndexWithProperName);
+
+ // Assert
+ Assert.Null(exceptionRecord);
+ }
+
+ [Fact]
+ public void Should_GetDedicatedIndexWithProperName()
+ {
+ // Arrange
+ // Act
+
+ // ReSharper disable once PossibleNullReferenceException
+ using (var scope = _autofacContainerBuilder.Build().BeginLifetimeScope())
+ {
+ var firstTestDocumentIndexDefinition = scope.Resolve>();
+ var secondTestDocumentIndexDefinition = scope.Resolve>();
+ var thirdTestDocumentIndexDefinition = scope.Resolve>();
+
+ // Assert
+ Assert.NotNull(firstTestDocumentIndexDefinition);
+ Assert.NotNull(secondTestDocumentIndexDefinition);
+ Assert.Equal(FirstDocumentIndexName, firstTestDocumentIndexDefinition.IndexName);
+ Assert.Equal(SecondDocumentIndexName, secondTestDocumentIndexDefinition.IndexName);
+ Assert.Equal(ThirdDocumentIndexName, thirdTestDocumentIndexDefinition.IndexName);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests.csproj b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests.csproj
new file mode 100644
index 0000000..cbe3235
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests.csproj
@@ -0,0 +1,41 @@
+
+
+
+ netcoreapp3.1
+
+ false
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Models/FirstTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Models/FirstTestDocumentModel.cs
new file mode 100644
index 0000000..f8d21a4
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Models/FirstTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.Autofac.UnitTests.Models
+{
+ public class FirstTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField()]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField()]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Models/NotRegistredTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Models/NotRegistredTestDocumentModel.cs
new file mode 100644
index 0000000..2560da2
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Models/NotRegistredTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.Autofac.UnitTests.Models
+{
+ public class NotRegisteredTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField()]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField()]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Models/SecondTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Models/SecondTestDocumentModel.cs
new file mode 100644
index 0000000..a1737af
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Models/SecondTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.Autofac.UnitTests.Models
+{
+ public class SecondTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField()]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField()]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Models/ThirdTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Models/ThirdTestDocumentModel.cs
new file mode 100644
index 0000000..65adeea
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Models/ThirdTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.Autofac.UnitTests.Models
+{
+ public class ThirdTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField()]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField()]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Searchers/CustomTestSearch.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Searchers/CustomTestSearch.cs
new file mode 100644
index 0000000..44a6440
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Autofac/tests/UnitTests/Cogworks.AzureSearch.IoC.Autofac.UnitTests/Searchers/CustomTestSearch.cs
@@ -0,0 +1,27 @@
+using Cogworks.AzureSearch.Interfaces.Searches;
+using Cogworks.AzureSearch.IoC.Autofac.UnitTests.Models;
+using Cogworks.AzureSearch.Searchers;
+
+namespace Cogworks.AzureSearch.IoC.Autofac.UnitTests.Searchers
+{
+ public interface ICustomTestSearch
+ {
+ void SomeCustomSearchExample();
+ }
+
+ public class CustomTestSearch : BaseDomainSearch, ICustomTestSearch
+ {
+ public CustomTestSearch(ISearcher search) : base(search)
+ {
+ }
+
+ public void SomeCustomSearchExample()
+ {
+ // Start of custom filters/logic
+ // ...
+ // End of custom filters
+
+ // _ = base.Search("test", new SearchParameters());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/src/Builders/ContainerBuilder.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/src/Builders/ContainerBuilder.cs
new file mode 100644
index 0000000..ae027ee
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/src/Builders/ContainerBuilder.cs
@@ -0,0 +1,151 @@
+using Azure.Search.Documents.Indexes.Models;
+using Cogworks.AzureSearch.Indexes;
+using Cogworks.AzureSearch.Initializers;
+using Cogworks.AzureSearch.Interfaces.Builder;
+using Cogworks.AzureSearch.Interfaces.Indexes;
+using Cogworks.AzureSearch.Interfaces.Initializers;
+using Cogworks.AzureSearch.Interfaces.Operations;
+using Cogworks.AzureSearch.Interfaces.Repositories;
+using Cogworks.AzureSearch.Interfaces.Searches;
+using Cogworks.AzureSearch.Interfaces.Wrappers;
+using Cogworks.AzureSearch.Models;
+using Cogworks.AzureSearch.Operations;
+using Cogworks.AzureSearch.Options;
+using Cogworks.AzureSearch.Repositories;
+using Cogworks.AzureSearch.Searchers;
+using Cogworks.AzureSearch.Wrappers;
+using LightInject;
+
+namespace Cogworks.AzureSearch.IoC.LightInject.Builders
+{
+ public class ContainerBuilder : IContainerBuilder
+ {
+ private readonly IServiceContainer _container;
+
+ public ContainerBuilder(IServiceContainer serviceContainer)
+ => _container = serviceContainer;
+
+ internal ContainerBuilder RegisterInitializers()
+ {
+ _ = _container.Register(
+ typeof(IInitializer<>),
+ typeof(Initializer<>));
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterIndexOptions(bool recreate, bool recreateOnUpdateFailure = false)
+ {
+ _ = _container.Register(
+ _ => new IndexOption(recreate, recreateOnUpdateFailure),
+ new PerContainerLifetime());
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterClientOptions(string serviceName, string credentials, string serviceEndpointUrl, bool searchHeaders = false)
+ {
+ _ = _container.Register(
+ _ => new ClientOption(
+ serviceName,
+ credentials,
+ serviceEndpointUrl,
+ searchHeaders),
+ new PerContainerLifetime());
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterIndexDefinitions(string indexName)
+ where TDocument : class, IModel, new()
+ {
+ _ = _container.Register(
+ _ => new IndexDefinition(indexName),
+ new PerContainerLifetime());
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterIndexDefinitions(SearchIndex customIndex)
+ where TDocument : class, IModel, new()
+ {
+ _ = _container.Register(
+ _ => new IndexDefinition(customIndex),
+ new PerContainerLifetime());
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterIndexes()
+ {
+ _ = _container.Register(
+ typeof(IIndex<>),
+ typeof(Index<>));
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterWrappers()
+ {
+ _ = _container.Register(
+ typeof(IDocumentOperationWrapper<>),
+ typeof(DocumentOperationWrapper<>));
+
+ _ = _container.Register();
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterRepositories()
+ {
+ _ = _container.Register(
+ typeof(IRepository<>),
+ typeof(Repository<>));
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterSearchers()
+ {
+ _ = _container.Register(
+ typeof(ISearcher<>),
+ typeof(Searcher<>));
+
+ return this;
+ }
+ internal ContainerBuilder RegisterOperations()
+ {
+ _ = _container.Register(
+ typeof(IDocumentOperation<>),
+ typeof(DocumentOperation<>),
+ new PerContainerLifetime());
+
+ _ = _container.Register(
+ typeof(IIndexOperation<>),
+ typeof(IndexOperation<>),
+ new PerContainerLifetime());
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterDomainSearcher()
+ where TDocument : class, IModel, new()
+ where TSearcher : BaseDomainSearch, TSearcherType
+ where TSearcherType : class
+ {
+ _ = _container.Register(typeof(TSearcherType), typeof(TSearcher), new PerContainerLifetime());
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterDomainSearcher(TSearcherType instance)
+ where TDocument : class, IModel, new()
+ where TSearcher : BaseDomainSearch, TSearcherType
+ where TSearcherType : class
+ {
+ _ = _container.RegisterInstance(instance); ;
+
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/src/Cogworks.AzureSearch.IoC.LightInject.csproj b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/src/Cogworks.AzureSearch.IoC.LightInject.csproj
new file mode 100644
index 0000000..7c50bba
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/src/Cogworks.AzureSearch.IoC.LightInject.csproj
@@ -0,0 +1,21 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/src/Cogworks.AzureSearch.IoC.LightInject.nuspec b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/src/Cogworks.AzureSearch.IoC.LightInject.nuspec
new file mode 100644
index 0000000..b7a865b
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/src/Cogworks.AzureSearch.IoC.LightInject.nuspec
@@ -0,0 +1,26 @@
+
+
+
+ Cogworks.AzureSearch.IoC.LightInject
+ $version$
+ Cogworks.AzureSearch.IoC.LightInject
+ Cogworks
+ Cogworks
+ https://github.com/thecogworks/Cogworks.AzureSearch.IoC.LightInject
+
+ Apache-2.0
+ false
+ An LightInject extension to Cogworks.AzureSearch.
+ The Cogworks Limited $CopyrightYear$
+ Azure Search, LightInject, container, IoC
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/src/Extensions/RegisterExtensions.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/src/Extensions/RegisterExtensions.cs
new file mode 100644
index 0000000..17dd5e9
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/src/Extensions/RegisterExtensions.cs
@@ -0,0 +1,17 @@
+using Cogworks.AzureSearch.IoC.LightInject.Builders;
+using LightInject;
+
+namespace Cogworks.AzureSearch.IoC.LightInject.Extensions
+{
+ public static class RegisterExtensions
+ {
+ public static ContainerBuilder RegisterAzureSearch(this IServiceContainer serviceContainer)
+ => new ContainerBuilder(serviceContainer)
+ .RegisterRepositories()
+ .RegisterIndexes()
+ .RegisterSearchers()
+ .RegisterInitializers()
+ .RegisterWrappers()
+ .RegisterOperations();
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests.csproj b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests.csproj
new file mode 100644
index 0000000..edb9a4a
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests.csproj
@@ -0,0 +1,40 @@
+
+
+
+ netcoreapp3.1
+
+ false
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/LightInjectIocExtensionTests.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/LightInjectIocExtensionTests.cs
new file mode 100644
index 0000000..0f2d502
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/LightInjectIocExtensionTests.cs
@@ -0,0 +1,218 @@
+using System;
+using Azure.Search.Documents.Indexes.Models;
+using Cogworks.AzureSearch.Interfaces.Builder;
+using Cogworks.AzureSearch.Interfaces.Indexes;
+using Cogworks.AzureSearch.Interfaces.Initializers;
+using Cogworks.AzureSearch.Interfaces.Operations;
+using Cogworks.AzureSearch.Interfaces.Repositories;
+using Cogworks.AzureSearch.Interfaces.Searches;
+using Cogworks.AzureSearch.IoC.LightInject.Extensions;
+using Cogworks.AzureSearch.IoC.LightInject.UnitTests.Models;
+using Cogworks.AzureSearch.IoC.LightInject.UnitTests.Searchers;
+using Cogworks.AzureSearch.Models;
+using LightInject;
+using NSubstitute;
+using Xunit;
+
+namespace Cogworks.AzureSearch.IoC.LightInject.UnitTests
+{
+ public class LightInjectIocExtensionTests
+ {
+ private readonly IContainerBuilder _containerBuilder;
+ private readonly IServiceContainer _container;
+
+ private const string FirstDocumentIndexName = "first-test-document";
+ private const string SecondDocumentIndexName = "second-test-document";
+ private const string ThirdDocumentIndexName = "third-test-document";
+
+ public LightInjectIocExtensionTests()
+ {
+ _container = new ServiceContainer();
+
+ _containerBuilder = _container.RegisterAzureSearch()
+ .RegisterClientOptions("test", "test", "https://localhost")
+ .RegisterIndexOptions(false, false)
+ .RegisterIndexDefinitions(FirstDocumentIndexName)
+ .RegisterIndexDefinitions(SecondDocumentIndexName)
+ .RegisterIndexDefinitions(customIndex: new SearchIndex(ThirdDocumentIndexName)); ;
+ }
+
+ [Theory]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ public void Should_ReturnDedicatedRepositoryInstance(Type desiredObjectType)
+ {
+ // Arrange
+
+ // ReSharper disable once PossibleNullReferenceException
+ using (var scope = _container.BeginScope())
+ {
+ // Act
+ var instance = scope.GetInstance(desiredObjectType);
+
+ // Assert
+ Assert.NotNull(instance);
+ Assert.True(desiredObjectType.IsInstanceOfType(instance));
+ Assert.NotEmpty(instance.GetType().GenericTypeArguments);
+ Assert.Equal(desiredObjectType.GenericTypeArguments[0], instance.GetType().GenericTypeArguments[0]);
+ }
+ }
+
+ [Theory]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ public void Should_Not_ThrowException_When_IndexRegistered(Type desiredObjectType)
+ {
+ // Arrange
+ // Act
+ var exceptionRecord = Record.Exception(() => Should_ReturnDedicatedRepositoryInstance(desiredObjectType));
+
+ // Assert
+ Assert.Null(exceptionRecord);
+ }
+
+ [Theory]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ public void Should_ThrowException_When_IndexNotRegistered(Type desiredObjectType)
+ {
+ // Arrange
+ // Act
+ var exceptionRecord = Record.Exception(() =>
+ {
+ // ReSharper disable once PossibleNullReferenceException
+ using (var scope = _container.BeginScope())
+ {
+ // Act
+ _ = scope.GetInstance(desiredObjectType);
+ }
+ });
+
+ // Assert
+ Assert.NotNull(exceptionRecord);
+ }
+
+ [Fact]
+ public void Should_Not_ThrowException_When_GettingCustomSearchService()
+ {
+ // Arrange
+ // Act
+ var exceptionRecord = Record.Exception(Should_ReturnCustomSearchService);
+
+ // Assert
+ Assert.Null(exceptionRecord);
+ }
+
+ [Fact]
+ public void Should_ReturnCustomSearchService()
+ {
+ // Arrange
+ _containerBuilder.RegisterDomainSearcher();
+
+ // ReSharper disable once PossibleNullReferenceException
+ using (var scope = _container.BeginScope())
+ {
+ var customTestSearch = scope.GetInstance();
+
+ // Assert
+ Assert.NotNull(customTestSearch);
+ }
+ }
+
+ [Fact]
+ public void Should_InvokeCustomSearchServiceDomainMethod()
+ {
+ // Arrange
+ var mockedCustomTestSearch = Substitute.For();
+
+ _containerBuilder.RegisterDomainSearcher(mockedCustomTestSearch);
+
+ // ReSharper disable once PossibleNullReferenceException
+ using (var scope = _container.BeginScope())
+ {
+ var customTestSearch = scope.GetInstance();
+
+ customTestSearch.SomeCustomSearchExample();
+
+ // Assert
+ Assert.NotNull(customTestSearch);
+
+ mockedCustomTestSearch.Received(1).SomeCustomSearchExample();
+
+ customTestSearch.SomeCustomSearchExample();
+
+ mockedCustomTestSearch.Received(2).SomeCustomSearchExample();
+ }
+ }
+
+ [Fact]
+ public void Should_Not_ThrowException_When_GettingDedicatedIndexWithProperName()
+ {
+ // Arrange
+ // Act
+ var exceptionRecord = Record.Exception(Should_GetDedicatedIndexWithProperName);
+
+ // Assert
+ Assert.Null(exceptionRecord);
+ }
+
+ [Fact]
+ public void Should_GetDedicatedIndexWithProperName()
+ {
+ // Arrange
+ // Act
+
+ // ReSharper disable once PossibleNullReferenceException
+ using (var scope = _container.BeginScope())
+ {
+ var firstTestDocumentIndexDefinition = scope.GetInstance>();
+ var secondTestDocumentIndexDefinition = scope.GetInstance>();
+ var thirdTestDocumentIndexDefinition = scope.GetInstance>();
+
+ // Assert
+ Assert.NotNull(firstTestDocumentIndexDefinition);
+ Assert.NotNull(secondTestDocumentIndexDefinition);
+ Assert.NotNull(thirdTestDocumentIndexDefinition);
+ Assert.Equal(FirstDocumentIndexName, firstTestDocumentIndexDefinition.IndexName);
+ Assert.Equal(SecondDocumentIndexName, secondTestDocumentIndexDefinition.IndexName);
+ Assert.Equal(ThirdDocumentIndexName, thirdTestDocumentIndexDefinition.IndexName);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Models/FirstTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Models/FirstTestDocumentModel.cs
new file mode 100644
index 0000000..64c4c7b
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Models/FirstTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.LightInject.UnitTests.Models
+{
+ public class FirstTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField()]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField()]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Models/NotRegistredTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Models/NotRegistredTestDocumentModel.cs
new file mode 100644
index 0000000..ffc3da5
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Models/NotRegistredTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.LightInject.UnitTests.Models
+{
+ public class NotRegisteredTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField()]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField()]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Models/SecondTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Models/SecondTestDocumentModel.cs
new file mode 100644
index 0000000..29b1798
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Models/SecondTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.LightInject.UnitTests.Models
+{
+ public class SecondTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField()]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField()]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Models/ThirdTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Models/ThirdTestDocumentModel.cs
new file mode 100644
index 0000000..83f7a5e
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Models/ThirdTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.LightInject.UnitTests.Models
+{
+ public class ThirdTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField()]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField()]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Searchers/CustomTestSearch.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Searchers/CustomTestSearch.cs
new file mode 100644
index 0000000..8f81388
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.LightInject/tests/UnitTests/Cogworks.AzureSearch.IoC.LightInject.UnitTests/Searchers/CustomTestSearch.cs
@@ -0,0 +1,27 @@
+using Cogworks.AzureSearch.Interfaces.Searches;
+using Cogworks.AzureSearch.IoC.LightInject.UnitTests.Models;
+using Cogworks.AzureSearch.Searchers;
+
+namespace Cogworks.AzureSearch.IoC.LightInject.UnitTests.Searchers
+{
+ public interface ICustomTestSearch
+ {
+ void SomeCustomSearchExample();
+ }
+
+ public class CustomTestSearch : BaseDomainSearch, ICustomTestSearch
+ {
+ public CustomTestSearch(ISearcher search) : base(search)
+ {
+ }
+
+ public void SomeCustomSearchExample()
+ {
+ // Start of custom filters/logic
+ // ...
+ // End of custom filters
+
+ // _ = base.Search("test", new SearchParameters());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/src/Builders/ContainerBuilder.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/src/Builders/ContainerBuilder.cs
new file mode 100644
index 0000000..027fba5
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/src/Builders/ContainerBuilder.cs
@@ -0,0 +1,131 @@
+using Azure.Search.Documents.Indexes.Models;
+using Cogworks.AzureSearch.Indexes;
+using Cogworks.AzureSearch.Initializers;
+using Cogworks.AzureSearch.Interfaces.Builder;
+using Cogworks.AzureSearch.Interfaces.Indexes;
+using Cogworks.AzureSearch.Interfaces.Initializers;
+using Cogworks.AzureSearch.Interfaces.Operations;
+using Cogworks.AzureSearch.Interfaces.Repositories;
+using Cogworks.AzureSearch.Interfaces.Searches;
+using Cogworks.AzureSearch.Interfaces.Wrappers;
+using Cogworks.AzureSearch.Models;
+using Cogworks.AzureSearch.Operations;
+using Cogworks.AzureSearch.Options;
+using Cogworks.AzureSearch.Repositories;
+using Cogworks.AzureSearch.Searchers;
+using Cogworks.AzureSearch.Wrappers;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+
+namespace Cogworks.AzureSearch.IoC.Microsoft.Builders
+{
+ public class ContainerBuilder : IContainerBuilder
+ {
+ private readonly IServiceCollection _serviceCollection;
+
+ public ContainerBuilder(IServiceCollection serviceCollection)
+ => _serviceCollection = serviceCollection;
+
+ internal ContainerBuilder RegisterInitializers()
+ {
+ _serviceCollection.TryAddScoped(typeof(IInitializer<>), typeof(Initializer<>));
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterIndexOptions(bool recreate, bool recreateOnUpdateFailure = false)
+ {
+ _serviceCollection.TryAddSingleton(_ => new IndexOption(recreate, recreateOnUpdateFailure));
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterClientOptions(string serviceName, string credentials,
+ string serviceEndpointUrl, bool searchHeaders = false)
+ {
+ _serviceCollection.TryAddSingleton(_ => new ClientOption(
+ serviceName,
+ credentials,
+ serviceEndpointUrl));
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterIndexDefinitions(string indexName)
+ where TDocument : class, IModel, new()
+ {
+ _serviceCollection.TryAddSingleton(_ => new IndexDefinition(indexName));
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterIndexDefinitions(SearchIndex customIndex)
+ where TDocument : class, IModel, new()
+ {
+ _serviceCollection.TryAddSingleton(_ => new IndexDefinition(customIndex));
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterIndexes()
+ {
+ _serviceCollection.TryAddScoped(typeof(IIndex<>), typeof(Index<>));
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterWrappers()
+ {
+ _serviceCollection.TryAddScoped(typeof(IDocumentOperationWrapper<>), typeof(DocumentOperationWrapper<>));
+
+ _serviceCollection.TryAddScoped();
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterRepositories()
+ {
+ _serviceCollection.TryAddScoped(
+ typeof(IRepository<>),
+ typeof(Repository<>));
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterSearchers()
+ {
+ _serviceCollection.TryAddScoped(typeof(ISearcher<>), typeof(Searcher<>));
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterOperations()
+ {
+ _serviceCollection.TryAddScoped(typeof(IDocumentOperation<>), typeof(DocumentOperation<>));
+
+ _serviceCollection.TryAddScoped(typeof(IIndexOperation<>), typeof(IndexOperation<>));
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterDomainSearcher()
+ where TDocument : class, IModel, new()
+ where TSearcher : BaseDomainSearch, TSearcherType
+ where TSearcherType : class
+ {
+ _serviceCollection.TryAddSingleton();
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterDomainSearcher(TSearcherType instance)
+ where TDocument : class, IModel, new()
+ where TSearcher : BaseDomainSearch, TSearcherType
+ where TSearcherType : class
+ {
+ _serviceCollection.TryAddSingleton(instance);
+
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/src/Cogworks.AzureSearch.IoC.Microsoft.csproj b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/src/Cogworks.AzureSearch.IoC.Microsoft.csproj
new file mode 100644
index 0000000..ab1c0a9
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/src/Cogworks.AzureSearch.IoC.Microsoft.csproj
@@ -0,0 +1,13 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/src/Cogworks.AzureSearch.IoC.Microsoft.nuspec b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/src/Cogworks.AzureSearch.IoC.Microsoft.nuspec
new file mode 100644
index 0000000..cab619a
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/src/Cogworks.AzureSearch.IoC.Microsoft.nuspec
@@ -0,0 +1,27 @@
+
+
+
+ Cogworks.AzureSearch.IoC.Microsoft
+ $version$
+ Cogworks.AzureSearch.IoC.Microsoft
+ Cogworks
+ Cogworks
+ https://github.com/thecogworks/Cogworks.AzureSearch.IoC.Microsoft
+
+ Apache-2.0
+ false
+ An Microsoft DependencyInjection extension to Cogworks.AzureSearch.
+ The Cogworks Limited $CopyrightYear$
+ Azure Search, Microsoft, Dependency Injection, container, IoC
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/src/Extensions/BuilderExtensions.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/src/Extensions/BuilderExtensions.cs
new file mode 100644
index 0000000..c88c026
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/src/Extensions/BuilderExtensions.cs
@@ -0,0 +1,17 @@
+using Cogworks.AzureSearch.IoC.Microsoft.Builders;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Cogworks.AzureSearch.IoC.Microsoft.Extensions
+{
+ public static class BuilderExtensions
+ {
+ public static ContainerBuilder RegisterAzureSearch(this IServiceCollection serviceCollection)
+ => new ContainerBuilder(serviceCollection)
+ .RegisterRepositories()
+ .RegisterIndexes()
+ .RegisterSearchers()
+ .RegisterInitializers()
+ .RegisterWrappers()
+ .RegisterOperations();
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests.csproj b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests.csproj
new file mode 100644
index 0000000..28ae7c4
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests.csproj
@@ -0,0 +1,41 @@
+
+
+
+ netcoreapp3.1
+
+ false
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/MicrosoftIocExtensionTests.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/MicrosoftIocExtensionTests.cs
new file mode 100644
index 0000000..e7da159
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/MicrosoftIocExtensionTests.cs
@@ -0,0 +1,220 @@
+using System;
+using Azure.Search.Documents.Indexes.Models;
+using Cogworks.AzureSearch.Interfaces.Builder;
+using Cogworks.AzureSearch.Interfaces.Indexes;
+using Cogworks.AzureSearch.Interfaces.Initializers;
+using Cogworks.AzureSearch.Interfaces.Operations;
+using Cogworks.AzureSearch.Interfaces.Repositories;
+using Cogworks.AzureSearch.Interfaces.Searches;
+using Cogworks.AzureSearch.IoC.Microsoft.Extensions;
+using Cogworks.AzureSearch.IoC.Microsoft.UnitTests.Models;
+using Cogworks.AzureSearch.IoC.Microsoft.UnitTests.Searchers;
+using Cogworks.AzureSearch.Models;
+using Microsoft.Extensions.DependencyInjection;
+using NSubstitute;
+using Xunit;
+
+namespace Cogworks.AzureSearch.IoC.Microsoft.UnitTests
+{
+ public class MicrosoftIocExtensionTests
+ {
+ private readonly IContainerBuilder _containerBuilder;
+ private readonly IServiceCollection _serviceContainer;
+
+ private const string FirstDocumentIndexName = "first-test-document";
+ private const string SecondDocumentIndexName = "second-test-document";
+ private const string ThirdDocumentIndexName = "third-test-document";
+
+ public MicrosoftIocExtensionTests()
+ {
+ _serviceContainer = new ServiceCollection();
+
+ _containerBuilder = _serviceContainer.RegisterAzureSearch()
+ .RegisterClientOptions("test", "test", "https://localhost")
+ .RegisterIndexOptions(false, false)
+ .RegisterIndexDefinitions(FirstDocumentIndexName)
+ .RegisterIndexDefinitions(SecondDocumentIndexName)
+ .RegisterIndexDefinitions(customIndex: new SearchIndex(ThirdDocumentIndexName));
+ }
+
+ [Theory]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ public void Should_ReturnDedicatedRepositoryInstance(Type desiredObjectType)
+ {
+ // Arrange
+
+ // ReSharper disable once PossibleNullReferenceException
+ using (var serviceProvider = _serviceContainer.BuildServiceProvider())
+ {
+ // Act
+ var instance = serviceProvider.GetService(desiredObjectType);
+
+ // Assert
+ Assert.NotNull(instance);
+ Assert.True(desiredObjectType.IsInstanceOfType(instance));
+ Assert.NotEmpty(instance.GetType().GenericTypeArguments);
+ Assert.Equal(desiredObjectType.GenericTypeArguments[0], instance.GetType().GenericTypeArguments[0]);
+ }
+ }
+
+ [Theory]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ public void Should_Not_ThrowException_When_IndexRegistered(Type desiredObjectType)
+ {
+ // Arrange
+ // Act
+ var exceptionRecord = Record.Exception(() => Should_ReturnDedicatedRepositoryInstance(desiredObjectType));
+
+ // Assert
+ Assert.Null(exceptionRecord);
+ }
+
+ [Theory]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ public void Should_ThrowException_When_IndexNotRegistered(Type desiredObjectType)
+ {
+ // NotRegisteredTestDocumentModel
+ // Arrange
+
+ // Act
+ var exceptionRecord = Record.Exception(() =>
+ {
+ // ReSharper disable once PossibleNullReferenceException
+ using (var serviceProvider = _serviceContainer.BuildServiceProvider())
+ {
+ // Act
+ _ = serviceProvider.GetService(desiredObjectType);
+ }
+ });
+
+ // Assert
+ Assert.NotNull(exceptionRecord);
+ }
+
+ [Fact]
+ public void Should_Not_ThrowException_When_GettingCustomSearchService()
+ {
+ // Arrange
+ // Act
+ var exceptionRecord = Record.Exception(Should_ReturnCustomSearchService);
+
+ // Assert
+ Assert.Null(exceptionRecord);
+ }
+
+ [Fact]
+ public void Should_ReturnCustomSearchService()
+ {
+ // Arrange
+ _containerBuilder.RegisterDomainSearcher();
+
+ // ReSharper disable once PossibleNullReferenceException
+ using (var serviceProvider = _serviceContainer.BuildServiceProvider())
+ {
+ var customTestSearch = serviceProvider.GetService();
+
+ // Assert
+ Assert.NotNull(customTestSearch);
+ }
+ }
+
+ [Fact]
+ public void Should_InvokeCustomSearchServiceDomainMethod()
+ {
+ // Arrange
+ var mockedCustomTestSearch = Substitute.For();
+
+ _containerBuilder.RegisterDomainSearcher(mockedCustomTestSearch);
+
+ // ReSharper disable once PossibleNullReferenceException
+ using (var serviceProvider = _serviceContainer.BuildServiceProvider())
+ {
+ var customTestSearch = serviceProvider.GetService();
+
+ customTestSearch.SomeCustomSearchExample();
+
+ // Assert
+ Assert.NotNull(customTestSearch);
+
+ mockedCustomTestSearch.Received(1).SomeCustomSearchExample();
+
+ customTestSearch.SomeCustomSearchExample();
+
+ mockedCustomTestSearch.Received(2).SomeCustomSearchExample();
+ }
+ }
+
+ [Fact]
+ public void Should_Not_ThrowException_When_GettingDedicatedIndexWithProperName()
+ {
+ // Arrange
+ // Act
+ var exceptionRecord = Record.Exception(Should_GetDedicatedIndexWithProperName);
+
+ // Assert
+ Assert.Null(exceptionRecord);
+ }
+
+ [Fact]
+ public void Should_GetDedicatedIndexWithProperName()
+ {
+ // Arrange
+ // Act
+
+ // ReSharper disable once PossibleNullReferenceException
+ using (var serviceProvider = _serviceContainer.BuildServiceProvider())
+ {
+ var firstTestDocumentIndexDefinition = serviceProvider.GetService>();
+ var secondTestDocumentIndexDefinition = serviceProvider.GetService>();
+ var thirdTestDocumentIndexDefinition = serviceProvider.GetService>();
+
+ // Assert
+ Assert.NotNull(firstTestDocumentIndexDefinition);
+ Assert.NotNull(secondTestDocumentIndexDefinition);
+ Assert.NotNull(thirdTestDocumentIndexDefinition);
+ Assert.Equal(FirstDocumentIndexName, firstTestDocumentIndexDefinition.IndexName);
+ Assert.Equal(SecondDocumentIndexName, secondTestDocumentIndexDefinition.IndexName);
+ Assert.Equal(ThirdDocumentIndexName, thirdTestDocumentIndexDefinition.IndexName);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Models/FirstTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Models/FirstTestDocumentModel.cs
new file mode 100644
index 0000000..12b9c24
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Models/FirstTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.Microsoft.UnitTests.Models
+{
+ public class FirstTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField()]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField()]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Models/NotRegistredTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Models/NotRegistredTestDocumentModel.cs
new file mode 100644
index 0000000..4ec4a69
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Models/NotRegistredTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.Microsoft.UnitTests.Models
+{
+ public class NotRegisteredTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField()]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField()]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Models/SecondTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Models/SecondTestDocumentModel.cs
new file mode 100644
index 0000000..3b0a021
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Models/SecondTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.Microsoft.UnitTests.Models
+{
+ public class SecondTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField()]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField()]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Models/ThirdTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Models/ThirdTestDocumentModel.cs
new file mode 100644
index 0000000..0063cef
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Models/ThirdTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.Microsoft.UnitTests.Models
+{
+ public class ThirdTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField()]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField()]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Searchers/CustomTestSearch.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Searchers/CustomTestSearch.cs
new file mode 100644
index 0000000..9a9fbb8
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Microsoft/tests/UnitTests/Cogworks.AzureSearch.IoC.Microsoft.UnitTests/Searchers/CustomTestSearch.cs
@@ -0,0 +1,27 @@
+using Cogworks.AzureSearch.Interfaces.Searches;
+using Cogworks.AzureSearch.IoC.Microsoft.UnitTests.Models;
+using Cogworks.AzureSearch.Searchers;
+
+namespace Cogworks.AzureSearch.IoC.Microsoft.UnitTests.Searchers
+{
+ public interface ICustomTestSearch
+ {
+ void SomeCustomSearchExample();
+ }
+
+ public class CustomTestSearch : BaseDomainSearch, ICustomTestSearch
+ {
+ public CustomTestSearch(ISearcher search) : base(search)
+ {
+ }
+
+ public void SomeCustomSearchExample()
+ {
+ // Start of custom filters/logic
+ // ...
+ // End of custom filters
+
+ // _ = base.Search("test", new SearchParameters());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/src/Builders/ContainerBuilder.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/src/Builders/ContainerBuilder.cs
new file mode 100644
index 0000000..b7ec1af
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/src/Builders/ContainerBuilder.cs
@@ -0,0 +1,174 @@
+using System;
+using Azure.Search.Documents.Indexes.Models;
+using Cogworks.AzureSearch.Indexes;
+using Cogworks.AzureSearch.Initializers;
+using Cogworks.AzureSearch.Interfaces.Builder;
+using Cogworks.AzureSearch.Interfaces.Indexes;
+using Cogworks.AzureSearch.Interfaces.Initializers;
+using Cogworks.AzureSearch.Interfaces.Operations;
+using Cogworks.AzureSearch.Interfaces.Repositories;
+using Cogworks.AzureSearch.Interfaces.Searches;
+using Cogworks.AzureSearch.Interfaces.Wrappers;
+using Cogworks.AzureSearch.Models;
+using Cogworks.AzureSearch.Operations;
+using Cogworks.AzureSearch.Options;
+using Cogworks.AzureSearch.Repositories;
+using Cogworks.AzureSearch.Searchers;
+using Cogworks.AzureSearch.Wrappers;
+using Microsoft.Extensions.DependencyInjection;
+using Umbraco.Cms.Core.DependencyInjection;
+
+namespace Cogworks.AzureSearch.IoC.Umbraco.Builders
+{
+ public class ContainerBuilder : IContainerBuilder
+ {
+ private readonly IUmbracoBuilder _umbracoBuilder;
+
+ public ContainerBuilder(IUmbracoBuilder umbracoBuilder)
+ => _umbracoBuilder = umbracoBuilder
+ ?? throw new ArgumentNullException(
+ nameof(umbracoBuilder));
+
+ public IContainerBuilder RegisterIndexOptions(bool recreate, bool recreateOnUpdateFailure = false)
+ {
+ _umbracoBuilder
+ .Services
+ .AddSingleton(_ => new IndexOption(recreate, recreateOnUpdateFailure));
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterClientOptions(string serviceName, string credentials,
+ string serviceEndpointUrl, bool searchHeaders = false)
+ {
+ _umbracoBuilder
+ .Services
+ .AddSingleton(
+ _ => new ClientOption(
+ serviceName,
+ credentials,
+ serviceEndpointUrl,
+ searchHeaders));
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterIndexDefinitions(string indexName)
+ where TDocument : class, IModel, new()
+ {
+ _umbracoBuilder
+ .Services
+ .AddSingleton(
+ _ => new IndexDefinition(indexName));
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterIndexDefinitions(SearchIndex customIndex)
+ where TDocument : class, IModel, new()
+ {
+ _umbracoBuilder
+ .Services
+ .AddSingleton(
+ _ => new IndexDefinition(customIndex));
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterDomainSearcher()
+ where TDocument : class, IModel, new()
+ where TSearcher : BaseDomainSearch, TSearcherType
+ where TSearcherType : class
+ {
+ _umbracoBuilder
+ .Services
+ .AddSingleton();
+
+ return this;
+ }
+
+ public IContainerBuilder RegisterDomainSearcher(TSearcherType instance)
+ where TDocument : class, IModel, new()
+ where TSearcher : BaseDomainSearch, TSearcherType
+ where TSearcherType : class
+ {
+ _umbracoBuilder.Services.AddTransient(_ => instance);
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterInitializers()
+ {
+ _umbracoBuilder
+ .Services
+ .AddTransient(typeof(IInitializer<>), typeof(Initializer<>));
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterIndexes()
+ {
+ _umbracoBuilder
+ .Services
+ .AddTransient(
+ typeof(IIndex<>),
+ typeof(Index<>));
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterWrappers()
+ {
+ _umbracoBuilder
+ .Services
+ .AddTransient(
+ typeof(IDocumentOperationWrapper<>),
+ typeof(DocumentOperationWrapper<>));
+
+ _umbracoBuilder
+ .Services
+ .AddTransient();
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterRepositories()
+ {
+ _umbracoBuilder
+ .Services
+ .AddTransient(
+ typeof(IRepository<>),
+ typeof(Repository<>));
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterSearchers()
+ {
+ _umbracoBuilder
+ .Services
+ .AddTransient(
+ typeof(ISearcher<>),
+ typeof(Searcher<>));
+
+ return this;
+ }
+
+ internal ContainerBuilder RegisterOperations()
+ {
+ _umbracoBuilder
+ .Services
+ .AddTransient(
+ typeof(IDocumentOperation<>),
+ typeof(DocumentOperation<>));
+
+ _umbracoBuilder
+ .Services
+ .AddTransient(
+ typeof(IIndexOperation<>),
+ typeof(IndexOperation<>));
+
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/src/Cogworks.AzureSearch.IoC.Umbraco.csproj b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/src/Cogworks.AzureSearch.IoC.Umbraco.csproj
new file mode 100644
index 0000000..bfbccd9
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/src/Cogworks.AzureSearch.IoC.Umbraco.csproj
@@ -0,0 +1,24 @@
+
+
+ net6.0;net5.0
+ .
+ Cogworks.AzureSearch.IoC.Umbraco
+ Cogworks.AzureSearch.IoC.Umbraco
+ An Umbraco extension to Cogworks.AzureSearch.
+ An Umbraco 9 extension to Cogworks.AzureSearch
+ Azure Search Umbraco container IoC
+
+ Apache-2.0
+ README.md
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/src/Extensions/RegisterExtensions.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/src/Extensions/RegisterExtensions.cs
new file mode 100644
index 0000000..e7d80e6
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/src/Extensions/RegisterExtensions.cs
@@ -0,0 +1,18 @@
+using Cogworks.AzureSearch.Interfaces.Builder;
+using Cogworks.AzureSearch.IoC.Umbraco.Builders;
+using Umbraco.Cms.Core.DependencyInjection;
+
+namespace Cogworks.AzureSearch.IoC.Umbraco.Extensions
+{
+ public static class RegisterExtensions
+ {
+ public static IContainerBuilder RegisterAzureSearch(this IUmbracoBuilder umbracoBuilder)
+ => new ContainerBuilder(umbracoBuilder)
+ .RegisterRepositories()
+ .RegisterIndexes()
+ .RegisterSearchers()
+ .RegisterInitializers()
+ .RegisterWrappers()
+ .RegisterOperations();
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests.csproj b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests.csproj
new file mode 100644
index 0000000..950e5f5
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests.csproj
@@ -0,0 +1,52 @@
+
+
+ false
+
+
+
+ net6.0;net5.0
+ latest
+ 1591;1701;1702;8032;NU1701;AD0001;CA1041;CS0311;CS5001
+ false
+ true
+ false
+ true
+ true
+ true
+ true
+ snupkg
+ true
+ true
+ true
+ true
+
+
+
+ disable
+ disable
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Models/FirstTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Models/FirstTestDocumentModel.cs
new file mode 100644
index 0000000..7411a13
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Models/FirstTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.Umbraco.UnitTests.Models
+{
+ public class FirstTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Models/NotRegisteredTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Models/NotRegisteredTestDocumentModel.cs
new file mode 100644
index 0000000..7a10987
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Models/NotRegisteredTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.Umbraco.UnitTests.Models
+{
+ public class NotRegisteredTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Models/SecondTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Models/SecondTestDocumentModel.cs
new file mode 100644
index 0000000..f8efd96
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Models/SecondTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.Umbraco.UnitTests.Models
+{
+ public class SecondTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Models/ThirdTestDocumentModel.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Models/ThirdTestDocumentModel.cs
new file mode 100644
index 0000000..bb5666f
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Models/ThirdTestDocumentModel.cs
@@ -0,0 +1,17 @@
+using Azure.Search.Documents.Indexes;
+using Cogworks.AzureSearch.Models;
+
+namespace Cogworks.AzureSearch.IoC.Umbraco.UnitTests.Models
+{
+ public class ThirdTestDocumentModel : IModel
+ {
+ [SimpleField(IsKey = true, IsFilterable = true)]
+ [SearchableField]
+ public string Id { get; set; }
+
+ [SimpleField(IsFilterable = true)]
+ [SearchableField]
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Searchers/CustomTestSearch.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Searchers/CustomTestSearch.cs
new file mode 100644
index 0000000..8a584ad
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/Searchers/CustomTestSearch.cs
@@ -0,0 +1,29 @@
+using Cogworks.AzureSearch.Interfaces.Searches;
+using Cogworks.AzureSearch.IoC.Umbraco.UnitTests.Models;
+using Cogworks.AzureSearch.Searchers;
+
+namespace Cogworks.AzureSearch.IoC.Umbraco.UnitTests.Searchers
+{
+#pragma warning disable SA1649 // SA1649FileNameMustMatchTypeName
+ public interface ICustomTestSearch
+ {
+ void SomeCustomSearchExample();
+ }
+
+ public class CustomTestSearch : BaseDomainSearch, ICustomTestSearch
+ {
+ public CustomTestSearch(ISearcher search) : base(search)
+ {
+ }
+
+ public void SomeCustomSearchExample()
+ {
+ // Start of custom filters/logic
+ // ...
+ // End of custom filters
+
+ // _ = base.Search("test", new SearchParameters());
+ }
+ }
+#pragma warning restore SA1649 // SA1649FileNameMustMatchTypeName
+}
\ No newline at end of file
diff --git a/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/UmbracoIocExtensionTests.cs b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/UmbracoIocExtensionTests.cs
new file mode 100644
index 0000000..1c8de9b
--- /dev/null
+++ b/src/IoC.Providers/Cogworks.AzureSearch.IoC.Umbraco/tests/UnitTests/Cogworks.AzureSearch.IoC.Umbraco.UnitTests/UmbracoIocExtensionTests.cs
@@ -0,0 +1,260 @@
+// ReSharper disable PossibleNullReferenceException
+
+using System;
+using System.IO;
+using System.Reflection;
+using Azure.Search.Documents.Indexes.Models;
+using Cogworks.AzureSearch.Interfaces.Builder;
+using Cogworks.AzureSearch.Interfaces.Indexes;
+using Cogworks.AzureSearch.Interfaces.Initializers;
+using Cogworks.AzureSearch.Interfaces.Operations;
+using Cogworks.AzureSearch.Interfaces.Repositories;
+using Cogworks.AzureSearch.Interfaces.Searches;
+using Cogworks.AzureSearch.IoC.Umbraco.Extensions;
+using Cogworks.AzureSearch.IoC.Umbraco.UnitTests.Models;
+using Cogworks.AzureSearch.IoC.Umbraco.UnitTests.Searchers;
+using Cogworks.AzureSearch.Models;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using NSubstitute;
+using Umbraco.Cms.Core.Cache;
+using Umbraco.Cms.Core.Composing;
+using Umbraco.Cms.Core.DependencyInjection;
+using Umbraco.Cms.Core.Logging;
+using Xunit;
+
+namespace Cogworks.AzureSearch.IoC.Umbraco.UnitTests
+{
+ public class UmbracoIocExtensionTests
+ {
+ private readonly IContainerBuilder _containerBuilder;
+ private readonly ServiceCollection _serviceCollection;
+ private readonly UmbracoBuilder _umbracoBuilder;
+
+ private const string FirstDocumentIndexName = "first-test-document";
+ private const string SecondDocumentIndexName = "second-test-document";
+ private const string ThirdDocumentIndexName = "third-test-document";
+
+ public UmbracoIocExtensionTests()
+ {
+ _serviceCollection = new ServiceCollection();
+ var dirName = Path.GetDirectoryName(
+ Assembly.GetExecutingAssembly()
+ .Location
+ .Replace("bin\\Debug", string.Empty));
+
+ var typeLoader = new TypeLoader(
+ Substitute.For(),
+ new VaryingRuntimeHash(),
+ Substitute.For(),
+ new DirectoryInfo(dirName),
+ Substitute.For>(),
+ Substitute.For());
+
+ _umbracoBuilder = new UmbracoBuilder(
+ _serviceCollection,
+ Substitute.For(),
+ typeLoader);
+
+ _containerBuilder = _umbracoBuilder.RegisterAzureSearch()
+ .RegisterClientOptions("test", "test", "https://localhost")
+ .RegisterIndexOptions(false, false)
+ .RegisterIndexDefinitions(FirstDocumentIndexName)
+ .RegisterIndexDefinitions(SecondDocumentIndexName)
+ .RegisterIndexDefinitions(customIndex: new SearchIndex(ThirdDocumentIndexName));
+ }
+
+ [Theory]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ public void Should_ReturnDedicatedRepositoryInstance(Type desiredObjectType)
+ {
+ // Arrange
+ _umbracoBuilder.Build();
+ var serviceProvider = _serviceCollection.BuildServiceProvider();
+
+ using (var scope = serviceProvider.CreateScope())
+ {
+ // Act
+ var instance = scope.ServiceProvider.GetService(desiredObjectType);
+
+ // Assert
+ Assert.NotNull(instance);
+ Assert.True(desiredObjectType.IsInstanceOfType(instance));
+ Assert.NotEmpty(instance.GetType().GenericTypeArguments);
+ Assert.Equal(desiredObjectType.GenericTypeArguments[0], instance.GetType().GenericTypeArguments[0]);
+ }
+ }
+
+ [Theory]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation))]
+ [InlineData(typeof(IDocumentOperation))]
+ [InlineData(typeof(IIndex))]
+ [InlineData(typeof(IInitializer))]
+ [InlineData(typeof(ISearcher))]
+ public void Should_Not_ThrowException_When_IndexRegistered(Type desiredObjectType)
+ {
+ // Arrange
+ // Act
+ var exceptionRecord = Record.Exception(() => Should_ReturnDedicatedRepositoryInstance(desiredObjectType));
+
+ // Assert
+ Assert.Null(exceptionRecord);
+ }
+
+ [Theory]
+ [InlineData(typeof(IRepository))]
+ [InlineData(typeof(IIndexOperation