Added Logging to Mvc

This commit is contained in:
Ben Brown 2014-07-17 13:22:38 -07:00
parent 11d6c507f9
commit 01f5fec210
38 changed files with 1348 additions and 206 deletions

146
Mvc.sln
View File

@ -29,27 +29,23 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MvcSample.Web", "samples\Mv
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Razor.Host", "src\Microsoft.AspNet.Mvc.Razor.Host\Microsoft.AspNet.Mvc.Razor.Host.kproj", "{520B3AA4-363A-497C-8C15-80423C5AFC85}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Razor.Host.Test", "test\Microsoft.AspNet.Mvc.Razor.Host.Test\Microsoft.AspNet.Mvc.Razor.Host.Test.kproj", "{7C4F5973-0491-4028-B1DC-A9BA73FF9F77}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebSites", "WebSites", "{16703B76-C9F7-4C75-AE6C-53D92E308E3C}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.FunctionalTests", "test\Microsoft.AspNet.Mvc.FunctionalTests\Microsoft.AspNet.Mvc.FunctionalTests.kproj", "{323D0C04-B518-4A8F-8A8E-3546AD153D34}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "BasicWebSite", "test\WebSites\BasicWebSite\BasicWebSite.kproj", "{34DF1487-12C6-476C-BE0A-F31DF1939AE5}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ActivatorWebSite", "test\WebSites\ActivatorWebSite\ActivatorWebSite.kproj", "{DB79BCBA-9538-4A53-87D9-77728E2BAA39}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "InlineConstraintsWebSite", "test\WebSites\InlineConstraintsWebSite\InlineConstraintsWebSite.kproj", "{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AutofacWebSite", "test\WebSites\AutofacWebSite\AutofacWebSite.kproj", "{07C0E921-FCBB-458C-AC11-3D01CE68B16B}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TestConfiguration", "test\WebSites\Microsoft.AspNet.Mvc.TestConfiguration\Microsoft.AspNet.Mvc.TestConfiguration.kproj", "{680D75ED-601F-4D86-B01B-1072D0C31B8C}"
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CompositeViewEngine", "test\WebSites\CompositeViewEngine\CompositeViewEngine.kproj", "{A853B2BA-4449-4908-A416-5A3C027FC22B}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RoutingWebSite", "test\WebSites\RoutingWebSite\RoutingWebSite.kproj", "{42CDBF4A-E238-4C0F-A416-44588363EB4C}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Test", "test\Microsoft.AspNet.Mvc.Test\Microsoft.AspNet.Mvc.Test.kproj", "{5F945B82-FE5F-425C-956C-8BC2F2020254}"
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AutofacWebSite", "test\WebSites\AutofacWebSite\AutofacWebSite.kproj", "{07C0E921-FCBB-458C-AC11-3D01CE68B16B}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CompositeViewEngine", "test\WebSites\CompositeViewEngine\CompositeViewEngine.kproj", "{A853B2BA-4449-4908-A416-5A3C027FC22B}"
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "InlineConstraintsWebSite", "test\WebSites\InlineConstraintsWebSite\InlineConstraintsWebSite.kproj", "{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TestConfiguration", "test\WebSites\Microsoft.AspNet.Mvc.TestConfiguration\Microsoft.AspNet.Mvc.TestConfiguration.kproj", "{680D75ED-601F-4D86-B01B-1072D0C31B8C}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ActivatorWebSite", "test\WebSites\ActivatorWebSite\ActivatorWebSite.kproj", "{DB79BCBA-9538-4A53-87D9-77728E2BAA39}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RazorWebSite", "test\WebSites\RazorWebSite\RazorWebSite.kproj", "{B07CAF59-11ED-40E3-A5DB-E1178F84FA78}"
EndProject
@ -171,16 +167,6 @@ Global
{520B3AA4-363A-497C-8C15-80423C5AFC85}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{520B3AA4-363A-497C-8C15-80423C5AFC85}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{520B3AA4-363A-497C-8C15-80423C5AFC85}.Release|x86.ActiveCfg = Release|Any CPU
{7C4F5973-0491-4028-B1DC-A9BA73FF9F77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C4F5973-0491-4028-B1DC-A9BA73FF9F77}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C4F5973-0491-4028-B1DC-A9BA73FF9F77}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{7C4F5973-0491-4028-B1DC-A9BA73FF9F77}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{7C4F5973-0491-4028-B1DC-A9BA73FF9F77}.Debug|x86.ActiveCfg = Debug|Any CPU
{7C4F5973-0491-4028-B1DC-A9BA73FF9F77}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C4F5973-0491-4028-B1DC-A9BA73FF9F77}.Release|Any CPU.Build.0 = Release|Any CPU
{7C4F5973-0491-4028-B1DC-A9BA73FF9F77}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{7C4F5973-0491-4028-B1DC-A9BA73FF9F77}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{7C4F5973-0491-4028-B1DC-A9BA73FF9F77}.Release|x86.ActiveCfg = Release|Any CPU
{323D0C04-B518-4A8F-8A8E-3546AD153D34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{323D0C04-B518-4A8F-8A8E-3546AD153D34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{323D0C04-B518-4A8F-8A8E-3546AD153D34}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -201,66 +187,6 @@ Global
{34DF1487-12C6-476C-BE0A-F31DF1939AE5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{34DF1487-12C6-476C-BE0A-F31DF1939AE5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{34DF1487-12C6-476C-BE0A-F31DF1939AE5}.Release|x86.ActiveCfg = Release|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Debug|x86.ActiveCfg = Debug|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Release|Any CPU.Build.0 = Release|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Release|x86.ActiveCfg = Release|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Debug|x86.ActiveCfg = Debug|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Release|Any CPU.Build.0 = Release|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Release|x86.ActiveCfg = Release|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Debug|x86.ActiveCfg = Debug|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Release|Any CPU.Build.0 = Release|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Release|x86.ActiveCfg = Release|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Debug|x86.ActiveCfg = Debug|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|Any CPU.Build.0 = Release|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|x86.ActiveCfg = Release|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|x86.ActiveCfg = Debug|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Any CPU.Build.0 = Release|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|x86.ActiveCfg = Release|Any CPU
{5F945B82-FE5F-425C-956C-8BC2F2020254}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F945B82-FE5F-425C-956C-8BC2F2020254}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F945B82-FE5F-425C-956C-8BC2F2020254}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{5F945B82-FE5F-425C-956C-8BC2F2020254}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{5F945B82-FE5F-425C-956C-8BC2F2020254}.Debug|x86.ActiveCfg = Debug|Any CPU
{5F945B82-FE5F-425C-956C-8BC2F2020254}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F945B82-FE5F-425C-956C-8BC2F2020254}.Release|Any CPU.Build.0 = Release|Any CPU
{5F945B82-FE5F-425C-956C-8BC2F2020254}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{5F945B82-FE5F-425C-956C-8BC2F2020254}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{5F945B82-FE5F-425C-956C-8BC2F2020254}.Release|x86.ActiveCfg = Release|Any CPU
{A853B2BA-4449-4908-A416-5A3C027FC22B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A853B2BA-4449-4908-A416-5A3C027FC22B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A853B2BA-4449-4908-A416-5A3C027FC22B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -271,6 +197,56 @@ Global
{A853B2BA-4449-4908-A416-5A3C027FC22B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A853B2BA-4449-4908-A416-5A3C027FC22B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A853B2BA-4449-4908-A416-5A3C027FC22B}.Release|x86.ActiveCfg = Release|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|x86.ActiveCfg = Debug|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Any CPU.Build.0 = Release|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|x86.ActiveCfg = Release|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Debug|x86.ActiveCfg = Debug|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Release|Any CPU.Build.0 = Release|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{07C0E921-FCBB-458C-AC11-3D01CE68B16B}.Release|x86.ActiveCfg = Release|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Debug|x86.ActiveCfg = Debug|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Release|Any CPU.Build.0 = Release|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Release|x86.ActiveCfg = Release|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Debug|x86.ActiveCfg = Debug|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|Any CPU.Build.0 = Release|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|x86.ActiveCfg = Release|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Debug|x86.ActiveCfg = Debug|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Release|Any CPU.Build.0 = Release|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{DB79BCBA-9538-4A53-87D9-77728E2BAA39}.Release|x86.ActiveCfg = Release|Any CPU
{B07CAF59-11ED-40E3-A5DB-E1178F84FA78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B07CAF59-11ED-40E3-A5DB-E1178F84FA78}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B07CAF59-11ED-40E3-A5DB-E1178F84FA78}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -336,17 +312,9 @@ Global
{A8AA326E-8EE8-4F11-B750-23028E0949D7} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{FBB2B86E-972B-4185-9FF2-62CAB5F8388F} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
{520B3AA4-363A-497C-8C15-80423C5AFC85} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{7C4F5973-0491-4028-B1DC-A9BA73FF9F77} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{16703B76-C9F7-4C75-AE6C-53D92E308E3C} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{323D0C04-B518-4A8F-8A8E-3546AD153D34} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{34DF1487-12C6-476C-BE0A-F31DF1939AE5} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{DB79BCBA-9538-4A53-87D9-77728E2BAA39} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{07C0E921-FCBB-458C-AC11-3D01CE68B16B} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{680D75ED-601F-4D86-B01B-1072D0C31B8C} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{42CDBF4A-E238-4C0F-A416-44588363EB4C} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{5F945B82-FE5F-425C-956C-8BC2F2020254} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{A853B2BA-4449-4908-A416-5A3C027FC22B} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{B07CAF59-11ED-40E3-A5DB-E1178F84FA78} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{62735776-46FF-4170-9392-02E128A69B89} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{14F79E79-AE79-48FA-95DE-D794EF4EABB3} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}

View File

@ -3,12 +3,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Mvc
{
@ -16,60 +17,108 @@ namespace Microsoft.AspNet.Mvc
{
private readonly IActionDescriptorsCollectionProvider _actionDescriptorsCollectionProvider;
private readonly IActionBindingContextProvider _bindingProvider;
private ILogger _logger;
public DefaultActionSelector(IActionDescriptorsCollectionProvider actionDescriptorsCollectionProvider,
IActionBindingContextProvider bindingProvider)
IActionBindingContextProvider bindingProvider,
[NotNull] ILoggerFactory loggerFactory)
{
_actionDescriptorsCollectionProvider = actionDescriptorsCollectionProvider;
_bindingProvider = bindingProvider;
_logger = loggerFactory.Create<DefaultActionSelector>();
}
public async Task<ActionDescriptor> SelectAsync([NotNull] RouteContext context)
{
var allDescriptors = GetActions();
var matching = allDescriptors.Where(ad => Match(ad, context)).ToList();
var matchesWithConstraints = new List<ActionDescriptor>();
foreach (var match in matching)
using (_logger.BeginScope("DefaultActionSelector.SelectAsync"))
{
if (match.DynamicConstraints != null && match.DynamicConstraints.Any() ||
match.MethodConstraints != null && match.MethodConstraints.Any())
var allDescriptors = GetActions();
var matchingRouteConstraints =
allDescriptors.Where(ad =>
MatchRouteConstraints(ad, context)).ToList();
var matchingRouteAndMethodConstraints =
matchingRouteConstraints.Where(ad =>
MatchMethodConstraints(ad, context)).ToList();
var matchingRouteAndMethodAndDynamicConstraints =
matchingRouteAndMethodConstraints.Where(ad =>
MatchDynamicConstraints(ad, context)).ToList();
var matching = matchingRouteAndMethodAndDynamicConstraints;
var matchesWithConstraints = new List<ActionDescriptor>();
foreach (var match in matching)
{
matchesWithConstraints.Add(match);
if (match.DynamicConstraints != null && match.DynamicConstraints.Any() ||
match.MethodConstraints != null && match.MethodConstraints.Any())
{
matchesWithConstraints.Add(match);
}
}
}
// If any action that's applicable has constraints, this is considered better than
// an action without.
if (matchesWithConstraints.Any())
{
matching = matchesWithConstraints;
}
// If any action that's applicable has constraints, this is considered better than
// an action without.
if (matchesWithConstraints.Any())
{
matching = matchesWithConstraints;
}
if (matching.Count == 0)
{
return null;
}
else
{
return await SelectBestCandidate(context, matching);
if (matching.Count == 0)
{
if (_logger.IsEnabled(TraceType.Information))
{
_logger.WriteValues(new DefaultActionSelectorSelectAsyncValues()
{
ActionsMatchingRouteConstraints = matchingRouteConstraints,
ActionsMatchingRouteAndMethodConstraints = matchingRouteAndMethodConstraints,
ActionsMatchingRouteAndMethodAndDynamicConstraints =
matchingRouteAndMethodAndDynamicConstraints,
ActionsMatchingWithConstraints = matchesWithConstraints
});
}
return null;
}
else
{
var selectedAction = await SelectBestCandidate(context, matching);
if (_logger.IsEnabled(TraceType.Information))
{
_logger.WriteValues(new DefaultActionSelectorSelectAsyncValues()
{
ActionsMatchingRouteConstraints = matchingRouteConstraints,
ActionsMatchingRouteAndMethodConstraints = matchingRouteAndMethodConstraints,
ActionsMatchingRouteAndMethodAndDynamicConstraints =
matchingRouteAndMethodAndDynamicConstraints,
ActionsMatchingWithConstraints = matchesWithConstraints,
SelectedAction = selectedAction
});
}
return selectedAction;
}
}
}
public bool Match(ActionDescriptor descriptor, RouteContext context)
private bool MatchRouteConstraints(ActionDescriptor descriptor, RouteContext context)
{
if (descriptor == null)
{
throw new ArgumentNullException("descriptor");
}
return descriptor.RouteConstraints == null ||
descriptor.RouteConstraints.All(c => c.Accept(context));
}
return (descriptor.RouteConstraints == null ||
descriptor.RouteConstraints.All(c => c.Accept(context))) &&
(descriptor.MethodConstraints == null ||
descriptor.MethodConstraints.All(c => c.Accept(context))) &&
(descriptor.DynamicConstraints == null ||
descriptor.DynamicConstraints.All(c => c.Accept(context)));
private bool MatchMethodConstraints(ActionDescriptor descriptor, RouteContext context)
{
return descriptor.MethodConstraints == null ||
descriptor.MethodConstraints.All(c => c.Accept(context));
}
private bool MatchDynamicConstraints(ActionDescriptor descriptor, RouteContext context)
{
return descriptor.DynamicConstraints == null ||
descriptor.DynamicConstraints.All(c => c.Accept(context));
}
protected virtual async Task<ActionDescriptor> SelectBestCandidate(

View File

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNet.Routing;
@ -11,8 +10,6 @@ namespace Microsoft.AspNet.Mvc
{
Task<ActionDescriptor> SelectAsync(RouteContext context);
bool Match(ActionDescriptor descriptor, RouteContext context);
bool HasValidAction(VirtualPathContext context);
}
}

View File

@ -0,0 +1,61 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNet.Routing.Template;
namespace Microsoft.AspNet.Mvc.Logging
{
/// <summary>
/// Represents the state of <see cref="Microsoft.AspNet.Mvc.Routing.AttributeRoute.RouteAsync(
/// AspNet.Routing.RouteContext)"/>.
/// </summary>
public class AttributeRouteRouteAsyncValues
{
/// <summary>
/// The name of the state.
/// </summary>
public string Name
{
get
{
return "AttributeRoute.RouteAsync";
}
}
/// <summary>
/// The matching routes.
/// </summary>
public IList<TemplateRoute> MatchingRoutes { get; set; }
/// <summary>
/// True if the request is handled.
/// </summary>
public bool Handled { get; set; }
/// <summary>
/// A summary of the data for display.
/// </summary>
public string Summary
{
get
{
var builder = new StringBuilder();
builder.AppendLine(Name);
builder.Append("\tMatching routes: ");
StringBuilderHelpers.Append(builder, MatchingRoutes);
builder.AppendLine();
builder.Append("\tHandled? ");
builder.Append(Handled);
return builder.ToString();
}
}
/// <inheritdoc/>
public override string ToString()
{
return Summary;
}
}
}

View File

@ -0,0 +1,88 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Text;
namespace Microsoft.AspNet.Mvc.Logging
{
/// <summary>
/// Represents the state of <see cref="DefaultActionSelector.SelectAsync(AspNet.Routing.RouteContext)"/>.
/// </summary>
public class DefaultActionSelectorSelectAsyncValues
{
/// <summary>
/// The name of the state.
/// </summary>
public string Name
{
get
{
return "DefaultActionSelector.SelectAsync";
}
}
/// <summary>
/// The list of actions that matched all their route constraints, if any.
/// </summary>
public IList<ActionDescriptor> ActionsMatchingRouteConstraints { get; set; }
/// <summary>
/// The list of actions that matched all their route and method constraints, if any.
/// </summary>
public IList<ActionDescriptor> ActionsMatchingRouteAndMethodConstraints { get; set; }
/// <summary>
/// The list of actions that matched all their route, method, and dynamic constraints, if any.
/// </summary>
public IList<ActionDescriptor> ActionsMatchingRouteAndMethodAndDynamicConstraints { get; set; }
/// <summary>
/// The actions that matched with at least one constraint.
/// </summary>
public IList<ActionDescriptor> ActionsMatchingWithConstraints { get; set; }
/// <summary>
/// The selected action.
/// </summary>
public ActionDescriptor SelectedAction { get; set; }
/// <summary>
/// A summary of the data for display.
/// </summary>
public string Summary
{
get
{
var builder = new StringBuilder();
builder.AppendLine(Name);
builder.Append("\tActions matching route constraints: ");
StringBuilderHelpers.Append(builder, ActionsMatchingRouteConstraints, Formatter);
builder.AppendLine();
builder.Append("\tActions matching route and method constraints: ");
StringBuilderHelpers.Append(builder, ActionsMatchingRouteAndMethodConstraints, Formatter);
builder.AppendLine();
builder.Append("\tActions matching route, method, and dynamic constraints: ");
StringBuilderHelpers.Append(builder, ActionsMatchingRouteAndMethodAndDynamicConstraints, Formatter);
builder.AppendLine();
builder.Append("\tActions matching with at least one constraint: ");
StringBuilderHelpers.Append(builder, ActionsMatchingWithConstraints, Formatter);
builder.AppendLine();
builder.Append("\tSelected action: ");
builder.Append(Formatter(SelectedAction));
return builder.ToString();
}
}
/// <inheritdoc/>
public override string ToString()
{
return Summary;
}
private string Formatter(ActionDescriptor descriptor)
{
return descriptor.DisplayName;
}
}
}

View File

@ -0,0 +1,37 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNet.Mvc.Logging
{
public static class LogFormatter
{
/// <summary>
/// A formatter for use with <see cref="Microsoft.Framework.Logging.ILogger.WriteCore(
/// Framework.Logging.TraceType,
/// int,
/// object,
/// Exception, Func{object, Exception, string})"/>.
/// </summary>
public static string Formatter(object o, Exception e)
{
if (o != null && e != null)
{
return o + Environment.NewLine + e;
}
if (o != null)
{
return o.ToString();
}
if (e != null)
{
return e.ToString();
}
return "";
}
}
}

View File

@ -0,0 +1,20 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Mvc.Logging
{
internal static class LoggerExtensions
{
public static bool WriteValues([NotNull] this ILogger logger, object values)
{
return logger.WriteCore(
eventType: TraceType.Information,
eventId: 0,
state: values,
exception: null,
formatter: LogFormatter.Formatter);
}
}
}

View File

@ -0,0 +1,66 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Text;
namespace Microsoft.AspNet.Mvc.Logging
{
/// <summary>
/// Represents the state of <see cref="MvcRouteHandler.RouteAsync(AspNet.Routing.RouteContext)"/>.
/// </summary>
public class MvcRouteHandlerRouteAsyncValues
{
/// <summary>
/// The name of the state.
/// </summary>
public string Name
{
get
{
return "MvcRouteHandler.RouteAsync";
}
}
/// <summary>
/// True if an action was selected.
/// </summary>
public bool ActionSelected { get; set; }
/// <summary>
/// True if the selected action was invoked.
/// </summary>
public bool ActionInvoked { get; set; }
/// <summary>
/// True if the request is handled.
/// </summary>
public bool Handled { get; set; }
/// <summary>
/// A summary of the data for display.
/// </summary>
public string Summary
{
get
{
var builder = new StringBuilder();
builder.AppendLine(Name);
builder.Append("\tAction selected? ");
builder.Append(ActionSelected);
builder.AppendLine();
builder.Append("\tAction invoked? ");
builder.Append(ActionInvoked);
builder.AppendLine();
builder.Append("\tHandled? ");
builder.Append(Handled);
return builder.ToString();
}
}
/// <inheritdoc/>
public override string ToString()
{
return Summary;
}
}
}

View File

@ -0,0 +1,55 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.AspNet.Mvc.Logging
{
internal static class StringBuilderHelpers
{
public static void Append<T>(
StringBuilder builder,
IEnumerable<T> items,
Func<T, string> itemFormatter = null)
{
if (items == null)
{
return;
}
foreach (var item in items)
{
builder.Append(Environment.NewLine);
builder.Append("\t\t");
if (itemFormatter == null)
{
builder.Append(item != null ? item.ToString() : "null");
}
else
{
builder.Append(item != null ? itemFormatter(item) : "null");
}
}
}
public static void Append<K, V>(StringBuilder builder, IDictionary<K, V> dict)
{
if (dict == null)
{
return;
}
foreach (var kvp in dict)
{
builder.Append(Environment.NewLine);
builder.Append("\t\t");
builder.Append(kvp.Key != null ? kvp.Key.ToString() : "null");
builder.Append(" : ");
builder.Append(kvp.Value != null ? kvp.Value.ToString() : "null");
}
}
}
}

View File

@ -31,6 +31,10 @@
<Compile Include="ActionDescriptorsCollection.cs" />
<Compile Include="ActionResults\HttpNotFoundResult.cs" />
<Compile Include="Formatters\TextPlainFormatter.cs" />
<Compile Include="Logging\AttributeRouteRouteAsyncValues.cs" />
<Compile Include="Logging\LoggerExtensions.cs" />
<Compile Include="Logging\MvcRouteHandlerRouteAsyncValues.cs" />
<Compile Include="Logging\StringBuilderHelpers.cs" />
<Compile Include="OptionDescriptors\DefaultModelBinderProvider.cs" />
<Compile Include="OptionDescriptors\DefaultValueProviderFactoryProvider.cs" />
<Compile Include="OptionDescriptors\DefaultViewEngineProvider.cs" />
@ -44,11 +48,9 @@
<Compile Include="OptionDescriptors\ViewEngineDescriptor.cs" />
<Compile Include="OptionDescriptors\ValueProviderFactoryDescriptorExtensions.cs" />
<Compile Include="OptionDescriptors\ViewEngineDescriptorExtensions.cs" />
<Compile Include="ExpiringFileInfoCache.cs" />
<Compile Include="Formatters\DefaultOutputFormattersProvider.cs" />
<Compile Include="Formatters\IOutputFormatter.cs" />
<Compile Include="Formatters\StringWithQualityHeaderValueComparer.cs" />
<Compile Include="IExpiringFileInfoCache.cs" />
<Compile Include="Formatters\IOutputFormattersProvider.cs" />
<Compile Include="Formatters\OutputFormatterContext.cs" />
<Compile Include="Formatters\HeaderParsingHelpers.cs" />
@ -56,12 +58,6 @@
<Compile Include="Formatters\MediaTypeWithQualityHeaderValueComparer.cs" />
<Compile Include="Formatters\OutputFormatter.cs" />
<Compile Include="ParameterBinding\ModelBindingHelper.cs" />
<Compile Include="ReflectedActionDescriptor.cs" />
<Compile Include="ReflectedActionDescriptorProvider.cs" />
<Compile Include="ReflectedModelBuilder\IReflectedApplicationModelConvention.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedActionModel.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedControllerModel.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedApplicationModel.cs" />
<Compile Include="ActionInvokerFactory.cs" />
<Compile Include="ActionInvokerProviderContext.cs" />
<Compile Include="ActionMethodSelectorAttribute.cs" />
@ -103,8 +99,10 @@
<Compile Include="DefaultActionDescriptorsCollectionProvider.cs" />
<Compile Include="DefaultActionDiscoveryConventions.cs" />
<Compile Include="DefaultActionSelector.cs" />
<Compile Include="DefaultControllerActivator.cs" />
<Compile Include="DefaultControllerAssemblyProvider.cs" />
<Compile Include="DefaultControllerFactory.cs" />
<Compile Include="ExpiringFileInfoCache.cs" />
<Compile Include="Extensions\IEnumerableExtensions.cs" />
<Compile Include="Filters\FilterItemOrderComparer.cs" />
<Compile Include="Filters\TypeFilterAttribute.cs" />
@ -163,11 +161,14 @@
<Compile Include="IActionSelector.cs" />
<Compile Include="IControllerActivator.cs" />
<Compile Include="IControllerAssemblyProvider.cs" />
<Compile Include="DefaultControllerActivator.cs" />
<Compile Include="IControllerFactory.cs" />
<Compile Include="IExpiringFileInfoCache.cs" />
<Compile Include="Injector.cs" />
<Compile Include="Internal\TypeHelper.cs" />
<Compile Include="IUrlHelper.cs" />
<Compile Include="KnownRouteValueConstraint.cs" />
<Compile Include="Logging\DefaultActionSelectorSelectAsyncValues.cs" />
<Compile Include="Logging\LogFormatter.cs" />
<Compile Include="MvcOptions.cs" />
<Compile Include="MvcRouteHandler.cs" />
<Compile Include="NonActionAttribute.cs" />
@ -179,9 +180,15 @@
<Compile Include="ParameterDescriptor.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\Resources.Designer.cs" />
<Compile Include="ReflectedActionDescriptor.cs" />
<Compile Include="ReflectedActionDescriptorProvider.cs" />
<Compile Include="ReflectedActionExecutor.cs" />
<Compile Include="ReflectedActionInvoker.cs" />
<Compile Include="ReflectedActionInvokerProvider.cs" />
<Compile Include="ReflectedModelBuilder\IReflectedApplicationModelConvention.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedActionModel.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedApplicationModel.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedControllerModel.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedParameterModel.cs" />
<Compile Include="Rendering\CompositeViewEngine.cs" />
<Compile Include="Rendering\DynamicViewData.cs" />
@ -227,16 +234,15 @@
<Compile Include="Rendering\IViewEngineProvider.cs" />
<Compile Include="Rendering\MultiSelectList.cs" />
<Compile Include="Rendering\MvcForm.cs" />
<Compile Include="Rendering\RazorViewEngineOptions.cs" />
<Compile Include="Rendering\SelectList.cs" />
<Compile Include="Rendering\SelectListGroup.cs" />
<Compile Include="Rendering\SelectListItem.cs" />
<Compile Include="Rendering\UnobtrusiveValidationAttributesGenerator.cs" />
<Compile Include="Rendering\RazorViewEngineOptions.cs" />
<Compile Include="Rendering\ViewEngineResult.cs" />
<Compile Include="RouteAttribute.cs" />
<Compile Include="RouteConstraintAttribute.cs" />
<Compile Include="RouteDataActionConstraint.cs" />
<Compile Include="KnownRouteValueConstraint.cs" />
<Compile Include="RouteKeyHandling.cs" />
<Compile Include="Routing\AttributeRoute.cs" />
<Compile Include="Routing\AttributeRouteLinkGenerationEntry.cs" />

View File

@ -4,14 +4,19 @@
using System;
using System.Diagnostics.Contracts;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Mvc
{
public class MvcRouteHandler : IRouter
{
private ILogger _logger;
public string GetVirtualPath([NotNull] VirtualPathContext context)
{
// The contract of this method is to check that the values coming in from the route are valid;
@ -31,12 +36,27 @@ namespace Microsoft.AspNet.Mvc
// TODO: Throw an error here that's descriptive enough so that
// users understand they should call the per request scoped middleware
// or set HttpContext.Services manually
var actionSelector = services.GetService<IActionSelector>();
var actionDescriptor = await actionSelector.SelectAsync(context);
if (actionDescriptor == null)
EnsureLogger(context.HttpContext);
using (_logger.BeginScope("MvcRouteHandler.RouteAsync"))
{
return;
}
var actionSelector = services.GetService<IActionSelector>();
var actionDescriptor = await actionSelector.SelectAsync(context);
if (actionDescriptor == null)
{
if (_logger.IsEnabled(TraceType.Information))
{
_logger.WriteValues(new MvcRouteHandlerRouteAsyncValues()
{
ActionSelected = false,
ActionInvoked = false,
Handled = context.IsHandled
});
}
return;
}
if (actionDescriptor.RouteValueDefaults != null)
{
@ -49,28 +69,49 @@ namespace Microsoft.AspNet.Mvc
}
}
var actionContext = new ActionContext(context.HttpContext, context.RouteData, actionDescriptor);
var actionContext = new ActionContext(context.HttpContext, context.RouteData, actionDescriptor);
var contextAccessor = services.GetService<IContextAccessor<ActionContext>>();
using (contextAccessor.SetContextSource(() => actionContext, PreventExchange))
{
var invokerFactory = services.GetService<IActionInvokerFactory>();
var invoker = invokerFactory.CreateInvoker(actionContext);
if (invoker == null)
var contextAccessor = services.GetService<IContextAccessor<ActionContext>>();
using (contextAccessor.SetContextSource(() => actionContext, PreventExchange))
{
var ex = new InvalidOperationException(
Resources.FormatActionInvokerFactory_CouldNotCreateInvoker(actionDescriptor));
var invokerFactory = services.GetService<IActionInvokerFactory>();
var invoker = invokerFactory.CreateInvoker(actionContext);
if (invoker == null)
{
var ex = new InvalidOperationException(
Resources.FormatActionInvokerFactory_CouldNotCreateInvoker(
actionDescriptor.DisplayName));
// Add tracing/logging (what do we think of this pattern of
// tacking on extra data on the exception?)
ex.Data.Add("AD", actionDescriptor);
// Add tracing/logging (what do we think of this pattern of
// tacking on extra data on the exception?)
ex.Data.Add("AD", actionDescriptor);
throw ex;
if (_logger.IsEnabled(TraceType.Information))
{
_logger.WriteValues(new MvcRouteHandlerRouteAsyncValues()
{
ActionSelected = true,
ActionInvoked = false,
Handled = context.IsHandled
});
}
throw ex;
}
await invoker.InvokeActionAsync();
context.IsHandled = true;
if (_logger.IsEnabled(TraceType.Information))
{
_logger.WriteValues(new MvcRouteHandlerRouteAsyncValues()
{
ActionSelected = true,
ActionInvoked = true,
Handled = context.IsHandled
});
}
}
await invoker.InvokeActionAsync();
context.IsHandled = true;
}
}
@ -78,5 +119,14 @@ namespace Microsoft.AspNet.Mvc
{
throw new InvalidOperationException(Resources.ActionContextAccessor_SetValueNotSupported);
}
private void EnsureLogger(HttpContext context)
{
if (_logger == null)
{
var factory = context.RequestServices.GetService<ILoggerFactory>();
_logger = factory.Create<MvcRouteHandler>();
}
}
}
}

View File

@ -5,8 +5,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Routing.Template;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Mvc.Routing
{
@ -18,6 +20,8 @@ namespace Microsoft.AspNet.Mvc.Routing
private readonly IRouter _next;
private readonly TemplateRoute[] _matchingRoutes;
private readonly AttributeRouteLinkGenerationEntry[] _linkGenerationEntries;
private ILogger _logger;
private ILogger _constraintLogger;
/// <summary>
/// Creates a new <see cref="AttributeRoute"/>.
@ -25,9 +29,10 @@ namespace Microsoft.AspNet.Mvc.Routing
/// <param name="next">The next router. Invoked when a route entry matches.</param>
/// <param name="entries">The set of route entries.</param>
public AttributeRoute(
[NotNull] IRouter next,
[NotNull] IRouter next,
[NotNull] IEnumerable<AttributeRouteMatchingEntry> matchingEntries,
[NotNull] IEnumerable<AttributeRouteLinkGenerationEntry> linkGenerationEntries)
[NotNull] IEnumerable<AttributeRouteLinkGenerationEntry> linkGenerationEntries,
[NotNull] ILoggerFactory factory)
{
_next = next;
@ -38,17 +43,33 @@ namespace Microsoft.AspNet.Mvc.Routing
// FOR RIGHT NOW - this is just an array of entries. We'll follow up by implementing
// a good data-structure here. See #741
_linkGenerationEntries = linkGenerationEntries.OrderBy(e => e.Precedence).ToArray();
_logger = factory.Create<AttributeRoute>();
_constraintLogger = factory.Create(typeof(RouteConstraintMatcher).FullName);
}
/// <inheritdoc />
public async Task RouteAsync([NotNull] RouteContext context)
{
foreach (var route in _matchingRoutes)
using (_logger.BeginScope("AttributeRoute.RouteAsync"))
{
await route.RouteAsync(context);
if (context.IsHandled)
foreach (var route in _matchingRoutes)
{
return;
await route.RouteAsync(context);
if (context.IsHandled)
{
break;
}
}
if (_logger.IsEnabled(TraceType.Information))
{
_logger.WriteValues(new AttributeRouteRouteAsyncValues()
{
MatchingRoutes = _matchingRoutes,
Handled = context.IsHandled
});
}
}
}
@ -130,7 +151,9 @@ namespace Microsoft.AspNet.Mvc.Routing
bindingResult.CombinedValues,
context.Context,
this,
RouteDirection.UrlGeneration);
RouteDirection.UrlGeneration,
_constraintLogger);
if (!matched)
{
// A constraint rejected this link.

View File

@ -8,6 +8,7 @@ using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Routing.Template;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Mvc.Routing
{
@ -69,7 +70,11 @@ namespace Microsoft.AspNet.Mvc.Routing
});
}
return new AttributeRoute(target, matchingEntries, generationEntries);
return new AttributeRoute(
target,
matchingEntries,
generationEntries,
services.GetService<ILoggerFactory>());
}
private static IReadOnlyList<ActionDescriptor> GetActionDescriptors(IServiceProvider services)

View File

@ -14,6 +14,7 @@
"Microsoft.AspNet.Security.DataProtection" : "1.0.0-*",
"Microsoft.Framework.DependencyInjection": "1.0.0-*",
"Microsoft.Framework.Runtime.Interfaces": "1.0.0-*",
"Microsoft.Framework.Logging": "1.0.0-*",
"Microsoft.Framework.OptionsModel": "1.0.0-*",
"Newtonsoft.Json": "5.0.8"
},

View File

@ -16,7 +16,7 @@ using Microsoft.Framework.DependencyInjection.NestedProviders;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Test
namespace Microsoft.AspNet.Mvc
{
public class ActionAttributeTests
{
@ -199,7 +199,8 @@ namespace Microsoft.AspNet.Mvc.Test
var bindingProvider = new Mock<IActionBindingContextProvider>();
var defaultActionSelector = new DefaultActionSelector(actionCollectionDescriptorProvider,
bindingProvider.Object);
bindingProvider.Object,
NullLoggerFactory.Instance);
return await defaultActionSelector.SelectAsync(context);
}

View File

@ -16,7 +16,7 @@ using Microsoft.Framework.DependencyInjection.NestedProviders;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Test
namespace Microsoft.AspNet.Mvc
{
public class DefaultActionDiscoveryConventionsActionSelectionTests
{
@ -178,7 +178,8 @@ namespace Microsoft.AspNet.Mvc.Test
var bindingProvider = new Mock<IActionBindingContextProvider>();
var defaultActionSelector = new DefaultActionSelector(actionCollectionDescriptorProvider,
bindingProvider.Object);
bindingProvider.Object,
NullLoggerFactory.Instance);
return await defaultActionSelector.SelectAsync(context);
}
@ -202,7 +203,6 @@ namespace Microsoft.AspNet.Mvc.Test
var headers = new Mock<IHeaderDictionary>();
request.SetupGet(r => r.Headers).Returns(headers.Object);
request.SetupGet(x => x.Method).Returns(httpMethod);
var httpContext = new Mock<HttpContext>();
httpContext.SetupGet(c => c.Request).Returns(request.Object);
return httpContext.Object;

View File

@ -7,13 +7,110 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.Framework.Logging;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Core.Test
namespace Microsoft.AspNet.Mvc
{
public class DefaultActionSelectorTest
public class DefaultActionSelectorTests
{
[Fact]
public async void SelectAsync_NoMatchedActions_LogIsCorrect()
{
// Arrange
var sink = new TestSink();
var loggerFactory = new TestLoggerFactory(sink);
var routeContext = CreateRouteContext("POST");
var actions = new ActionDescriptor[0];
var selector = CreateSelector(actions, loggerFactory);
// Act
var action = await selector.SelectAsync(routeContext);
// Assert
Assert.Equal(1, sink.Scopes.Count);
var scope = sink.Scopes[0];
Assert.Equal(typeof(DefaultActionSelector).FullName, scope.LoggerName);
Assert.Equal("DefaultActionSelector.SelectAsync", scope.Scope);
// There is a record for IsEnabled and one for WriteCore.
Assert.Equal(2, sink.Writes.Count);
var enabled = sink.Writes[0];
Assert.Equal(typeof(DefaultActionSelector).FullName, enabled.LoggerName);
Assert.Equal("DefaultActionSelector.SelectAsync", enabled.Scope);
Assert.Null(enabled.State);
var write = sink.Writes[1];
Assert.Equal(typeof(DefaultActionSelector).FullName, write.LoggerName);
Assert.Equal("DefaultActionSelector.SelectAsync", write.Scope);
var values = Assert.IsType<DefaultActionSelectorSelectAsyncValues>(write.State);
Assert.Equal("DefaultActionSelector.SelectAsync", values.Name);
Assert.Empty(values.ActionsMatchingRouteConstraints);
Assert.Empty(values.ActionsMatchingRouteAndMethodConstraints);
Assert.Empty(values.ActionsMatchingRouteAndMethodAndDynamicConstraints);
Assert.Empty(values.ActionsMatchingWithConstraints);
Assert.Null(values.SelectedAction);
}
[Fact]
public async void SelectAsync_MatchedActions_LogIsCorrect()
{
// Arrange
var sink = new TestSink();
var loggerFactory = new TestLoggerFactory(sink);
var matched = new ActionDescriptor()
{
MethodConstraints = new List<HttpMethodConstraint>()
{
new HttpMethodConstraint(new string[] { "POST" }),
},
Parameters = new List<ParameterDescriptor>(),
};
var notMatched = new ActionDescriptor()
{
Parameters = new List<ParameterDescriptor>(),
};
var actions = new ActionDescriptor[] { matched, notMatched };
var selector = CreateSelector(actions, loggerFactory);
var routeContext = CreateRouteContext("POST");
// Act
var action = await selector.SelectAsync(routeContext);
// Assert
Assert.Equal(1, sink.Scopes.Count);
var scope = sink.Scopes[0];
Assert.Equal(typeof(DefaultActionSelector).FullName, scope.LoggerName);
Assert.Equal("DefaultActionSelector.SelectAsync", scope.Scope);
// There is a record for IsEnabled and one for WriteCore.
Assert.Equal(2, sink.Writes.Count);
var enabled = sink.Writes[0];
Assert.Equal(typeof(DefaultActionSelector).FullName, enabled.LoggerName);
Assert.Equal("DefaultActionSelector.SelectAsync", enabled.Scope);
Assert.Null(enabled.State);
var write = sink.Writes[1];
Assert.Equal(typeof(DefaultActionSelector).FullName, write.LoggerName);
Assert.Equal("DefaultActionSelector.SelectAsync", write.Scope);
var values = Assert.IsType<DefaultActionSelectorSelectAsyncValues>(write.State);
Assert.Equal("DefaultActionSelector.SelectAsync", values.Name);
Assert.NotEmpty(values.ActionsMatchingRouteConstraints);
Assert.NotEmpty(values.ActionsMatchingRouteAndMethodConstraints);
Assert.NotEmpty(values.ActionsMatchingWithConstraints);
Assert.Equal(matched, values.SelectedAction);
}
[Fact]
public void HasValidAction_Match()
{
@ -22,7 +119,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
var selector = CreateSelector(actions);
var context = CreateContext(new { });
context.ProvidedValues = new RouteValueDictionary(new { controller = "Home", action = "Index"});
context.ProvidedValues = new RouteValueDictionary(new { controller = "Home", action = "Index" });
// Act
var isValid = selector.HasValidAction(context);
@ -109,8 +206,10 @@ namespace Microsoft.AspNet.Mvc.Core.Test
.Where(a => a.RouteConstraints.Any(c => c.RouteKey == "action" && c.Comparer.Equals(c.RouteValue, action)));
}
private static DefaultActionSelector CreateSelector(IReadOnlyList<ActionDescriptor> actions)
private static DefaultActionSelector CreateSelector(IReadOnlyList<ActionDescriptor> actions, ILoggerFactory loggerFactory = null)
{
loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
var actionProvider = new Mock<IActionDescriptorsCollectionProvider>(MockBehavior.Strict);
actionProvider
@ -121,7 +220,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
.Setup(bp => bp.GetActionBindingContextAsync(It.IsAny<ActionContext>()))
.Returns(() => Task.FromResult<ActionBindingContext>(null));
return new DefaultActionSelector(actionProvider.Object, bindingProvider.Object);
return new DefaultActionSelector(actionProvider.Object, bindingProvider.Object, loggerFactory);
}
private static VirtualPathContext CreateContext(object routeValues)
@ -145,7 +244,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
};
routeData.Routers.Add(new Mock<IRouter>(MockBehavior.Strict).Object);
var httpContext = new Mock<HttpContext>(MockBehavior.Strict);
var request = new Mock<HttpRequest>(MockBehavior.Strict);

View File

@ -0,0 +1,12 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.Mvc
{
public class BeginScopeContext
{
public object Scope { get; set; }
public string LoggerName { get; set; }
}
}

View File

@ -0,0 +1,17 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNet.Mvc
{
public class NullDisposable : IDisposable
{
public static NullDisposable Instance = new NullDisposable();
public void Dispose()
{
// intentionally does nothing
}
}
}

View File

@ -0,0 +1,23 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Mvc
{
public class NullLogger : ILogger
{
public static NullLogger Instance = new NullLogger();
public IDisposable BeginScope(object state)
{
return NullDisposable.Instance;
}
public bool WriteCore(TraceType eventType, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
return false;
}
}
}

View File

@ -0,0 +1,17 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Mvc
{
public class NullLoggerFactory : ILoggerFactory
{
public static NullLoggerFactory Instance = new NullLoggerFactory();
public ILogger Create(string name)
{
return NullLogger.Instance;
}
}
}

View File

@ -0,0 +1,52 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Mvc
{
public class TestLogger : ILogger
{
private object _scope;
private TestSink _sink;
private string _name;
public TestLogger(string name, TestSink sink)
{
_sink = sink;
_name = name;
}
public string Name { get; set; }
public IDisposable BeginScope(object state)
{
_scope = state;
_sink.Begin(new BeginScopeContext()
{
LoggerName = _name,
Scope = state,
});
return NullDisposable.Instance;
}
public bool WriteCore(TraceType eventType, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
_sink.Write(new WriteCoreContext()
{
EventType = eventType,
EventId = eventId,
State = state,
Exception = exception,
Formatter = formatter,
LoggerName = _name,
Scope = _scope
});
return true;
}
}
}

View File

@ -0,0 +1,22 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Mvc
{
public class TestLoggerFactory : ILoggerFactory
{
private TestSink _sink;
public TestLoggerFactory(TestSink sink)
{
_sink = sink;
}
public ILogger Create(string name)
{
return new TestLogger(name, _sink);
}
}
}

View File

@ -0,0 +1,56 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
namespace Microsoft.AspNet.Mvc
{
public class TestSink
{
public TestSink(
Func<WriteCoreContext, bool> writeEnabled = null,
Func<BeginScopeContext, bool> beginEnabled = null)
{
WriteEnabled = writeEnabled;
BeginEnabled = beginEnabled;
Scopes = new List<BeginScopeContext>();
Writes = new List<WriteCoreContext>();
}
public Func<WriteCoreContext, bool> WriteEnabled { get; set; }
public Func<BeginScopeContext, bool> BeginEnabled { get; set; }
public List<BeginScopeContext> Scopes { get; set; }
public List<WriteCoreContext> Writes { get; set; }
public void Write(WriteCoreContext context)
{
if (WriteEnabled == null || WriteEnabled(context))
{
Writes.Add(context);
}
}
public void Begin(BeginScopeContext context)
{
if (BeginEnabled == null || BeginEnabled(context))
{
Scopes.Add(context);
}
}
public static bool EnableWithTypeName<T>(WriteCoreContext context)
{
return context.LoggerName.Equals(typeof(T).FullName);
}
public static bool EnableWithTypeName<T>(BeginScopeContext context)
{
return context.LoggerName.Equals(typeof(T).FullName);
}
}
}

View File

@ -0,0 +1,25 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Mvc
{
public class WriteCoreContext
{
public TraceType EventType { get; set; }
public int EventId { get; set; }
public object State { get; set; }
public Exception Exception { get; set; }
public Func<object, Exception, string> Formatter { get; set; }
public object Scope { get; set; }
public string LoggerName { get; set; }
}
}

View File

@ -25,14 +25,22 @@
<Compile Include="ActionExecutorTests.cs" />
<Compile Include="ActionResults\HttpNotFoundResultTests.cs" />
<Compile Include="ActionResults\HttpStatusCodeResultTests.cs" />
<Compile Include="ActionResults\ObjectContentResultTests.cs" />
<Compile Include="ActionResults\ChallengeResultTest.cs" />
<Compile Include="ActionResults\ObjectContentResultTests.cs" />
<Compile Include="ActionResults\RedirectResultTest.cs" />
<Compile Include="ActionResults\RedirectToActionResultTest.cs" />
<Compile Include="ActionResults\RedirectToRouteResultTest.cs" />
<Compile Include="ActionResults\RedirectResultTest.cs" />
<Compile Include="DefaultActionDiscoveryConventionsActionSelectionTests.cs" />
<Compile Include="AntiXsrf\AntiForgeryOptionsTests.cs" />
<Compile Include="Formatters\TextPlainFormatterTests.cs" />
<Compile Include="Logging\BeginScopeContext.cs" />
<Compile Include="Logging\TestLoggerFactory.cs" />
<Compile Include="Logging\WriteCoreContext.cs" />
<Compile Include="Logging\NullDisposable.cs" />
<Compile Include="Logging\NullLogger.cs" />
<Compile Include="Logging\NullLoggerFactory.cs" />
<Compile Include="Logging\TestSink.cs" />
<Compile Include="Logging\TestLogger.cs" />
<Compile Include="MvcRouteHandlerTests.cs" />
<Compile Include="OptionDescriptors\DefaultModelBindersProviderTest.cs" />
<Compile Include="OptionDescriptors\DefaultValueProviderFactoryProviderTest.cs" />
<Compile Include="OptionDescriptors\DefaultViewEngineProviderTest.cs" />
@ -44,20 +52,16 @@
<Compile Include="OptionDescriptors\ViewEngineDescriptorTest.cs" />
<Compile Include="OptionDescriptors\ValueProviderFactoryDescriptorExtensionsTest.cs" />
<Compile Include="OptionDescriptors\ViewEngineDscriptorExtensionsTest.cs" />
<Compile Include="ExpiringFileInfoCacheTest.cs" />
<Compile Include="DefaultActionDiscoveryConventionsTests.cs" />
<Compile Include="Formatters\OutputFormatterTests.cs" />
<Compile Include="MediaTypeWithQualityHeaderValueTests.cs" />
<Compile Include="ParameterBinding\ModelBindingHelperTest.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedParameterModelTests.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedActionModelTests.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedControllerModelTests.cs" />
<Compile Include="MockMvcOptionsAccessor.cs" />
<Compile Include="MvcOptionsTests.cs" />
<Compile Include="AntiXsrf\AntiForgeryTokenSerializerTest.cs" />
<Compile Include="AntiXsrf\ITokenProvider.cs" />
<Compile Include="AntiXsrf\ValidateAntiForgeryTokenAttributeTest.cs" />
<Compile Include="DefaultActionDiscoveryConventionsActionSelectionTests.cs" />
<Compile Include="DefaultActionDiscoveryConventionsTests.cs" />
<Compile Include="DefaultControllerActivatorTest.cs" />
<Compile Include="ExpiringFileInfoCacheTest.cs" />
<Compile Include="Filters\ActionFilterAttributeTests.cs" />
<Compile Include="Filters\AuthorizeAttributeTests.cs" />
<Compile Include="Filters\AuthorizeAttributeTestsBase.cs" />
@ -69,19 +73,25 @@
<Compile Include="AntiXsrf\MockClaimsIdentity.cs" />
<Compile Include="AntiXsrf\TokenProviderTests.cs" />
<Compile Include="ControllerTests.cs" />
<Compile Include="DefaultActionSelectorTest.cs" />
<Compile Include="DefaultActionSelectorTests.cs" />
<Compile Include="DefaultControllerAssemblyProviderTests.cs" />
<Compile Include="DefaultControllerFactoryTest.cs" />
<Compile Include="Filters\ResultFilterAttributeTest.cs" />
<Compile Include="JsonResultTest.cs" />
<Compile Include="KnownRouteValueConstraintTests.cs" />
<Compile Include="MockMvcOptionsAccessor.cs" />
<Compile Include="MvcOptionsTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyHelperTest.cs" />
<Compile Include="ReflectedActionDescriptorProviderTests.cs" />
<Compile Include="ReflectedActionInvokerTest.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedActionModelTests.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedControllerModelTests.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedParameterModelTests.cs" />
<Compile Include="Rendering\CompositeViewEngineTest.cs" />
<Compile Include="Rendering\DefaultTemplatesUtilities.cs" />
<Compile Include="Rendering\DefaultDisplayTemplatesTests.cs" />
<Compile Include="Rendering\DefaultEditorTemplatesTests.cs" />
<Compile Include="Rendering\DefaultTemplatesUtilities.cs" />
<Compile Include="Rendering\HtmlHelperDisplayNameExtensionsTest.cs" />
<Compile Include="Rendering\HtmlAttributePropertyHelperTest.cs" />
<Compile Include="Rendering\HtmlHelperLabelExtensionsTest.cs" />
@ -96,10 +106,9 @@
<Compile Include="Routing\AttributeRouteTests.cs" />
<Compile Include="TestController.cs" />
<Compile Include="TypeHelperTest.cs" />
<Compile Include="StaticActionDiscoveryConventions.cs" />
<Compile Include="UrlHelperTest.cs" />
<Compile Include="ViewResultTest.cs" />
<Compile Include="ViewComponentTests.cs" />
<Compile Include="ViewResultTest.cs" />
</ItemGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -3,7 +3,7 @@
using Microsoft.Framework.OptionsModel;
namespace Microsoft.AspNet.Mvc.Test
namespace Microsoft.AspNet.Mvc
{
public class MockMvcOptionsAccessor : IOptionsAccessor<MvcOptions>
{

View File

@ -0,0 +1,199 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc
{
public class MvcRouteHandlerTests
{
[Fact]
public async void RouteAsync_Success_LogsCorrectValues()
{
// Arrange
var sink = new TestSink();
var loggerFactory = new TestLoggerFactory(sink);
var context = CreateRouteContext(loggerFactory: loggerFactory);
var handler = new MvcRouteHandler();
// Act
await handler.RouteAsync(context);
// Assert
Assert.Equal(1, sink.Scopes.Count);
var scope = sink.Scopes[0];
Assert.Equal(typeof(MvcRouteHandler).FullName, scope.LoggerName);
Assert.Equal("MvcRouteHandler.RouteAsync", scope.Scope);
// There is a record for IsEnabled and one for WriteCore.
Assert.Equal(2, sink.Writes.Count);
var enabled = sink.Writes[0];
Assert.Equal(typeof(MvcRouteHandler).FullName, enabled.LoggerName);
Assert.Equal("MvcRouteHandler.RouteAsync", enabled.Scope);
Assert.Null(enabled.State);
var write = sink.Writes[1];
Assert.Equal(typeof(MvcRouteHandler).FullName, write.LoggerName);
Assert.Equal("MvcRouteHandler.RouteAsync", write.Scope);
var values = Assert.IsType<MvcRouteHandlerRouteAsyncValues>(write.State);
Assert.Equal("MvcRouteHandler.RouteAsync", values.Name);
Assert.Equal(true, values.ActionSelected);
Assert.Equal(true, values.ActionInvoked);
Assert.Equal(true, values.Handled);
}
[Fact]
public async void RouteAsync_FailOnNoAction_LogsCorrectValues()
{
// Arrange
var sink = new TestSink();
var loggerFactory = new TestLoggerFactory(sink);
var mockActionSelector = new Mock<IActionSelector>();
mockActionSelector.Setup(a => a.SelectAsync(It.IsAny<RouteContext>()))
.Returns(Task.FromResult<ActionDescriptor>(null));
var context = CreateRouteContext(
actionSelector: mockActionSelector.Object,
loggerFactory: loggerFactory);
var handler = new MvcRouteHandler();
// Act
await handler.RouteAsync(context);
// Assert
Assert.Equal(1, sink.Scopes.Count);
var scope = sink.Scopes[0];
Assert.Equal(typeof(MvcRouteHandler).FullName, scope.LoggerName);
Assert.Equal("MvcRouteHandler.RouteAsync", scope.Scope);
// There is a record for IsEnabled and one for WriteCore.
Assert.Equal(2, sink.Writes.Count);
var enabled = sink.Writes[0];
Assert.Equal(typeof(MvcRouteHandler).FullName, enabled.LoggerName);
Assert.Equal("MvcRouteHandler.RouteAsync", enabled.Scope);
Assert.Null(enabled.State);
var write = sink.Writes[1];
Assert.Equal(typeof(MvcRouteHandler).FullName, write.LoggerName);
Assert.Equal("MvcRouteHandler.RouteAsync", write.Scope);
var values = Assert.IsType<MvcRouteHandlerRouteAsyncValues>(write.State);
Assert.Equal("MvcRouteHandler.RouteAsync", values.Name);
Assert.Equal(false, values.ActionSelected);
Assert.Equal(false, values.ActionInvoked);
Assert.Equal(false, values.Handled);
}
[Fact]
public async void RouteAsync_FailOnNoInvoker_LogsCorrectValues()
{
// Arrange
var sink = new TestSink();
var loggerFactory = new TestLoggerFactory(sink);
var mockInvokerFactory = new Mock<IActionInvokerFactory>();
mockInvokerFactory.Setup(f => f.CreateInvoker(It.IsAny<ActionContext>()))
.Returns<IActionInvoker>(null);
var context = CreateRouteContext(
invokerFactory: mockInvokerFactory.Object,
loggerFactory: loggerFactory);
var handler = new MvcRouteHandler();
// Act
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
await handler.RouteAsync(context));
// Assert
Assert.Equal(1, sink.Scopes.Count);
var scope = sink.Scopes[0];
Assert.Equal(typeof(MvcRouteHandler).FullName, scope.LoggerName);
Assert.Equal("MvcRouteHandler.RouteAsync", scope.Scope);
// There is a record for IsEnabled and one for WriteCore.
Assert.Equal(2, sink.Writes.Count);
var enabled = sink.Writes[0];
Assert.Equal(typeof(MvcRouteHandler).FullName, enabled.LoggerName);
Assert.Equal("MvcRouteHandler.RouteAsync", enabled.Scope);
Assert.Null(enabled.State);
var write = sink.Writes[1];
Assert.Equal(typeof(MvcRouteHandler).FullName, write.LoggerName);
Assert.Equal("MvcRouteHandler.RouteAsync", write.Scope);
var values = Assert.IsType<MvcRouteHandlerRouteAsyncValues>(write.State);
Assert.Equal("MvcRouteHandler.RouteAsync", values.Name);
Assert.Equal(true, values.ActionSelected);
Assert.Equal(false, values.ActionInvoked);
Assert.Equal(false, values.Handled);
}
private RouteContext CreateRouteContext(
IActionSelector actionSelector = null,
IActionInvokerFactory invokerFactory = null,
ILoggerFactory loggerFactory = null)
{
var mockContextAccessor = new Mock<IContextAccessor<ActionContext>>();
mockContextAccessor.Setup(c => c.SetContextSource(
It.IsAny<Func<ActionContext>>(),
It.IsAny<Func<ActionContext, ActionContext>>()))
.Returns(NullDisposable.Instance);
if (actionSelector == null)
{
var mockAction = new Mock<ActionDescriptor>();
var mockActionSelector = new Mock<IActionSelector>();
mockActionSelector.Setup(a => a.SelectAsync(It.IsAny<RouteContext>()))
.Returns(Task.FromResult(mockAction.Object));
actionSelector = mockActionSelector.Object;
}
if (invokerFactory == null)
{
var mockInvoker = new Mock<IActionInvoker>();
mockInvoker.Setup(i => i.InvokeActionAsync())
.Returns(Task.FromResult<object>(null));
var mockInvokerFactory = new Mock<IActionInvokerFactory>();
mockInvokerFactory.Setup(f => f.CreateInvoker(It.IsAny<ActionContext>()))
.Returns(mockInvoker.Object);
invokerFactory = mockInvokerFactory.Object;
}
if (loggerFactory == null)
{
loggerFactory = NullLoggerFactory.Instance;
}
var httpContext = new Mock<HttpContext>();
httpContext.Setup(h => h.RequestServices.GetService(typeof(IContextAccessor<ActionContext>)))
.Returns(mockContextAccessor.Object);
httpContext.Setup(h => h.RequestServices.GetService(typeof(IActionSelector)))
.Returns(actionSelector);
httpContext.Setup(h => h.RequestServices.GetService(typeof(IActionInvokerFactory)))
.Returns(invokerFactory);
httpContext.Setup(h => h.RequestServices.GetService(typeof(ILoggerFactory)))
.Returns(loggerFactory);
return new RouteContext(httpContext.Object);
}
}
}

View File

@ -8,7 +8,9 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Routing.Template;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.Framework.OptionsModel;
using Microsoft.Framework.Logging;
using Moq;
using Xunit;
@ -16,6 +18,80 @@ namespace Microsoft.AspNet.Mvc.Routing
{
public class AttributeRouteTests
{
[Fact]
public async void AttributeRoute_RouteAsyncHandled_LogsCorrectValues()
{
// Arrange
var sink = new TestSink();
var loggerFactory = new TestLoggerFactory(sink);
var entry = CreateMatchingEntry("api/Store");
var route = CreateRoutingAttributeRoute(loggerFactory, entry);
var context = CreateRouteContext("/api/Store");
// Act
await route.RouteAsync(context);
// Assert
Assert.Equal(1, sink.Scopes.Count);
var scope = sink.Scopes[0];
Assert.Equal(typeof(AttributeRoute).FullName, scope.LoggerName);
Assert.Equal("AttributeRoute.RouteAsync", scope.Scope);
// There is a record for IsEnabled and one for WriteCore.
Assert.Equal(2, sink.Writes.Count);
var enabled = sink.Writes[0];
Assert.Equal(typeof(AttributeRoute).FullName, enabled.LoggerName);
Assert.Equal("AttributeRoute.RouteAsync", enabled.Scope);
Assert.Null(enabled.State);
var write = sink.Writes[1];
Assert.Equal(typeof(AttributeRoute).FullName, write.LoggerName);
Assert.Equal("AttributeRoute.RouteAsync", write.Scope);
var values = Assert.IsType<AttributeRouteRouteAsyncValues>(write.State);
Assert.Equal("AttributeRoute.RouteAsync", values.Name);
Assert.Equal(true, values.Handled);
}
[Fact]
public async void AttributeRoute_RouteAsyncNotHandled_LogsCorrectValues()
{
// Arrange
var sink = new TestSink();
var loggerFactory = new TestLoggerFactory(sink);
var entry = CreateMatchingEntry("api/Store");
var route = CreateRoutingAttributeRoute(loggerFactory, entry);
var context = CreateRouteContext("/");
// Act
await route.RouteAsync(context);
// Assert
Assert.Equal(1, sink.Scopes.Count);
var scope = sink.Scopes[0];
Assert.Equal(typeof(AttributeRoute).FullName, scope.LoggerName);
Assert.Equal("AttributeRoute.RouteAsync", scope.Scope);
// There is a record for IsEnabled and one for WriteCore.
Assert.Equal(2, sink.Writes.Count);
var enabled = sink.Writes[0];
Assert.Equal(typeof(AttributeRoute).FullName, enabled.LoggerName);
Assert.Equal("AttributeRoute.RouteAsync", enabled.Scope);
Assert.Null(enabled.State);
var write = sink.Writes[1];
Assert.Equal(typeof(AttributeRoute).FullName, write.LoggerName);
Assert.Equal("AttributeRoute.RouteAsync", write.Scope);
var values = Assert.IsType<AttributeRouteRouteAsyncValues>(write.State);
Assert.Equal("AttributeRoute.RouteAsync", values.Name);
Assert.Equal(false, values.Handled);
}
[Fact]
public void AttributeRoute_GenerateLink_NoRequiredValues()
{
@ -392,12 +468,28 @@ namespace Microsoft.AspNet.Mvc.Routing
Assert.Equal("Store", path);
}
private static RouteContext CreateRouteContext(string requestPath)
{
var request = new Mock<HttpRequest>(MockBehavior.Strict);
request.SetupGet(r => r.Path).Returns(new PathString(requestPath));
var context = new Mock<HttpContext>(MockBehavior.Strict);
context.Setup(m => m.RequestServices.GetService(typeof(ILoggerFactory)))
.Returns(NullLoggerFactory.Instance);
context.SetupGet(c => c.Request).Returns(request.Object);
return new RouteContext(context.Object);
}
private static VirtualPathContext CreateVirtualPathContext(object values, object ambientValues = null)
{
var httpContext = Mock.Of<HttpContext>();
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(h => h.RequestServices.GetService(typeof(ILoggerFactory)))
.Returns(NullLoggerFactory.Instance);
return new VirtualPathContext(
httpContext,
mockHttpContext.Object,
new RouteValueDictionary(ambientValues),
new RouteValueDictionary(values));
}
@ -427,6 +519,30 @@ namespace Microsoft.AspNet.Mvc.Routing
return entry;
}
private AttributeRouteMatchingEntry CreateMatchingEntry(string template)
{
var mockConstraint = new Mock<IRouteConstraint>();
mockConstraint.Setup(c => c.Match(
It.IsAny<HttpContext>(),
It.IsAny<IRouter>(),
It.IsAny<string>(),
It.IsAny<IDictionary<string, object>>(),
It.IsAny<RouteDirection>()))
.Returns(true);
var mockConstraintResolver = new Mock<IInlineConstraintResolver>();
mockConstraintResolver.Setup(r => r.ResolveConstraint(
It.IsAny<string>()))
.Returns(mockConstraint.Object);
var entry = new AttributeRouteMatchingEntry()
{
Route = new TemplateRoute(new StubRouter(), template, mockConstraintResolver.Object)
};
return entry;
}
private static DefaultInlineConstraintResolver CreateConstraintResolver()
{
var services = Mock.Of<IServiceProvider>();
@ -458,7 +574,19 @@ namespace Microsoft.AspNet.Mvc.Routing
return new AttributeRoute(
next,
Enumerable.Empty<AttributeRouteMatchingEntry>(),
entries);
entries,
NullLoggerFactory.Instance);
}
private static AttributeRoute CreateRoutingAttributeRoute(ILoggerFactory loggerFactory = null, params AttributeRouteMatchingEntry[] entries)
{
loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
return new AttributeRoute(
new StubRouter(),
entries,
Enumerable.Empty<AttributeRouteLinkGenerationEntry>(),
loggerFactory);
}
private class StubRouter : IRouter

View File

@ -5,7 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Microsoft.AspNet.Mvc.Test
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// An implementation of DefaultActionDiscoveryConventions that only allows controllers

View File

@ -4,7 +4,7 @@
using System.Collections.Generic;
using System.Reflection;
namespace Microsoft.AspNet.Mvc.Test
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// An implementation of IControllerAssemblyProvider that provides just this assembly.

View File

@ -9,6 +9,7 @@ using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel;
using Moq;
using Xunit;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Mvc.Core.Test
{
@ -445,8 +446,13 @@ namespace Microsoft.AspNet.Mvc.Core.Test
Assert.Equal("/app/named/home2/newaction/someid", url);
}
private static HttpContext CreateHttpContext(string appRoot)
private static HttpContext CreateHttpContext(string appRoot, ILoggerFactory factory = null)
{
if(factory == null)
{
factory = NullLoggerFactory.Instance;
}
var appRootPath = new PathString(appRoot);
var request = new Mock<HttpRequest>();
request.SetupGet(r => r.PathBase)
@ -454,6 +460,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test
request.SetupGet(r => r.Host)
.Returns(new HostString("localhost"));
var context = new Mock<HttpContext>();
context.Setup(m => m.RequestServices.GetService(typeof(ILoggerFactory)))
.Returns(factory);
context.SetupGet(c => c.Request)
.Returns(request.Object);

View File

@ -12,6 +12,7 @@
"Microsoft.AspNet.Routing": "1.0.0-*",
"Microsoft.AspNet.Testing": "1.0.0-*",
"Microsoft.Framework.DependencyInjection": "1.0.0-*",
"Microsoft.Framework.Logging": "1.0.0-*",
"Moq": "4.2.1312.1622",
"Xunit.KRunner": "1.0.0-*"
},

View File

@ -30,21 +30,22 @@
<Content Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="BasicTests.cs" />
<Compile Include="ViewEngineTests.cs" />
<Compile Include="ActivatorTests.cs" />
<Compile Include="ValueProviderTests.cs" />
<Compile Include="CompositeViewEngineTests.cs" />
<Compile Include="DependencyResolverTests.cs" />
<Compile Include="HttpResponseHelpers.cs" />
<Compile Include="InlineConstraintTests.cs" />
<Compile Include="InputFormatterTests.cs" />
<Compile Include="NullLoggerFactory.cs" />
<Compile Include="ResourceHelpers.cs" />
<Compile Include="RoutingTests.cs" />
<Compile Include="TestApplicationEnvironment.cs" />
<Compile Include="TestAssemblyProvider.cs" />
<Compile Include="TestConfigurationProvider.cs" />
<Compile Include="TestHelper.cs" />
<Compile Include="BasicTests.cs" />
<Compile Include="HttpResponseHelpers.cs" />
<Compile Include="ResourceHelpers.cs" />
<Compile Include="TestApplicationEnvironment.cs" />
</ItemGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -0,0 +1,40 @@
using Microsoft.Framework.Logging;
using System;
namespace Microsoft.AspNet.Mvc
{
public class NullLoggerFactory : ILoggerFactory
{
public static NullLoggerFactory Instance = new NullLoggerFactory();
public ILogger Create(string name)
{
return NullLogger.Instance;
}
}
public class NullLogger : ILogger
{
public static NullLogger Instance = new NullLogger();
public IDisposable BeginScope(object state)
{
return NullDisposable.Instance;
}
public bool WriteCore(TraceType eventType, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
return false;
}
}
public class NullDisposable : IDisposable
{
public static NullDisposable Instance = new NullDisposable();
public void Dispose()
{
// intentionally does nothing
}
}
}

View File

@ -15,6 +15,7 @@ using Microsoft.Framework.Runtime;
using Microsoft.Framework.Runtime.Infrastructure;
using Xunit;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.Logging;
namespace Microsoft.AspNet.Mvc.FunctionalTests
{
@ -51,6 +52,10 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
typeof(ITestConfigurationProvider),
configuration);
services.AddInstance(
typeof(ILoggerFactory),
NullLoggerFactory.Instance);
return services.BuildServiceProvider(originalProvider);
}

View File

@ -14,6 +14,7 @@
"Microsoft.Framework.ConfigurationModel": "1.0.0-*",
"Microsoft.Framework.ConfigurationModel.Json": "1.0.0-*",
"Microsoft.Framework.DependencyInjection": "1.0.0-*",
"Microsoft.Framework.Logging": "1.0.0-*",
"Microsoft.Framework.Runtime.Interfaces": "1.0.0-*",
"Microsoft.AspNet.PipelineCore": "1.0.0-*",
"RoutingWebSite": "",

View File

@ -29,9 +29,9 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="ActionDescriptorCreationCounter.cs" />
<Compile Include="Controllers\UsersController.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\MonitorController.cs" />
<Compile Include="Controllers\UsersController.cs" />
<Compile Include="Startup.cs" />
</ItemGroup>
<ItemGroup>