diff --git a/Hosuto.sln b/Hosuto.sln
index 7373561..3d0b828 100644
--- a/Hosuto.sln
+++ b/Hosuto.sln
@@ -49,76 +49,240 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "samples\dotnet\App\A
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorLibrary", "samples\dotnet\RazorLibrary\RazorLibrary.csproj", "{71E30ED2-53D6-4A9D-B541-4255D88E97AD}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "minimal", "minimal", "{8CBA57D1-6EFE-D619-F938-253FEAFA8EE9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "samples\dotnet\minimal\App\App.csproj", "{EB49E8F1-D31A-46E5-98BE-F525FFF44DBC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RazorModule", "samples\dotnet\minimal\RazorModule\RazorModule.csproj", "{961CB672-6FAB-4F8A-90F4-5EB074ADEE97}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1B1C938C-B367-4EF7-8AE2-7832B857DB7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1B1C938C-B367-4EF7-8AE2-7832B857DB7B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1B1C938C-B367-4EF7-8AE2-7832B857DB7B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {1B1C938C-B367-4EF7-8AE2-7832B857DB7B}.Debug|x64.Build.0 = Debug|Any CPU
+ {1B1C938C-B367-4EF7-8AE2-7832B857DB7B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1B1C938C-B367-4EF7-8AE2-7832B857DB7B}.Debug|x86.Build.0 = Debug|Any CPU
{1B1C938C-B367-4EF7-8AE2-7832B857DB7B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1B1C938C-B367-4EF7-8AE2-7832B857DB7B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1B1C938C-B367-4EF7-8AE2-7832B857DB7B}.Release|x64.ActiveCfg = Release|Any CPU
+ {1B1C938C-B367-4EF7-8AE2-7832B857DB7B}.Release|x64.Build.0 = Release|Any CPU
+ {1B1C938C-B367-4EF7-8AE2-7832B857DB7B}.Release|x86.ActiveCfg = Release|Any CPU
+ {1B1C938C-B367-4EF7-8AE2-7832B857DB7B}.Release|x86.Build.0 = Release|Any CPU
{D78ABD82-026C-4393-ABAB-E9CF551DF7E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D78ABD82-026C-4393-ABAB-E9CF551DF7E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D78ABD82-026C-4393-ABAB-E9CF551DF7E1}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D78ABD82-026C-4393-ABAB-E9CF551DF7E1}.Debug|x64.Build.0 = Debug|Any CPU
+ {D78ABD82-026C-4393-ABAB-E9CF551DF7E1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D78ABD82-026C-4393-ABAB-E9CF551DF7E1}.Debug|x86.Build.0 = Debug|Any CPU
{D78ABD82-026C-4393-ABAB-E9CF551DF7E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D78ABD82-026C-4393-ABAB-E9CF551DF7E1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D78ABD82-026C-4393-ABAB-E9CF551DF7E1}.Release|x64.ActiveCfg = Release|Any CPU
+ {D78ABD82-026C-4393-ABAB-E9CF551DF7E1}.Release|x64.Build.0 = Release|Any CPU
+ {D78ABD82-026C-4393-ABAB-E9CF551DF7E1}.Release|x86.ActiveCfg = Release|Any CPU
+ {D78ABD82-026C-4393-ABAB-E9CF551DF7E1}.Release|x86.Build.0 = Release|Any CPU
{26C793F8-EF85-4C4B-AD70-096D0758631D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{26C793F8-EF85-4C4B-AD70-096D0758631D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {26C793F8-EF85-4C4B-AD70-096D0758631D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {26C793F8-EF85-4C4B-AD70-096D0758631D}.Debug|x64.Build.0 = Debug|Any CPU
+ {26C793F8-EF85-4C4B-AD70-096D0758631D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {26C793F8-EF85-4C4B-AD70-096D0758631D}.Debug|x86.Build.0 = Debug|Any CPU
{26C793F8-EF85-4C4B-AD70-096D0758631D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26C793F8-EF85-4C4B-AD70-096D0758631D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {26C793F8-EF85-4C4B-AD70-096D0758631D}.Release|x64.ActiveCfg = Release|Any CPU
+ {26C793F8-EF85-4C4B-AD70-096D0758631D}.Release|x64.Build.0 = Release|Any CPU
+ {26C793F8-EF85-4C4B-AD70-096D0758631D}.Release|x86.ActiveCfg = Release|Any CPU
+ {26C793F8-EF85-4C4B-AD70-096D0758631D}.Release|x86.Build.0 = Release|Any CPU
{0D000FD6-F2EE-4658-9DB0-A28CF977CA09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D000FD6-F2EE-4658-9DB0-A28CF977CA09}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0D000FD6-F2EE-4658-9DB0-A28CF977CA09}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0D000FD6-F2EE-4658-9DB0-A28CF977CA09}.Debug|x64.Build.0 = Debug|Any CPU
+ {0D000FD6-F2EE-4658-9DB0-A28CF977CA09}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0D000FD6-F2EE-4658-9DB0-A28CF977CA09}.Debug|x86.Build.0 = Debug|Any CPU
{0D000FD6-F2EE-4658-9DB0-A28CF977CA09}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D000FD6-F2EE-4658-9DB0-A28CF977CA09}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0D000FD6-F2EE-4658-9DB0-A28CF977CA09}.Release|x64.ActiveCfg = Release|Any CPU
+ {0D000FD6-F2EE-4658-9DB0-A28CF977CA09}.Release|x64.Build.0 = Release|Any CPU
+ {0D000FD6-F2EE-4658-9DB0-A28CF977CA09}.Release|x86.ActiveCfg = Release|Any CPU
+ {0D000FD6-F2EE-4658-9DB0-A28CF977CA09}.Release|x86.Build.0 = Release|Any CPU
{B0DF33E2-2F24-4C0F-9F5A-9EFD1D714FC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0DF33E2-2F24-4C0F-9F5A-9EFD1D714FC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B0DF33E2-2F24-4C0F-9F5A-9EFD1D714FC4}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B0DF33E2-2F24-4C0F-9F5A-9EFD1D714FC4}.Debug|x64.Build.0 = Debug|Any CPU
+ {B0DF33E2-2F24-4C0F-9F5A-9EFD1D714FC4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B0DF33E2-2F24-4C0F-9F5A-9EFD1D714FC4}.Debug|x86.Build.0 = Debug|Any CPU
{B0DF33E2-2F24-4C0F-9F5A-9EFD1D714FC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0DF33E2-2F24-4C0F-9F5A-9EFD1D714FC4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B0DF33E2-2F24-4C0F-9F5A-9EFD1D714FC4}.Release|x64.ActiveCfg = Release|Any CPU
+ {B0DF33E2-2F24-4C0F-9F5A-9EFD1D714FC4}.Release|x64.Build.0 = Release|Any CPU
+ {B0DF33E2-2F24-4C0F-9F5A-9EFD1D714FC4}.Release|x86.ActiveCfg = Release|Any CPU
+ {B0DF33E2-2F24-4C0F-9F5A-9EFD1D714FC4}.Release|x86.Build.0 = Release|Any CPU
{29C629D3-033F-4112-9F31-F0285D91FC71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{29C629D3-033F-4112-9F31-F0285D91FC71}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {29C629D3-033F-4112-9F31-F0285D91FC71}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {29C629D3-033F-4112-9F31-F0285D91FC71}.Debug|x64.Build.0 = Debug|Any CPU
+ {29C629D3-033F-4112-9F31-F0285D91FC71}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {29C629D3-033F-4112-9F31-F0285D91FC71}.Debug|x86.Build.0 = Debug|Any CPU
{29C629D3-033F-4112-9F31-F0285D91FC71}.Release|Any CPU.ActiveCfg = Release|Any CPU
{29C629D3-033F-4112-9F31-F0285D91FC71}.Release|Any CPU.Build.0 = Release|Any CPU
+ {29C629D3-033F-4112-9F31-F0285D91FC71}.Release|x64.ActiveCfg = Release|Any CPU
+ {29C629D3-033F-4112-9F31-F0285D91FC71}.Release|x64.Build.0 = Release|Any CPU
+ {29C629D3-033F-4112-9F31-F0285D91FC71}.Release|x86.ActiveCfg = Release|Any CPU
+ {29C629D3-033F-4112-9F31-F0285D91FC71}.Release|x86.Build.0 = Release|Any CPU
{ECECF074-B3EF-428C-B3F6-4975200F7E1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ECECF074-B3EF-428C-B3F6-4975200F7E1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ECECF074-B3EF-428C-B3F6-4975200F7E1A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {ECECF074-B3EF-428C-B3F6-4975200F7E1A}.Debug|x64.Build.0 = Debug|Any CPU
+ {ECECF074-B3EF-428C-B3F6-4975200F7E1A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {ECECF074-B3EF-428C-B3F6-4975200F7E1A}.Debug|x86.Build.0 = Debug|Any CPU
{ECECF074-B3EF-428C-B3F6-4975200F7E1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ECECF074-B3EF-428C-B3F6-4975200F7E1A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ECECF074-B3EF-428C-B3F6-4975200F7E1A}.Release|x64.ActiveCfg = Release|Any CPU
+ {ECECF074-B3EF-428C-B3F6-4975200F7E1A}.Release|x64.Build.0 = Release|Any CPU
+ {ECECF074-B3EF-428C-B3F6-4975200F7E1A}.Release|x86.ActiveCfg = Release|Any CPU
+ {ECECF074-B3EF-428C-B3F6-4975200F7E1A}.Release|x86.Build.0 = Release|Any CPU
{17D33BF9-3D31-47D1-8561-D3194A5D18C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{17D33BF9-3D31-47D1-8561-D3194A5D18C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {17D33BF9-3D31-47D1-8561-D3194A5D18C5}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {17D33BF9-3D31-47D1-8561-D3194A5D18C5}.Debug|x64.Build.0 = Debug|Any CPU
+ {17D33BF9-3D31-47D1-8561-D3194A5D18C5}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {17D33BF9-3D31-47D1-8561-D3194A5D18C5}.Debug|x86.Build.0 = Debug|Any CPU
{17D33BF9-3D31-47D1-8561-D3194A5D18C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{17D33BF9-3D31-47D1-8561-D3194A5D18C5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {17D33BF9-3D31-47D1-8561-D3194A5D18C5}.Release|x64.ActiveCfg = Release|Any CPU
+ {17D33BF9-3D31-47D1-8561-D3194A5D18C5}.Release|x64.Build.0 = Release|Any CPU
+ {17D33BF9-3D31-47D1-8561-D3194A5D18C5}.Release|x86.ActiveCfg = Release|Any CPU
+ {17D33BF9-3D31-47D1-8561-D3194A5D18C5}.Release|x86.Build.0 = Release|Any CPU
{D4A5C193-51F1-4C10-BE03-C940090F245F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4A5C193-51F1-4C10-BE03-C940090F245F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D4A5C193-51F1-4C10-BE03-C940090F245F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D4A5C193-51F1-4C10-BE03-C940090F245F}.Debug|x64.Build.0 = Debug|Any CPU
+ {D4A5C193-51F1-4C10-BE03-C940090F245F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D4A5C193-51F1-4C10-BE03-C940090F245F}.Debug|x86.Build.0 = Debug|Any CPU
{D4A5C193-51F1-4C10-BE03-C940090F245F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4A5C193-51F1-4C10-BE03-C940090F245F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D4A5C193-51F1-4C10-BE03-C940090F245F}.Release|x64.ActiveCfg = Release|Any CPU
+ {D4A5C193-51F1-4C10-BE03-C940090F245F}.Release|x64.Build.0 = Release|Any CPU
+ {D4A5C193-51F1-4C10-BE03-C940090F245F}.Release|x86.ActiveCfg = Release|Any CPU
+ {D4A5C193-51F1-4C10-BE03-C940090F245F}.Release|x86.Build.0 = Release|Any CPU
{4F525B97-E934-4F9B-AB40-78CBF6B61269}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F525B97-E934-4F9B-AB40-78CBF6B61269}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4F525B97-E934-4F9B-AB40-78CBF6B61269}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {4F525B97-E934-4F9B-AB40-78CBF6B61269}.Debug|x64.Build.0 = Debug|Any CPU
+ {4F525B97-E934-4F9B-AB40-78CBF6B61269}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4F525B97-E934-4F9B-AB40-78CBF6B61269}.Debug|x86.Build.0 = Debug|Any CPU
{4F525B97-E934-4F9B-AB40-78CBF6B61269}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F525B97-E934-4F9B-AB40-78CBF6B61269}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4F525B97-E934-4F9B-AB40-78CBF6B61269}.Release|x64.ActiveCfg = Release|Any CPU
+ {4F525B97-E934-4F9B-AB40-78CBF6B61269}.Release|x64.Build.0 = Release|Any CPU
+ {4F525B97-E934-4F9B-AB40-78CBF6B61269}.Release|x86.ActiveCfg = Release|Any CPU
+ {4F525B97-E934-4F9B-AB40-78CBF6B61269}.Release|x86.Build.0 = Release|Any CPU
{5101C6BF-94D4-4001-AA0B-AC863E6E79F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5101C6BF-94D4-4001-AA0B-AC863E6E79F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5101C6BF-94D4-4001-AA0B-AC863E6E79F2}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5101C6BF-94D4-4001-AA0B-AC863E6E79F2}.Debug|x64.Build.0 = Debug|Any CPU
+ {5101C6BF-94D4-4001-AA0B-AC863E6E79F2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5101C6BF-94D4-4001-AA0B-AC863E6E79F2}.Debug|x86.Build.0 = Debug|Any CPU
{5101C6BF-94D4-4001-AA0B-AC863E6E79F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5101C6BF-94D4-4001-AA0B-AC863E6E79F2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5101C6BF-94D4-4001-AA0B-AC863E6E79F2}.Release|x64.ActiveCfg = Release|Any CPU
+ {5101C6BF-94D4-4001-AA0B-AC863E6E79F2}.Release|x64.Build.0 = Release|Any CPU
+ {5101C6BF-94D4-4001-AA0B-AC863E6E79F2}.Release|x86.ActiveCfg = Release|Any CPU
+ {5101C6BF-94D4-4001-AA0B-AC863E6E79F2}.Release|x86.Build.0 = Release|Any CPU
{C650ED86-171D-4823-B334-F696FED6C471}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C650ED86-171D-4823-B334-F696FED6C471}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C650ED86-171D-4823-B334-F696FED6C471}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C650ED86-171D-4823-B334-F696FED6C471}.Debug|x64.Build.0 = Debug|Any CPU
+ {C650ED86-171D-4823-B334-F696FED6C471}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C650ED86-171D-4823-B334-F696FED6C471}.Debug|x86.Build.0 = Debug|Any CPU
{C650ED86-171D-4823-B334-F696FED6C471}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C650ED86-171D-4823-B334-F696FED6C471}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C650ED86-171D-4823-B334-F696FED6C471}.Release|x64.ActiveCfg = Release|Any CPU
+ {C650ED86-171D-4823-B334-F696FED6C471}.Release|x64.Build.0 = Release|Any CPU
+ {C650ED86-171D-4823-B334-F696FED6C471}.Release|x86.ActiveCfg = Release|Any CPU
+ {C650ED86-171D-4823-B334-F696FED6C471}.Release|x86.Build.0 = Release|Any CPU
{B16EA0A4-8EBE-4EAC-ACE9-538572951747}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B16EA0A4-8EBE-4EAC-ACE9-538572951747}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B16EA0A4-8EBE-4EAC-ACE9-538572951747}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B16EA0A4-8EBE-4EAC-ACE9-538572951747}.Debug|x64.Build.0 = Debug|Any CPU
+ {B16EA0A4-8EBE-4EAC-ACE9-538572951747}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B16EA0A4-8EBE-4EAC-ACE9-538572951747}.Debug|x86.Build.0 = Debug|Any CPU
{B16EA0A4-8EBE-4EAC-ACE9-538572951747}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B16EA0A4-8EBE-4EAC-ACE9-538572951747}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B16EA0A4-8EBE-4EAC-ACE9-538572951747}.Release|x64.ActiveCfg = Release|Any CPU
+ {B16EA0A4-8EBE-4EAC-ACE9-538572951747}.Release|x64.Build.0 = Release|Any CPU
+ {B16EA0A4-8EBE-4EAC-ACE9-538572951747}.Release|x86.ActiveCfg = Release|Any CPU
+ {B16EA0A4-8EBE-4EAC-ACE9-538572951747}.Release|x86.Build.0 = Release|Any CPU
{1C6AD780-6DC3-4AF1-AB4E-51ABC1FC3A75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1C6AD780-6DC3-4AF1-AB4E-51ABC1FC3A75}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1C6AD780-6DC3-4AF1-AB4E-51ABC1FC3A75}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {1C6AD780-6DC3-4AF1-AB4E-51ABC1FC3A75}.Debug|x64.Build.0 = Debug|Any CPU
+ {1C6AD780-6DC3-4AF1-AB4E-51ABC1FC3A75}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1C6AD780-6DC3-4AF1-AB4E-51ABC1FC3A75}.Debug|x86.Build.0 = Debug|Any CPU
{1C6AD780-6DC3-4AF1-AB4E-51ABC1FC3A75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1C6AD780-6DC3-4AF1-AB4E-51ABC1FC3A75}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1C6AD780-6DC3-4AF1-AB4E-51ABC1FC3A75}.Release|x64.ActiveCfg = Release|Any CPU
+ {1C6AD780-6DC3-4AF1-AB4E-51ABC1FC3A75}.Release|x64.Build.0 = Release|Any CPU
+ {1C6AD780-6DC3-4AF1-AB4E-51ABC1FC3A75}.Release|x86.ActiveCfg = Release|Any CPU
+ {1C6AD780-6DC3-4AF1-AB4E-51ABC1FC3A75}.Release|x86.Build.0 = Release|Any CPU
{1BFA0E1B-556C-49DA-81F0-1067FAD97458}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1BFA0E1B-556C-49DA-81F0-1067FAD97458}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1BFA0E1B-556C-49DA-81F0-1067FAD97458}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {1BFA0E1B-556C-49DA-81F0-1067FAD97458}.Debug|x64.Build.0 = Debug|Any CPU
+ {1BFA0E1B-556C-49DA-81F0-1067FAD97458}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1BFA0E1B-556C-49DA-81F0-1067FAD97458}.Debug|x86.Build.0 = Debug|Any CPU
{1BFA0E1B-556C-49DA-81F0-1067FAD97458}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BFA0E1B-556C-49DA-81F0-1067FAD97458}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1BFA0E1B-556C-49DA-81F0-1067FAD97458}.Release|x64.ActiveCfg = Release|Any CPU
+ {1BFA0E1B-556C-49DA-81F0-1067FAD97458}.Release|x64.Build.0 = Release|Any CPU
+ {1BFA0E1B-556C-49DA-81F0-1067FAD97458}.Release|x86.ActiveCfg = Release|Any CPU
+ {1BFA0E1B-556C-49DA-81F0-1067FAD97458}.Release|x86.Build.0 = Release|Any CPU
{71E30ED2-53D6-4A9D-B541-4255D88E97AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{71E30ED2-53D6-4A9D-B541-4255D88E97AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {71E30ED2-53D6-4A9D-B541-4255D88E97AD}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {71E30ED2-53D6-4A9D-B541-4255D88E97AD}.Debug|x64.Build.0 = Debug|Any CPU
+ {71E30ED2-53D6-4A9D-B541-4255D88E97AD}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {71E30ED2-53D6-4A9D-B541-4255D88E97AD}.Debug|x86.Build.0 = Debug|Any CPU
{71E30ED2-53D6-4A9D-B541-4255D88E97AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71E30ED2-53D6-4A9D-B541-4255D88E97AD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {71E30ED2-53D6-4A9D-B541-4255D88E97AD}.Release|x64.ActiveCfg = Release|Any CPU
+ {71E30ED2-53D6-4A9D-B541-4255D88E97AD}.Release|x64.Build.0 = Release|Any CPU
+ {71E30ED2-53D6-4A9D-B541-4255D88E97AD}.Release|x86.ActiveCfg = Release|Any CPU
+ {71E30ED2-53D6-4A9D-B541-4255D88E97AD}.Release|x86.Build.0 = Release|Any CPU
+ {EB49E8F1-D31A-46E5-98BE-F525FFF44DBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EB49E8F1-D31A-46E5-98BE-F525FFF44DBC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EB49E8F1-D31A-46E5-98BE-F525FFF44DBC}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EB49E8F1-D31A-46E5-98BE-F525FFF44DBC}.Debug|x64.Build.0 = Debug|Any CPU
+ {EB49E8F1-D31A-46E5-98BE-F525FFF44DBC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EB49E8F1-D31A-46E5-98BE-F525FFF44DBC}.Debug|x86.Build.0 = Debug|Any CPU
+ {EB49E8F1-D31A-46E5-98BE-F525FFF44DBC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EB49E8F1-D31A-46E5-98BE-F525FFF44DBC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EB49E8F1-D31A-46E5-98BE-F525FFF44DBC}.Release|x64.ActiveCfg = Release|Any CPU
+ {EB49E8F1-D31A-46E5-98BE-F525FFF44DBC}.Release|x64.Build.0 = Release|Any CPU
+ {EB49E8F1-D31A-46E5-98BE-F525FFF44DBC}.Release|x86.ActiveCfg = Release|Any CPU
+ {EB49E8F1-D31A-46E5-98BE-F525FFF44DBC}.Release|x86.Build.0 = Release|Any CPU
+ {961CB672-6FAB-4F8A-90F4-5EB074ADEE97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {961CB672-6FAB-4F8A-90F4-5EB074ADEE97}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {961CB672-6FAB-4F8A-90F4-5EB074ADEE97}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {961CB672-6FAB-4F8A-90F4-5EB074ADEE97}.Debug|x64.Build.0 = Debug|Any CPU
+ {961CB672-6FAB-4F8A-90F4-5EB074ADEE97}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {961CB672-6FAB-4F8A-90F4-5EB074ADEE97}.Debug|x86.Build.0 = Debug|Any CPU
+ {961CB672-6FAB-4F8A-90F4-5EB074ADEE97}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {961CB672-6FAB-4F8A-90F4-5EB074ADEE97}.Release|Any CPU.Build.0 = Release|Any CPU
+ {961CB672-6FAB-4F8A-90F4-5EB074ADEE97}.Release|x64.ActiveCfg = Release|Any CPU
+ {961CB672-6FAB-4F8A-90F4-5EB074ADEE97}.Release|x64.Build.0 = Release|Any CPU
+ {961CB672-6FAB-4F8A-90F4-5EB074ADEE97}.Release|x86.ActiveCfg = Release|Any CPU
+ {961CB672-6FAB-4F8A-90F4-5EB074ADEE97}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -134,6 +298,9 @@ Global
{1C6AD780-6DC3-4AF1-AB4E-51ABC1FC3A75} = {F03A55C6-AB61-4A07-8E06-A742A1E9F625}
{1BFA0E1B-556C-49DA-81F0-1067FAD97458} = {F03A55C6-AB61-4A07-8E06-A742A1E9F625}
{71E30ED2-53D6-4A9D-B541-4255D88E97AD} = {F03A55C6-AB61-4A07-8E06-A742A1E9F625}
+ {8CBA57D1-6EFE-D619-F938-253FEAFA8EE9} = {F03A55C6-AB61-4A07-8E06-A742A1E9F625}
+ {EB49E8F1-D31A-46E5-98BE-F525FFF44DBC} = {8CBA57D1-6EFE-D619-F938-253FEAFA8EE9}
+ {961CB672-6FAB-4F8A-90F4-5EB074ADEE97} = {8CBA57D1-6EFE-D619-F938-253FEAFA8EE9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C7C4A16F-35F6-40CB-9F59-B48D0757FA7C}
diff --git a/samples/dotnet/minimal/App/App.csproj b/samples/dotnet/minimal/App/App.csproj
new file mode 100644
index 0000000..0e08d3f
--- /dev/null
+++ b/samples/dotnet/minimal/App/App.csproj
@@ -0,0 +1,16 @@
+
+
+
+ Exe
+ net10.0
+ false
+ disable
+ disable
+ Dbosoft.Hosuto.Samples.Minimal.App
+
+
+
+
+
+
+
diff --git a/samples/dotnet/minimal/App/Program.cs b/samples/dotnet/minimal/App/Program.cs
new file mode 100644
index 0000000..2063229
--- /dev/null
+++ b/samples/dotnet/minimal/App/Program.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Linq;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Dbosoft.Hosuto.Modules.Hosting;
+using Dbosoft.Hosuto.Samples.Minimal.RazorModule;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Server;
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using Microsoft.Extensions.DependencyInjection;
+using SimpleInjector;
+
+namespace Dbosoft.Hosuto.Samples.Minimal.App
+{
+ public static class Program
+ {
+ public static async Task Main()
+ {
+ var builder = ModulesHost.CreateDefaultBuilder();
+ builder.UseSimpleInjector(new Container());
+ builder.UseAspNetCoreMinimal(app => app.WebHost.UseUrls("http://127.0.0.1:0"));
+ builder.HostModule();
+
+ using var host = builder.Build();
+ await host.StartAsync();
+
+ var moduleHost = host.Services.GetRequiredService>();
+ var baseUrl = moduleHost.Services.GetRequiredService()
+ .Features.Get().Addresses.First();
+
+ using (var http = new HttpClient())
+ {
+ await Probe(http, baseUrl + "/", "Razor page");
+ await Probe(http, baseUrl + "/css/site.css", "static asset (wwwroot)");
+ }
+
+ await host.StopAsync();
+ }
+
+ private static async Task Probe(HttpClient http, string url, string what)
+ {
+ try
+ {
+ var response = await http.GetAsync(url);
+ var body = await response.Content.ReadAsStringAsync();
+ var snippet = body.Replace("\r", " ").Replace("\n", " ").Trim();
+ if (snippet.Length > 70) snippet = snippet.Substring(0, 70) + "...";
+ Console.WriteLine($"[{what,-22}] {(int)response.StatusCode} {response.StatusCode} {url}");
+ Console.WriteLine($" -> {snippet}");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"[{what,-22}] ERROR {url} -> {ex.Message}");
+ }
+ }
+ }
+}
diff --git a/samples/dotnet/minimal/README.md b/samples/dotnet/minimal/README.md
new file mode 100644
index 0000000..344d5b5
--- /dev/null
+++ b/samples/dotnet/minimal/README.md
@@ -0,0 +1,33 @@
+# Minimal-API host sample (net10, Razor)
+
+Demonstrates the opt-in **`UseAspNetCoreMinimal()`** path: a Hosuto web module is hosted on a
+minimal-API `WebApplication` inner host instead of the classic `ConfigureWebHostDefaults` host. The
+module (`RazorModule`) is an ordinary Hosuto `WebModule` using the module interfaces
+(`IServiceConfiguringModule` / `IApplicationConfiguringModule`) and is authored exactly like a
+module for the multi-host builder.
+
+Run it:
+
+```
+dotnet run --project App
+```
+
+The host starts the module on an ephemeral port, then probes two URLs and prints the results.
+
+## What works
+
+- `GET /` → **200** — Razor Pages are discovered and rendered on the minimal-API module host.
+- Dependency injection / SimpleInjector module container (`ConfigureContainer`) works post-build.
+
+## Known limitation (tracked as a follow-up)
+
+- `GET /css/site.css` → **404** — a module's **static web assets are not yet mapped** on the
+ minimal-API host.
+
+ The classic host wires module assets via `ModuleWebAssetsLoader`, which is **file-provider /
+ XML-manifest** based (`{app}.StaticWebAssets.xml`) and manipulates `WebRootFileProvider`. Since
+ .NET 9 static web assets are **endpoint-based** (`MapStaticAssets`,
+ `{app}.staticwebassets.*.json`), that mechanism no longer applies. Mapping a module's static web
+ assets on net9/10 (filtering the host manifest's `.modules/{module}` entries into the module host)
+ is a separate piece of work and is intentionally **not** part of the initial `UseAspNetCoreMinimal`
+ handler.
diff --git a/samples/dotnet/minimal/RazorModule/Pages/Index.cshtml b/samples/dotnet/minimal/RazorModule/Pages/Index.cshtml
new file mode 100644
index 0000000..6f47d09
--- /dev/null
+++ b/samples/dotnet/minimal/RazorModule/Pages/Index.cshtml
@@ -0,0 +1,14 @@
+@page
+@{
+ Layout = null;
+}
+
+
+
+ Razor module
+
+
+
+ Razor module page rendered
+
+
diff --git a/samples/dotnet/minimal/RazorModule/RazorGreetModule.cs b/samples/dotnet/minimal/RazorModule/RazorGreetModule.cs
new file mode 100644
index 0000000..449f043
--- /dev/null
+++ b/samples/dotnet/minimal/RazorModule/RazorGreetModule.cs
@@ -0,0 +1,34 @@
+using System;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.Extensions.DependencyInjection;
+using Dbosoft.Hosuto.Modules;
+
+namespace Dbosoft.Hosuto.Samples.Minimal.RazorModule
+{
+ // A Razor web module on the minimal-API WebApplication inner host, authored with the three
+ // module contracts - services, middleware, and (minimal-API-style) endpoints:
+ // IServiceConfiguringModule -> AddRazorPages
+ // IApplicationConfiguringModule -> UseStaticFiles (middleware)
+ // IEndpointConfiguringModule -> MapRazorPages (idiomatic endpoint mapping)
+ public sealed class RazorGreetModule
+ : WebModule, IServiceConfiguringModule, IApplicationConfiguringModule, IEndpointConfiguringModule
+ {
+ public override string Path { get; } = "";
+
+ public void ConfigureServices(IServiceProvider serviceProvider, IServiceCollection services)
+ {
+ services.AddRazorPages();
+ }
+
+ public void Configure(IServiceProvider serviceProvider, IApplicationBuilder app)
+ {
+ app.UseStaticFiles();
+ }
+
+ public void MapEndpoints(IServiceProvider serviceProvider, IEndpointRouteBuilder endpoints)
+ {
+ endpoints.MapRazorPages();
+ }
+ }
+}
diff --git a/samples/dotnet/minimal/RazorModule/RazorModule.csproj b/samples/dotnet/minimal/RazorModule/RazorModule.csproj
new file mode 100644
index 0000000..154721b
--- /dev/null
+++ b/samples/dotnet/minimal/RazorModule/RazorModule.csproj
@@ -0,0 +1,25 @@
+
+
+
+ net10.0
+ Library
+ true
+ false
+ disable
+ disable
+ Dbosoft.Hosuto.Samples.Minimal.RazorModule
+ Dbosoft.Hosuto.Samples.Minimal.RazorModule
+
+ .modules/$(AssemblyName)
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/dotnet/minimal/RazorModule/wwwroot/css/site.css b/samples/dotnet/minimal/RazorModule/wwwroot/css/site.css
new file mode 100644
index 0000000..f2a1506
--- /dev/null
+++ b/samples/dotnet/minimal/RazorModule/wwwroot/css/site.css
@@ -0,0 +1 @@
+#msg { color: green; }
diff --git a/src/Hosuto.Hosting.AspNetCore/Modules/Hosting/ModuleConfigureStartupFilter.cs b/src/Hosuto.Hosting.AspNetCore/Modules/Hosting/ModuleConfigureStartupFilter.cs
new file mode 100644
index 0000000..fdcdd28
--- /dev/null
+++ b/src/Hosuto.Hosting.AspNetCore/Modules/Hosting/ModuleConfigureStartupFilter.cs
@@ -0,0 +1,50 @@
+#if NET6_0_OR_GREATER
+using System;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+
+namespace Dbosoft.Hosuto.Modules.Hosting
+{
+ // Runs the module's Configure delegate when the request pipeline is built (at start), which is
+ // after the module container has been configured by the bootstrap pipeline.
+ internal sealed class ModuleConfigureStartupFilter : IStartupFilter
+ {
+ private readonly Action _configure;
+
+ public ModuleConfigureStartupFilter(Action configure)
+ {
+ _configure = configure;
+ }
+
+ public Action Configure(Action next)
+ {
+ return app =>
+ {
+ _configure(app);
+ next(app);
+ };
+ }
+ }
+
+ ///
+ /// Opt-in hook to configure the minimal-API of a web module
+ /// hosted via UseAspNetCoreMinimal().
+ ///
+ public interface IWebApplicationBuilderConfigurer
+ {
+ void Configure(WebApplicationBuilder builder);
+ }
+
+ internal sealed class DelegateWebApplicationBuilderConfigurer : IWebApplicationBuilderConfigurer
+ {
+ private readonly Action _configure;
+
+ public DelegateWebApplicationBuilderConfigurer(Action configure)
+ {
+ _configure = configure;
+ }
+
+ public void Configure(WebApplicationBuilder builder) => _configure(builder);
+ }
+}
+#endif
diff --git a/src/Hosuto.Hosting.AspNetCore/Modules/Hosting/ModulesHostBuilderExtensions.cs b/src/Hosuto.Hosting.AspNetCore/Modules/Hosting/ModulesHostBuilderExtensions.cs
index c52657f..047a1f6 100644
--- a/src/Hosuto.Hosting.AspNetCore/Modules/Hosting/ModulesHostBuilderExtensions.cs
+++ b/src/Hosuto.Hosting.AspNetCore/Modules/Hosting/ModulesHostBuilderExtensions.cs
@@ -37,6 +37,29 @@ public static IModulesHostBuilder UseAspNetCoreWithDefaults(this IModulesHostBui
return UseAspNetCore(builder, configure);
}
+#if NET6_0_OR_GREATER
+ ///
+ /// Opt-in: host web modules on a minimal-API
+ /// inner host instead of the classic ConfigureWebHostDefaults host. Additive - the
+ /// module authoring model (ConfigureServices/Configure/ConfigureContainer, convention or the
+ /// module interfaces) is unchanged.
+ ///
+ public static IModulesHostBuilder UseAspNetCoreMinimal(this IModulesHostBuilder builder,
+ Action configure = null)
+ {
+ builder.ConfigureFrameworkServices((ctx, services) =>
+ {
+ services.AddTransient(typeof(IBootstrapHostFilter<>), typeof(WebApplicationBootstrapHostFilter<>));
+
+ if (configure != null)
+ services.AddTransient(sp =>
+ new DelegateWebApplicationBuilderConfigurer(configure));
+ });
+
+ return builder;
+ }
+#endif
+
public static IModulesHostBuilder UseAspNetCore(this IModulesHostBuilder builder,
Action configure = null)
{
diff --git a/src/Hosuto.Hosting.AspNetCore/Modules/Hosting/WebApplicationBootstrapHostFilter.cs b/src/Hosuto.Hosting.AspNetCore/Modules/Hosting/WebApplicationBootstrapHostFilter.cs
new file mode 100644
index 0000000..7bc4316
--- /dev/null
+++ b/src/Hosuto.Hosting.AspNetCore/Modules/Hosting/WebApplicationBootstrapHostFilter.cs
@@ -0,0 +1,19 @@
+#if NET6_0_OR_GREATER
+using System;
+
+namespace Dbosoft.Hosuto.Modules.Hosting
+{
+ public class WebApplicationBootstrapHostFilter : IBootstrapHostFilter where TModule : class
+ {
+ public Action> Invoke(Action> next)
+ {
+ return command =>
+ {
+ var handler = new WebApplicationModuleHostHandler();
+ handler.BootstrapHost(command);
+ next(command);
+ };
+ }
+ }
+}
+#endif
diff --git a/src/Hosuto.Hosting.AspNetCore/Modules/Hosting/WebApplicationModuleHostHandler.cs b/src/Hosuto.Hosting.AspNetCore/Modules/Hosting/WebApplicationModuleHostHandler.cs
new file mode 100644
index 0000000..089a381
--- /dev/null
+++ b/src/Hosuto.Hosting.AspNetCore/Modules/Hosting/WebApplicationModuleHostHandler.cs
@@ -0,0 +1,134 @@
+#if NET6_0_OR_GREATER
+using System.Collections.Generic;
+using Dbosoft.Hosuto.Modules.Hosting.Internal;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace Dbosoft.Hosuto.Modules.Hosting
+{
+ ///
+ /// Builds a web module's inner host as a minimal-API instead of the
+ /// classic HostBuilder + ConfigureWebHostDefaults host. Opt-in via
+ /// UseAspNetCoreMinimal(). The module's ConfigureServices runs against
+ /// before build; Configure is deferred to
+ /// pipeline build (start) via an so it runs after the module
+ /// container (e.g. SimpleInjector) has been configured by the bootstrap pipeline.
+ ///
+ ///
+ /// A module hosting options Configure(Action<IHostBuilder>) delegate is applied to
+ /// , which restricts some
+ /// operations (it manages the service provider factory itself).
+ ///
+ public class WebApplicationModuleHostHandler : DefaultBootstrapHostHandler where TModule : class
+ {
+ public override void BootstrapHost(BootstrapModuleHostCommand command)
+ {
+ if (command.Host != null || !(command.BootstrapContext.Module is IWebModule))
+ return;
+
+ BootstrapContext = command.BootstrapContext;
+
+ var frameworkServices = BootstrapContext.Advanced.FrameworkServices;
+ var hostBuilderContext = frameworkServices.GetRequiredService();
+ var moduleAssemblyName = BootstrapContext.Module.GetType().Assembly.GetName().Name;
+
+ var builder = WebApplication.CreateBuilder(new WebApplicationOptions
+ {
+ ApplicationName = moduleAssemblyName,
+ EnvironmentName = hostBuilderContext.HostingEnvironment.EnvironmentName,
+ ContentRootPath = hostBuilderContext.HostingEnvironment.ContentRootPath
+ });
+
+ // configuration: outer app configuration + module application name + module config filters.
+ builder.Configuration.AddConfiguration(hostBuilderContext.Configuration);
+ builder.Configuration.AddInMemoryCollection(new[]
+ {
+ new KeyValuePair(HostDefaults.ApplicationKey, moduleAssemblyName)
+ });
+
+ // a HostBuilderContext that reflects the *inner* module host (its environment and
+ // configuration), so module configuration/services filters see the module host being
+ // built rather than the outer host.
+ var moduleHostContext = new HostBuilderContext(new Dictionary