diff --git a/Mvc.sln b/Mvc.sln index 7478c7b22e..2bcf1d1580 100644 --- a/Mvc.sln +++ b/Mvc.sln @@ -178,7 +178,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BasicViews", "benchmarkapps EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mvc.Api.Analyzers.Test", "test\Mvc.Api.Analyzers.Test\Mvc.Api.Analyzers.Test.csproj", "{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Mvc.Api.Analyzers", "src\Microsoft.AspNetCore.Mvc.Api.Analyzers\Microsoft.AspNetCore.Mvc.Api.Analyzers.csproj", "{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Api.Analyzers", "src\Microsoft.AspNetCore.Mvc.Api.Analyzers\Microsoft.AspNetCore.Mvc.Api.Analyzers.csproj", "{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorRendering", "benchmarkapps\RazorRendering\RazorRendering.csproj", "{D7C6A696-F232-4288-BCCD-367407E4A934}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -952,6 +954,18 @@ Global {3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Release|Mixed Platforms.Build.0 = Release|Any CPU {3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Release|x86.ActiveCfg = Release|Any CPU {3B550487-10E4-4E6D-9CEF-B1B4CA1253DA}.Release|x86.Build.0 = Release|Any CPU + {D7C6A696-F232-4288-BCCD-367407E4A934}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D7C6A696-F232-4288-BCCD-367407E4A934}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D7C6A696-F232-4288-BCCD-367407E4A934}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D7C6A696-F232-4288-BCCD-367407E4A934}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D7C6A696-F232-4288-BCCD-367407E4A934}.Debug|x86.ActiveCfg = Debug|Any CPU + {D7C6A696-F232-4288-BCCD-367407E4A934}.Debug|x86.Build.0 = Debug|Any CPU + {D7C6A696-F232-4288-BCCD-367407E4A934}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D7C6A696-F232-4288-BCCD-367407E4A934}.Release|Any CPU.Build.0 = Release|Any CPU + {D7C6A696-F232-4288-BCCD-367407E4A934}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D7C6A696-F232-4288-BCCD-367407E4A934}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D7C6A696-F232-4288-BCCD-367407E4A934}.Release|x86.ActiveCfg = Release|Any CPU + {D7C6A696-F232-4288-BCCD-367407E4A934}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1025,6 +1039,7 @@ Global {E89EB74D-C1CE-456F-B42D-CCF1575E0CFB} = {2859F266-673A-45A2-9E3C-7B39C6DDD38E} {DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} {3B550487-10E4-4E6D-9CEF-B1B4CA1253DA} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} + {D7C6A696-F232-4288-BCCD-367407E4A934} = {2859F266-673A-45A2-9E3C-7B39C6DDD38E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {63D344F6-F86D-40E6-85B9-0AABBE338C4A} diff --git a/benchmarkapps/RazorRendering/Data/DataA.cs b/benchmarkapps/RazorRendering/Data/DataA.cs new file mode 100644 index 0000000000..42cbf300ee --- /dev/null +++ b/benchmarkapps/RazorRendering/Data/DataA.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Html; + +namespace Data +{ + public class DataA + { + public DataA(int id, HtmlString icon, HtmlString html, string name, int seconds, int max, float perHour) + { + Id = id; + Icon = icon; + Html = html; + Name = name; + Seconds = seconds; + Max = max; + PerHour = perHour; + } + + public int Id { get; } + public HtmlString Icon { get; } + public HtmlString Html { get; } + public string Name { get; } + public int Seconds { get; } + public int Max { get; } + public float PerHour { get; } + } +} diff --git a/benchmarkapps/RazorRendering/Data/DataB.cs b/benchmarkapps/RazorRendering/Data/DataB.cs new file mode 100644 index 0000000000..be2830e67f --- /dev/null +++ b/benchmarkapps/RazorRendering/Data/DataB.cs @@ -0,0 +1,25 @@ +using System; +using Microsoft.AspNetCore.Html; + +namespace Data +{ + public class DataB + { + public DataB(int id, HtmlString icon, string name, int value, DateTimeOffset startDate, DateTimeOffset completeDate) + { + Id = id; + Icon = icon; + Name = name; + Value = value; + StartDate = startDate; + CompleteDate = completeDate; + } + + public int Id { get; } + public HtmlString Icon { get; } + public string Name { get; } + public int Value { get; } + public DateTimeOffset StartDate { get; } + public DateTimeOffset CompleteDate { get; } + } +} diff --git a/benchmarkapps/RazorRendering/Pages/Category/PageA.cshtml b/benchmarkapps/RazorRendering/Pages/Category/PageA.cshtml new file mode 100644 index 0000000000..036af8cb1f --- /dev/null +++ b/benchmarkapps/RazorRendering/Pages/Category/PageA.cshtml @@ -0,0 +1,138 @@ +@page +@model Pages.PageA +@using static System.Convert + +@section Subcategories { + +} + +@section Tabs { + Sub cat A + Sub cat B + Sub cat C + Sub cat D +} + +@switch (Model.Value) +{ + case 0: +

@Model.Name Type A

+ break; + case 1: +

@Model.Name Type B

+ break; + case 2: +

@Model.Name Type C

+ break; +} + + +

Something Something

+
+ + + + + + @if (Model.Value3 != 0) + { + + } + + + @{ + foreach (var data in Model.Data1) + { + + + + + @if (Model.Value3 != 0) + { + + } + + + } + } +
SomethingSomething SomethingSomething
@data.Icon@data.Name@data.Html + @(new TimeSpan(0, 0, (int)data.Seconds))
+ (@data.PerHour.ToString("N2") p/h) +
+
+ + + + max + +
+
+
+ +

Something something something

+
+@{ + if (Model.Data2.Count > 0) + { + + + + + + + + + + + + + @foreach (var data in Model.Data2) + { + var StartDate = data.StartDate; + var CompleteDate = data.CompleteDate; + + + + + + + @{ + float percentage = 100f; + + var totalTime = CompleteDate.Subtract(StartDate).TotalMilliseconds; + if (totalTime > 1000) + { + percentage = 100f * (float)DateTimeOffset.UtcNow.Subtract(StartDate).TotalMilliseconds / (float)totalTime; + } + + percentage = MathF.Min(100f, MathF.Max(0f, percentage)); + + var startDate = ToInt64(StartDate.Subtract(DateTime.UnixEpoch).Ticks / (double)10000); + var endDate = ToInt64(CompleteDate.Subtract(DateTime.UnixEpoch).Ticks / (double)10000); + } + + + + + + } +
SomethingASomethingBSomethingCSomethingDSomethingESomethingF
@data.Icon@data.Name@data.Value@StartDate.ToString("dd MMM HH:mm:ss") +
+
+
+
@CompleteDate.ToString("dd MMM HH:mm:ss") + @(CompleteDate.Subtract(DateTime.UtcNow).ToString()) + +
+ + +
+
+ } + else + { + Something @Model.Name something something something something. + } + +} +
\ No newline at end of file diff --git a/benchmarkapps/RazorRendering/Pages/Category/PageA.cshtml.cs b/benchmarkapps/RazorRendering/Pages/Category/PageA.cshtml.cs new file mode 100644 index 0000000000..8f2d98dc78 --- /dev/null +++ b/benchmarkapps/RazorRendering/Pages/Category/PageA.cshtml.cs @@ -0,0 +1,35 @@ +using Data; +using Microsoft.Extensions.Logging; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Pages +{ + public class PageA : Page + { + public int Value { get; } = 0; + public int Value1 { get; } = 0; + public int Value2 { get; } = 0; + public int Value3 { get; } = 1; + public bool Condition { get; } = true; + + public string Name { get; } = "A Name"; + + public List Data1 { get; } + public List Data2 { get; } + + public PageA(List dataA, List dataB, ILogger logger) : base(logger) + { + Data1 = dataA; + Data2 = dataB; + } + + public async Task OnGetAsync() + { + PageTitle = "PageA Title"; + PageIcon = "sicon dialogue_pagea"; + await Task.Delay(0); + } + } + +} \ No newline at end of file diff --git a/benchmarkapps/RazorRendering/Pages/Category/_Subcategories.cshtml b/benchmarkapps/RazorRendering/Pages/Category/_Subcategories.cshtml new file mode 100644 index 0000000000..3681e4e9cd --- /dev/null +++ b/benchmarkapps/RazorRendering/Pages/Category/_Subcategories.cshtml @@ -0,0 +1,12 @@ +@model Pages.Page + +
+
+
+
+
+
+
+
+
+
diff --git a/benchmarkapps/RazorRendering/Pages/Page.cs b/benchmarkapps/RazorRendering/Pages/Page.cs new file mode 100644 index 0000000000..e02d03b5de --- /dev/null +++ b/benchmarkapps/RazorRendering/Pages/Page.cs @@ -0,0 +1,26 @@ +using System.Text.Encodings.Web; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace Pages +{ + public class Page : PageModel + { + public ILogger Logger { get; } + + public string PageIcon { get; protected set; } + public string PageTitle { get; protected set; } + public string PageUrl { get; protected set; } + + public Page(ILogger logger) + { + Logger = logger; + } + + + public void AddErrorMessage(string message) + { + Response.Headers.Add("X-Error-Message", UrlEncoder.Default.Encode(message)); + } + } +} \ No newline at end of file diff --git a/benchmarkapps/RazorRendering/Pages/Shared/_Layout.cshtml b/benchmarkapps/RazorRendering/Pages/Shared/_Layout.cshtml new file mode 100644 index 0000000000..6e3fbe8720 --- /dev/null +++ b/benchmarkapps/RazorRendering/Pages/Shared/_Layout.cshtml @@ -0,0 +1,31 @@ +@model Pages.Page + +@RenderSection("Subcategories") +
+
@Model.PageTitle
+@{ + var hasTabs = IsSectionDefined("Tabs"); +} +
+ @if (hasTabs) + { +
+ @RenderSection("Tabs", required: false) +
+ } +
+
+
+
+
+ @RenderBody() +
+
+
+
+
+
+
+
+
+
diff --git a/benchmarkapps/RazorRendering/Pages/_ViewImports.cshtml b/benchmarkapps/RazorRendering/Pages/_ViewImports.cshtml new file mode 100644 index 0000000000..b0ad3a90b5 --- /dev/null +++ b/benchmarkapps/RazorRendering/Pages/_ViewImports.cshtml @@ -0,0 +1,2 @@ + +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers \ No newline at end of file diff --git a/benchmarkapps/RazorRendering/Pages/_ViewStart.cshtml b/benchmarkapps/RazorRendering/Pages/_ViewStart.cshtml new file mode 100644 index 0000000000..d641c67f33 --- /dev/null +++ b/benchmarkapps/RazorRendering/Pages/_ViewStart.cshtml @@ -0,0 +1,3 @@ +@{ + Layout = "_Layout"; +} \ No newline at end of file diff --git a/benchmarkapps/RazorRendering/RazorRendering.csproj b/benchmarkapps/RazorRendering/RazorRendering.csproj new file mode 100644 index 0000000000..dbbbfc0027 --- /dev/null +++ b/benchmarkapps/RazorRendering/RazorRendering.csproj @@ -0,0 +1,23 @@ + + + netcoreapp2.2 + + + + + + + + + + + + + + + + + + diff --git a/benchmarkapps/RazorRendering/Readme.md b/benchmarkapps/RazorRendering/Readme.md new file mode 100644 index 0000000000..15640cadc8 --- /dev/null +++ b/benchmarkapps/RazorRendering/Readme.md @@ -0,0 +1 @@ +Url: /Category/PageA \ No newline at end of file diff --git a/benchmarkapps/RazorRendering/Startup.cs b/benchmarkapps/RazorRendering/Startup.cs new file mode 100644 index 0000000000..3092f1639c --- /dev/null +++ b/benchmarkapps/RazorRendering/Startup.cs @@ -0,0 +1,78 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using Data; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Html; +using Microsoft.Extensions.Configuration; +using System.IO; + +public class Startup +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddScoped>(_ => DataA); + services.AddScoped>(_ => DataB); + services.AddMvc() + .SetCompatibilityVersion(CompatibilityVersion.Latest); + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + app.UseMvc(); + } + + private static List DataA = GenerateDataA(); + + private static List GenerateDataA() + { + var dataA = new List(); + + foreach (var i in Enumerable.Range(0, 100)) + { + dataA.Add(new DataA(i, new HtmlString(i.ToString()), new HtmlString(i.ToString()), i.ToString(), i, i, 60f / i)); + } + + return dataA; + } + + private static List DataB = GenerateDataB(); + + private static List GenerateDataB() + { + var utc = DateTimeOffset.UtcNow; + var dataB = new List(); + foreach (var i in Enumerable.Range(0, 100)) + { + dataB.Add(new DataB(i, new HtmlString(i.ToString()), i.ToString(), i, utc, utc)); + } + + return dataB; + } + + public static void Main(string[] args) + { + var host = CreateWebHostBuilder(args) + .Build(); + + host.Run(); + } + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) + { + var configuration = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddCommandLine(args) + .Build(); + + return new WebHostBuilder() + .UseKestrel() + .UseUrls("http://+:5000") + .UseConfiguration(configuration) + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup(); + } +} \ No newline at end of file diff --git a/benchmarks/Microsoft.AspNetCore.Mvc.Performance/ActionSelectorBenchmark.cs b/benchmarks/Microsoft.AspNetCore.Mvc.Performance/ActionSelectorBenchmark.cs index ec9c2c5a4b..5b4cebad21 100644 --- a/benchmarks/Microsoft.AspNetCore.Mvc.Performance/ActionSelectorBenchmark.cs +++ b/benchmarks/Microsoft.AspNetCore.Mvc.Performance/ActionSelectorBenchmark.cs @@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Mvc.Performance var state = routeContext.RouteData.PushState(MockRouter.Instance, routeValues, null); - var actual = NaiveSelectCandiates(_actions, routeContext.RouteData.Values); + var actual = NaiveSelectCandidates(_actions, routeContext.RouteData.Values); Verify(expected, actual); state.Restore(); @@ -113,7 +113,7 @@ namespace Microsoft.AspNetCore.Mvc.Performance } // A naive implementation we can use to generate match data for inputs, and for a baseline. - private static IReadOnlyList NaiveSelectCandiates(ActionDescriptor[] actions, RouteValueDictionary routeValues) + private static IReadOnlyList NaiveSelectCandidates(ActionDescriptor[] actions, RouteValueDictionary routeValues) { var results = new List(); for (var i = 0; i < actions.Length; i++) @@ -175,7 +175,7 @@ namespace Microsoft.AspNetCore.Mvc.Performance { var action = actions[i]; var routeValues = new RouteValueDictionary(action.RouteValues); - var matches = NaiveSelectCandiates(actions, routeValues); + var matches = NaiveSelectCandidates(actions, routeValues); if (matches.Count == 0) { throw new InvalidOperationException("This should have at least one match."); @@ -193,7 +193,7 @@ namespace Microsoft.AspNetCore.Mvc.Performance // Make one of the route values not match. routeValues[routeValues.First().Key] = ((string)routeValues.First().Value) + "fkdkfdkkf"; - var matches = NaiveSelectCandiates(actions, routeValues); + var matches = NaiveSelectCandidates(actions, routeValues); if (matches.Count != 0) { throw new InvalidOperationException("This should have 0 matches."); diff --git a/build/dependencies.props b/build/dependencies.props index 67761a1add..ea25042d20 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -48,8 +48,8 @@ 3.0.0-alpha1-10400 3.0.0-alpha1-10400 3.0.0-alpha1-10400 - 3.0.0-alpha1-10400 - 3.0.0-alpha1-10400 + 3.0.0-a-alpha1-link-generator-master-16955 + 3.0.0-a-alpha1-link-generator-master-16955 3.0.0-alpha1-10400 3.0.0-alpha1-10400 3.0.0-alpha1-10400 diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/Abstractions/ActionDescriptor.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/Abstractions/ActionDescriptor.cs index 20ab53e773..276f3179f3 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/Abstractions/ActionDescriptor.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/Abstractions/ActionDescriptor.cs @@ -36,6 +36,9 @@ namespace Microsoft.AspNetCore.Mvc.Abstractions /// public IList ActionConstraints { get; set; } + /// + /// Gets or sets the endpoint metadata for this action. + /// public IList EndpointMetadata { get; set; } /// diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ActionContext.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ActionContext.cs index f7735c1637..744a439dc7 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ActionContext.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ActionContext.cs @@ -31,15 +31,11 @@ namespace Microsoft.AspNetCore.Mvc /// The to copy. public ActionContext(ActionContext actionContext) : this( - actionContext.HttpContext, - actionContext.RouteData, - actionContext.ActionDescriptor, - actionContext.ModelState) + actionContext?.HttpContext, + actionContext?.RouteData, + actionContext?.ActionDescriptor, + actionContext?.ModelState) { - if (actionContext == null) - { - throw new ArgumentNullException(nameof(actionContext)); - } } /// @@ -136,4 +132,4 @@ namespace Microsoft.AspNetCore.Mvc get; set; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ActionResultOfT.cs b/src/Microsoft.AspNetCore.Mvc.Core/ActionResultOfT.cs index 048c80ff52..048f1be54a 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ActionResultOfT.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ActionResultOfT.cs @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Mvc } /// - /// Intializes a new instance of using the specified . + /// Initializes a new instance of using the specified . /// /// The . public ActionResult(ActionResult result) diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ApiConventionMethodAttribute.cs b/src/Microsoft.AspNetCore.Mvc.Core/ApiConventionMethodAttribute.cs index a54f9a0c07..8efb21d871 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ApiConventionMethodAttribute.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ApiConventionMethodAttribute.cs @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Mvc } else if (methods.Length > 1) { - throw new ArgumentException(Resources.FormatApiConventionMethod_AmbigiousMethodName(methodName, conventionType), nameof(methodName)); + throw new ArgumentException(Resources.FormatApiConventionMethod_AmbiguousMethodName(methodName, conventionType), nameof(methodName)); } return methods[0]; diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/ApplicationPartManager.cs b/src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/ApplicationPartManager.cs index 1636c61df7..99e1c608e1 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/ApplicationPartManager.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ApplicationParts/ApplicationPartManager.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts /// Gets the list of instances. /// /// Instances in this collection are stored in precedence order. An that appears - /// earlier in the list has a higher precendence. + /// earlier in the list has a higher precedence. /// An may choose to use this an interface as a way to resolve conflicts when /// multiple instances resolve equivalent feature values. /// diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ClientErrorData.cs b/src/Microsoft.AspNetCore.Mvc.Core/ClientErrorData.cs index 38b3448ece..9b292ad53d 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ClientErrorData.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ClientErrorData.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Mvc /// /// /// By default, this maps to and should not change - /// between multiple occurences of the same error. + /// between multiple occurrences of the same error. /// public string Title { get; set; } } diff --git a/src/Microsoft.AspNetCore.Mvc.Core/CompatibilityVersion.cs b/src/Microsoft.AspNetCore.Mvc.Core/CompatibilityVersion.cs index 0260f464a7..ad18d058a6 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/CompatibilityVersion.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/CompatibilityVersion.cs @@ -6,11 +6,11 @@ using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Mvc { /// - /// Specifies the version compatibility of runtime behaviors configured by . + /// Specifies the version compatibility of runtime behaviors configured by . /// /// /// - /// The best way to set a compatibility version is by using + /// The best way to set a compatibility version is by using /// or /// in your application's /// ConfigureServices method. @@ -20,32 +20,32 @@ namespace Microsoft.AspNetCore.Mvc /// public class Startup /// { /// ... - /// + /// /// public void ConfigureServices(IServiceCollection services) /// { /// services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); /// } - /// + /// /// ... /// } /// /// /// /// - /// Setting compatiblity version to a specific version will change the default values of various - /// settings to match a particular minor release of ASP.NET Core MVC. + /// Setting compatibility version to a specific version will change the default values of various + /// settings to match a particular minor release of ASP.NET Core MVC. /// /// public enum CompatibilityVersion { /// - /// Sets the default value of settings on to match the behavior of + /// Sets the default value of settings on to match the behavior of /// ASP.NET Core MVC 2.0. /// Version_2_0, /// - /// Sets the default value of settings on to match the behavior of + /// Sets the default value of settings on to match the behavior of /// ASP.NET Core MVC 2.1. /// /// diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ConsumesAttribute.cs b/src/Microsoft.AspNetCore.Mvc.Core/ConsumesAttribute.cs index 7af167dc51..30a103a531 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ConsumesAttribute.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ConsumesAttribute.cs @@ -189,7 +189,7 @@ namespace Microsoft.AspNetCore.Mvc // If there are multiple IConsumeActionConstraints which are defined at the class and // at the action level, the one closest to the action overrides the others. To ensure this // we take advantage of the fact that ConsumesAttribute is both an IActionFilter and an - // IConsumeActionConstraint. Since filterdescriptor collection is ordered (the last filter is the one + // IConsumeActionConstraint. Since FilterDescriptor collection is ordered (the last filter is the one // closest to the action), we apply this constraint only if there is no IConsumeActionConstraint after this. return actionDescriptor.FilterDescriptors.Last( filter => filter.Filter is IConsumesActionConstraint).Filter == this; diff --git a/src/Microsoft.AspNetCore.Mvc.Core/FromServicesAttribute.cs b/src/Microsoft.AspNetCore.Mvc.Core/FromServicesAttribute.cs index 271ae181f2..31e299de73 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/FromServicesAttribute.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/FromServicesAttribute.cs @@ -16,9 +16,9 @@ namespace Microsoft.AspNetCore.Mvc /// /// /// [HttpGet] - /// public ProductModel GetProduct([FromServices] IProductModelRequestService productModelReqest) + /// public ProductModel GetProduct([FromServices] IProductModelRequestService productModelRequest) /// { - /// return productModelReqest.Value; + /// return productModelRequest.Value; /// } /// /// diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/ConfigureCompatibilityOptions.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/ConfigureCompatibilityOptions.cs index c46a3529d0..33009c95de 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/ConfigureCompatibilityOptions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/ConfigureCompatibilityOptions.cs @@ -9,7 +9,7 @@ using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Mvc.Infrastructure { /// - /// A base class for infrastructure that implements ASP.NET Core MVC's support for + /// A base class for infrastructure that implements ASP.NET Core MVC's support for /// . This is framework infrastructure and should not be used /// by application code. /// @@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure throw new ArgumentNullException(nameof(options)); } - // Evaluate DefaultValues onces so subclasses don't have to cache. + // Evaluate DefaultValues once so subclasses don't have to cache. var defaultValues = DefaultValues; foreach (var @switch in options) diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/DefaultActionDescriptorCollectionProvider.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/DefaultActionDescriptorCollectionProvider.cs index 6204ce3945..aef4292b6c 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/DefaultActionDescriptorCollectionProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/DefaultActionDescriptorCollectionProvider.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. 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.Collections.ObjectModel; using System.Diagnostics; @@ -85,7 +84,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure return new CompositeChangeToken(changeTokens); } - + private void Initialize() { // Using double-checked locking on initialization because we fire change token callbacks @@ -134,7 +133,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure // Consumers who poll will observe a new action descriptor collection at step 2 - they will see // the new collection and ignore the change token. // - // Consumers who listen to the change token will requery at step 4 - they will see the new collection + // Consumers who listen to the change token will re-query at step 4 - they will see the new collection // and new change token. // // Anyone who acquires the collection and change token between steps 2 and 3 will be notified of diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/IActionDescriptorCollectionProvider.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/IActionDescriptorCollectionProvider.cs index ee1648e170..c109d78846 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/IActionDescriptorCollectionProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/IActionDescriptorCollectionProvider.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure /// /// /// To be reactively notified of changes, downcast to and - /// subcribe to the change token returned from + /// subscribe to the change token returned from /// using . /// /// diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/IActionResultExecutor.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/IActionResultExecutor.cs index 3a4e398c5e..99d01f81d2 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/IActionResultExecutor.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/IActionResultExecutor.cs @@ -12,14 +12,14 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure /// /// The type of . /// - /// Implementions of are typically called by the + /// Implementations of are typically called by the /// method of the corresponding action result type. /// Implementations should be registered as singleton services. /// public interface IActionResultExecutor where TResult : IActionResult { /// - /// Asynchronously excecutes the action result, by modifying the . + /// Asynchronously executes the action result, by modifying the . /// /// The associated with the current request."/> /// The action result to execute. diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ActionMethodExecutor.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ActionMethodExecutor.cs index 28541b3e55..806b97d1e5 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ActionMethodExecutor.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ActionMethodExecutor.cs @@ -165,7 +165,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal => typeof(Task).IsAssignableFrom(executor.MethodReturnType); } - // Task DownloadFile(..) + // Task DownloadFile(..) // ValueTask GetViewsAsync(..) private class TaskOfActionResultExecutor : ActionMethodExecutor { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ActionSelector.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ActionSelector.cs index 0f9a1cb6e4..210250ff69 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ActionSelector.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ActionSelector.cs @@ -365,7 +365,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal // We also want to add the same (as in reference equality) list of actions to the ordinal entries. // We'll keep updating `entries` to include all of the actions in the same equivalence class - - // meaning, all conventionally routed actions for which the route values are equalignoring case. + // meaning, all conventionally routed actions for which the route values are equal ignoring case. // // `entries` will appear in `OrdinalIgnoreCaseEntries` exactly once and in `OrdinalEntries` once // for each variation of casing that we've seen. diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ControllerActionDescriptorBuilder.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ControllerActionDescriptorBuilder.cs index 27a548c37a..4c7e4aa8f2 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ControllerActionDescriptorBuilder.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ControllerActionDescriptorBuilder.cs @@ -138,10 +138,12 @@ namespace Microsoft.AspNetCore.Mvc.Internal ActionModel action) { var defaultControllerConstraints = Enumerable.Empty(); + var defaultControllerEndpointMetadata = Enumerable.Empty(); if (controller.Selectors.Count > 0) { defaultControllerConstraints = controller.Selectors[0].ActionConstraints .Where(constraint => !(constraint is IRouteTemplateProvider)); + defaultControllerEndpointMetadata = controller.Selectors[0].EndpointMetadata; } var actionDescriptors = new List(); @@ -164,8 +166,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal AddActionConstraints(actionDescriptor, actionSelector, controllerConstraints); - // REVIEW: Need to get metadata from controller - actionDescriptor.EndpointMetadata = actionSelector.EndpointMetadata.ToList(); + // Metadata for the action is more significant so order it before the controller metadata + var actionDescriptorMetadata = actionSelector.EndpointMetadata.ToList(); + actionDescriptorMetadata.AddRange(defaultControllerEndpointMetadata); + + actionDescriptor.EndpointMetadata = actionDescriptorMetadata; } return actionDescriptors; diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MiddlewareFilterBuilder.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MiddlewareFilterBuilder.cs index cbceab72b0..6257968f90 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MiddlewareFilterBuilder.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MiddlewareFilterBuilder.cs @@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal public RequestDelegate GetPipeline(Type configurationType) { - // Build the pipeline only once. This is similar to how middlewares registered in Startup are constructed. + // Build the pipeline only once. This is similar to how middleware registered in Startup are constructed. var requestDelegate = _pipelinesCache.GetOrAdd( configurationType, @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal } // Ideally we want the experience of a middleware pipeline to behave the same as if it was registered - // in Startup. In this scenario, an Exception thrown in a middelware later in the pipeline gets + // in Startup. In this scenario, an Exception thrown in a middleware later in the pipeline gets // propagated back to earlier middleware. So, check if a later resource filter threw an Exception and // propagate that back to the middleware pipeline. resourceExecutedContext.ExceptionDispatchInfo?.Throw(); diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcEndpointDataSource.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcEndpointDataSource.cs index c99e3a216d..4c0304e380 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcEndpointDataSource.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcEndpointDataSource.cs @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal private readonly DefaultHttpContext _httpContextInstance; // The following are protected by this lock for WRITES only. This pattern is similar - // to DefaultActionDescriptorChangeProvider - see comments there for details on + // to DefaultActionDescriptorChangeProvider - see comments there for details on // all of the threading behaviors. private readonly object _lock = new object(); private List _endpoints; @@ -162,7 +162,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal // - /Home/Index/{id?} // - /Home // - / - if (UseDefaultValuePlusRemainingSegementsOptional(i, action, endpointInfo, newPathSegments)) + if (UseDefaultValuePlusRemainingSegmentsOptional(i, action, endpointInfo, newPathSegments)) { var subPathSegments = newPathSegments.Take(i); @@ -270,7 +270,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal } } - private bool UseDefaultValuePlusRemainingSegementsOptional( + private bool UseDefaultValuePlusRemainingSegmentsOptional( int segmentIndex, ActionDescriptor action, MvcEndpointInfo endpointInfo, diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/CollectionModelBinderProvider.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/CollectionModelBinderProvider.cs index 0617122b5f..bacc1f371f 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/CollectionModelBinderProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/CollectionModelBinderProvider.cs @@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders } // If the model type is IEnumerable<> then we need to know if we can assign a List<> to it, since - // that's what we would create. (The cases handled here are IEnumerable<>, IReadOnlyColection<> and + // that's what we would create. (The cases handled here are IEnumerable<>, IReadOnlyCollection<> and // IReadOnlyList<>). var enumerableType = ClosedGenericMatcher.ExtractGenericInterface(modelType, typeof(IEnumerable<>)); if (enumerableType != null) diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ComplexTypeModelBinder.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ComplexTypeModelBinder.cs index dd02365c96..3f15ffdf20 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ComplexTypeModelBinder.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ComplexTypeModelBinder.cs @@ -256,7 +256,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders // // If a property does not have a binding source, then it's fair game for any value provider. // - // If any property meets the above conditions and has a value from valueproviders, then we'll + // If any property meets the above conditions and has a value from ValueProviders, then we'll // create the model and try to bind it. OR if ALL properties of the model have a greedy source, // then we go ahead and create it. // diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/EnumTypeModelBinder.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/EnumTypeModelBinder.cs index 601d02ba44..f6c99138fd 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/EnumTypeModelBinder.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/EnumTypeModelBinder.cs @@ -82,11 +82,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders // enum FlagsEnum { Value1 = 1, Value2 = 2, Value4 = 4 } // // Valid Scenarios: - // 1. valueproviderresult="Value2,Value4", model=Value2 | Value4, underlying=6, converted=Value2, Value4 - // 2. valueproviderresult="2,4", model=Value2 | Value4, underlying=6, converted=Value2, Value4 + // 1. valueProviderResult="Value2,Value4", model=Value2 | Value4, underlying=6, converted=Value2, Value4 + // 2. valueProviderResult="2,4", model=Value2 | Value4, underlying=6, converted=Value2, Value4 // // Invalid Scenarios: - // 1. valueproviderresult="2,10", model=12, underlying=12, converted=12 + // 1. valueProviderResult="2,10", model=12, underlying=12, converted=12 // var underlying = Convert.ChangeType( model, diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/HeaderModelBinder.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/HeaderModelBinder.cs index 48c3ae2304..e9de376246 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/HeaderModelBinder.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/HeaderModelBinder.cs @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders var headerName = bindingContext.FieldName; // Do not set ModelBindingResult to Failed on not finding the value in the header as we want the inner - // modelbinder to do that. This would give a chance to the inner binder to add more useful information. + // ModelBinder to do that. This would give a chance to the inner binder to add more useful information. // For example, SimpleTypeModelBinder adds a model error when binding to let's say an integer and the // model is null. var request = bindingContext.HttpContext.Request; diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/JQueryKeyValuePairNormalizer.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/JQueryKeyValuePairNormalizer.cs index b0c1c28c0f..0fdd6c2634 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/JQueryKeyValuePairNormalizer.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/JQueryKeyValuePairNormalizer.cs @@ -9,7 +9,7 @@ using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Mvc.ModelBinding { - // Normalizes keys, in a keyvaluepair collection, from jQuery format to a format that MVC understands. + // Normalizes keys, in a KeyValuePair collection, from jQuery format to a format that MVC understands. internal static class JQueryKeyValuePairNormalizer { public static IDictionary GetValues( diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadataProvider.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadataProvider.cs index 75bd188997..e7a2d454d8 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadataProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadataProvider.cs @@ -79,7 +79,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata var cacheEntry = GetCacheEntry(modelType); // We're relying on a safe race-condition for Properties - take care only - // to set the value onces the properties are fully-initialized. + // to set the value once the properties are fully-initialized. if (cacheEntry.Details.Properties == null) { var key = ModelMetadataIdentity.ForType(modelType); diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs index d70a92f526..70d895c8af 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs @@ -1509,18 +1509,18 @@ namespace Microsoft.AspNetCore.Mvc.Core => string.Format(CultureInfo.CurrentCulture, GetString("ApiConvention_UnsupportedAttributesOnConvention"), p0, p1, p2); /// - /// Method name '{0}' is ambigous for convention type '{1}'. More than one method found with the name '{0}'. + /// Method name '{0}' is ambiguous for convention type '{1}'. More than one method found with the name '{0}'. /// - internal static string ApiConventionMethod_AmbigiousMethodName + internal static string ApiConventionMethod_AmbiguousMethodName { - get => GetString("ApiConventionMethod_AmbigiousMethodName"); + get => GetString("ApiConventionMethod_AmbiguousMethodName"); } /// - /// Method name '{0}' is ambigous for convention type '{1}'. More than one method found with the name '{0}'. + /// Method name '{0}' is ambiguous for convention type '{1}'. More than one method found with the name '{0}'. /// - internal static string FormatApiConventionMethod_AmbigiousMethodName(object p0, object p1) - => string.Format(CultureInfo.CurrentCulture, GetString("ApiConventionMethod_AmbigiousMethodName"), p0, p1); + internal static string FormatApiConventionMethod_AmbiguousMethodName(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("ApiConventionMethod_AmbiguousMethodName"), p0, p1); /// /// A method named '{0}' was not found on convention type '{1}'. diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx index cc88759296..5ec7fea828 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx +++ b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx @@ -1,17 +1,17 @@  - @@ -451,8 +451,8 @@ Method {0} is decorated with the following attributes that are not allowed on an API convention method:{1}The following attributes are allowed on API convention methods: {2}. - - Method name '{0}' is ambigous for convention type '{1}'. More than one method found with the name '{0}'. + + Method name '{0}' is ambiguous for convention type '{1}'. More than one method found with the name '{0}'. A method named '{0}' was not found on convention type '{1}'. diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Routing/EndpointRoutingUrlHelper.cs b/src/Microsoft.AspNetCore.Mvc.Core/Routing/EndpointRoutingUrlHelper.cs index 8ddd49c2f1..adc94a7d8e 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Routing/EndpointRoutingUrlHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Routing/EndpointRoutingUrlHelper.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Logging; @@ -51,46 +52,41 @@ namespace Microsoft.AspNetCore.Mvc.Routing throw new ArgumentNullException(nameof(urlActionContext)); } - var valuesDictionary = GetValuesDictionary(urlActionContext.Values); + var values = GetValuesDictionary(urlActionContext.Values); if (urlActionContext.Action == null) { - if (!valuesDictionary.ContainsKey("action") && + if (!values.ContainsKey("action") && AmbientValues.TryGetValue("action", out var action)) { - valuesDictionary["action"] = action; + values["action"] = action; } } else { - valuesDictionary["action"] = urlActionContext.Action; + values["action"] = urlActionContext.Action; } if (urlActionContext.Controller == null) { - if (!valuesDictionary.ContainsKey("controller") && + if (!values.ContainsKey("controller") && AmbientValues.TryGetValue("controller", out var controller)) { - valuesDictionary["controller"] = controller; + values["controller"] = controller; } } else { - valuesDictionary["controller"] = urlActionContext.Controller; + values["controller"] = urlActionContext.Controller; } - var successfullyGeneratedLink = _linkGenerator.TryGetLink( + + var path = _linkGenerator.GetPathByRouteValues( ActionContext.HttpContext, - valuesDictionary, - out var link); - if (!successfullyGeneratedLink) - { - //TODO: log here - - return null; - } - - return GenerateUrl(urlActionContext.Protocol, urlActionContext.Host, link, urlActionContext.Fragment); + routeName: null, + values, + new FragmentString(urlActionContext.Fragment == null ? null : "#" + urlActionContext.Fragment)); + return GenerateUrl(urlActionContext.Protocol, urlActionContext.Host, path); } /// @@ -101,20 +97,12 @@ namespace Microsoft.AspNetCore.Mvc.Routing throw new ArgumentNullException(nameof(routeContext)); } - var valuesDictionary = routeContext.Values as RouteValueDictionary ?? GetValuesDictionary(routeContext.Values); - - var successfullyGeneratedLink = _linkGenerator.TryGetLink( + var path = _linkGenerator.GetPathByRouteValues( ActionContext.HttpContext, routeContext.RouteName, - valuesDictionary, - out var link); - - if (!successfullyGeneratedLink) - { - return null; - } - - return GenerateUrl(routeContext.Protocol, routeContext.Host, link, routeContext.Fragment); + routeContext.Values, + new FragmentString(routeContext.Fragment == null ? null : "#" + routeContext.Fragment)); + return GenerateUrl(routeContext.Protocol, routeContext.Host, path); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Routing/UrlHelperBase.cs b/src/Microsoft.AspNetCore.Mvc.Core/Routing/UrlHelperBase.cs index 730323f33b..a68c9c988b 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Routing/UrlHelperBase.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Routing/UrlHelperBase.cs @@ -201,6 +201,68 @@ namespace Microsoft.AspNetCore.Mvc.Routing } } + /// + /// Generates a URI from the provided components. + /// + /// The URI scheme/protocol. + /// The URI host. + /// The URI path and remaining portions (path, query, and fragment). + /// + /// An absolute URI if the or is specified, otherwise generates a + /// URI with an absolute path. + /// + protected string GenerateUrl(string protocol, string host, string path) + { + // This method is similar to GenerateUrl, but it's used for EndpointRouting. It ignores pathbase and fragment + // because those have already been incorporated. + if (path == null) + { + return null; + } + + // Perf: In most of the common cases, GenerateUrl is called with a null protocol, host and fragment. + // In such cases, we might not need to build any URL as the url generated is mostly same as the virtual path available in pathData. + // For such common cases, this FastGenerateUrl method saves a string allocation per GenerateUrl call. + string url; + if (TryFastGenerateUrl(protocol, host, path, fragment: null, out url)) + { + return url; + } + + var builder = GetStringBuilder(); + try + { + if (string.IsNullOrEmpty(protocol) && string.IsNullOrEmpty(host)) + { + AppendPathAndFragment(builder, pathBase: null, path, fragment: null); + + // We're returning a partial URL (just path + query + fragment), but we still want it to be rooted. + if (builder.Length == 0 || builder[0] != '/') + { + builder.Insert(0, '/'); + } + } + else + { + protocol = string.IsNullOrEmpty(protocol) ? "http" : protocol; + builder.Append(protocol); + + builder.Append("://"); + + host = string.IsNullOrEmpty(host) ? ActionContext.HttpContext.Request.Host.Value : host; + builder.Append(host); + AppendPathAndFragment(builder, pathBase: null, path, fragment: null); + } + + return builder.ToString(); + } + finally + { + // Clear the StringBuilder so that it can reused for the next call. + builder.Clear(); + } + } + // for unit testing internal static void AppendPathAndFragment(StringBuilder builder, PathString pathBase, string virtualPath, string fragment) { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/UrlHelperExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Core/UrlHelperExtensions.cs index af43e847bb..42da1bc1ac 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/UrlHelperExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/UrlHelperExtensions.cs @@ -462,7 +462,7 @@ namespace Microsoft.AspNetCore.Mvc if (!routeValues.ContainsKey("handler") && ambientValues.TryGetValue("handler", out var handler)) { - // Clear out formaction unless it's explicitly specified in the routeValues. + // Clear out form action unless it's explicitly specified in the routeValues. routeValues["handler"] = null; } } diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ValidationProblemDetails.cs b/src/Microsoft.AspNetCore.Mvc.Core/ValidationProblemDetails.cs index b27e790a90..2332367b95 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ValidationProblemDetails.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ValidationProblemDetails.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc public class ValidationProblemDetails : ProblemDetails { /// - /// Intializes a new instance of . + /// Initializes a new instance of . /// public ValidationProblemDetails() { diff --git a/src/Microsoft.AspNetCore.Mvc.Formatters.Json/MvcJsonOptions.cs b/src/Microsoft.AspNetCore.Mvc.Formatters.Json/MvcJsonOptions.cs index f27cf0b00c..28df9825b5 100644 --- a/src/Microsoft.AspNetCore.Mvc.Formatters.Json/MvcJsonOptions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Formatters.Json/MvcJsonOptions.cs @@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Mvc } /// - /// Gets or sets a flag to determine whether error messsages from JSON deserialization by the + /// Gets or sets a flag to determine whether error messages from JSON deserialization by the /// will be added to the . The default /// value is false, meaning that a generic error message will be used instead. /// diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/ApplicationParts/RazorCompiledItemFeatureProvider.cs b/src/Microsoft.AspNetCore.Mvc.Razor/ApplicationParts/RazorCompiledItemFeatureProvider.cs index d59c4e9ffb..ccfc49127d 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/ApplicationParts/RazorCompiledItemFeatureProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/ApplicationParts/RazorCompiledItemFeatureProvider.cs @@ -25,12 +25,12 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts if (duplicates != null) { - var viewsDiffereningInCase = string.Join(Environment.NewLine, duplicates.Select(d => d.Identifier)); + var viewsDifferingInCase = string.Join(Environment.NewLine, duplicates.Select(d => d.Identifier)); var message = string.Join( Environment.NewLine, Resources.RazorViewCompiler_ViewPathsDifferOnlyInCase, - viewsDiffereningInCase); + viewsDifferingInCase); throw new InvalidOperationException(message); } diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewsFeatureProvider.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewsFeatureProvider.cs index deb57205de..e7e7143fbb 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewsFeatureProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Compilation/ViewsFeatureProvider.cs @@ -35,12 +35,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation { // Ensure parts do not specify views with differing cases. This is not supported // at runtime and we should flag at as such for precompiled views. - var viewsDiffereningInCase = string.Join(Environment.NewLine, duplicates.Select(d => d.RelativePath)); + var viewsDifferingInCase = string.Join(Environment.NewLine, duplicates.Select(d => d.RelativePath)); var message = string.Join( Environment.NewLine, Resources.RazorViewCompiler_ViewPathsDifferOnlyInCase, - viewsDiffereningInCase); + viewsDifferingInCase); throw new InvalidOperationException(message); } diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs index fa30c8eddd..7ede8232f4 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs @@ -81,7 +81,7 @@ namespace Microsoft.Extensions.DependencyInjection // ViewFeature items have precedence semantics - when two views have the same path \ identifier, // the one that appears earlier in the list wins. Therefore the ordering of // RazorCompiledItemFeatureProvider and ViewsFeatureProvider is pertinent - any view compiled - // using the Sdk will be prefered to views compiled using MvcPrecompilation. + // using the Sdk will be preferred to views compiled using MvcPrecompilation. if (!builder.PartManager.FeatureProviders.OfType().Any()) { builder.PartManager.FeatureProviders.Add(new RazorCompiledItemFeatureProvider()); @@ -159,6 +159,9 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddEnumerable( ServiceDescriptor.Transient, RazorViewEngineOptionsSetup>()); + services.TryAddEnumerable( + ServiceDescriptor.Transient, RazorViewEngineOptionsSetup>()); + services.TryAddSingleton< IRazorViewEngineFileProviderAccessor, DefaultRazorViewEngineFileProviderAccessor>(); diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewCompiler.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewCompiler.cs index 1f4d30b159..9bbce19d88 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewCompiler.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewCompiler.cs @@ -90,7 +90,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal // from either the set of known precompiled views, or by being compiled. _cache = cache; - // We need to validate that the all of the precompiled views are unique by path (case-insenstive). + // We need to validate that the all of the precompiled views are unique by path (case-insensitive). // We do this because there's no good way to canonicalize paths on windows, and it will create // problems when deploying to linux. Rather than deal with these issues, we just don't support // views that differ only by case. @@ -116,6 +116,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal } } + public bool AllowRecompilingViewsOnFileChange { get; set; } + /// public Task CompileAsync(string relativePath) { @@ -254,16 +256,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal // Used to validate and recompile NormalizedPath = normalizedPath, - ExpirationTokens = new List(), - }; - var checksums = precompiledView.Item.GetChecksumMetadata(); - for (var i = 0; i < checksums.Count; i++) - { - // We rely on Razor to provide the right set of checksums. Trust the compiler, it has to do a good job, - // so it probably will. - item.ExpirationTokens.Add(_fileProvider.Watch(checksums[i].Identifier)); - } + ExpirationTokens = GetExpirationTokens(precompiledView), + }; // We also need to create a new descriptor, because the original one doesn't have expiration tokens on // it. These will be used by the view location cache, which is like an L1 cache for views (this class is @@ -282,10 +277,13 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal private ViewCompilerWorkItem CreateRuntimeCompilationWorkItem(string normalizedPath) { - var expirationTokens = new List() + IList expirationTokens = Array.Empty(); + + if (AllowRecompilingViewsOnFileChange) { - _fileProvider.Watch(normalizedPath), - }; + var changeToken = _fileProvider.Watch(normalizedPath); + expirationTokens = new List { changeToken }; + } var projectItem = _projectEngine.FileSystem.GetItem(normalizedPath); if (!projectItem.Exists) @@ -293,7 +291,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal _logger.ViewCompilerCouldNotFindFileAtPath(normalizedPath); // If the file doesn't exist, we can't do compilation right now - we still want to cache - // the fact that we tried. This will allow us to retrigger compilation if the view file + // the fact that we tried. This will allow us to re-trigger compilation if the view file // is added. return new ViewCompilerWorkItem() { @@ -313,9 +311,46 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal _logger.ViewCompilerFoundFileToCompile(normalizedPath); + GetChangeTokensFromImports(expirationTokens, projectItem); + + return new ViewCompilerWorkItem() + { + SupportsCompilation = true, + + NormalizedPath = normalizedPath, + ExpirationTokens = expirationTokens, + }; + } + + private IList GetExpirationTokens(CompiledViewDescriptor precompiledView) + { + if (!AllowRecompilingViewsOnFileChange) + { + return Array.Empty(); + } + + var checksums = precompiledView.Item.GetChecksumMetadata(); + var expirationTokens = new List(checksums.Count); + + for (var i = 0; i < checksums.Count; i++) + { + // We rely on Razor to provide the right set of checksums. Trust the compiler, it has to do a good job, + // so it probably will. + expirationTokens.Add(_fileProvider.Watch(checksums[i].Identifier)); + } + + return expirationTokens; + } + + private void GetChangeTokensFromImports(IList expirationTokens, RazorProjectItem projectItem) + { + if (!AllowRecompilingViewsOnFileChange) + { + return; + } + // OK this means we can do compilation. For now let's just identify the other files we need to watch // so we can create the cache entry. Compilation will happen after we release the lock. - var importFeature = _projectEngine.ProjectFeatures.OfType().FirstOrDefault(); // There should always be an import feature unless someone has misconfigured their RazorProjectEngine. @@ -330,14 +365,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal { expirationTokens.Add(_fileProvider.Watch(physicalImport.FilePath)); } - - return new ViewCompilerWorkItem() - { - SupportsCompilation = true, - - NormalizedPath = normalizedPath, - ExpirationTokens = expirationTokens, - }; } protected virtual CompiledViewDescriptor CompileAndEmit(string relativePath) diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewCompilerProvider.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewCompilerProvider.cs index 560b1493d6..3776bc845f 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewCompilerProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewCompilerProvider.cs @@ -80,7 +80,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal #pragma warning restore CS0618 // Type or member is obsolete feature.ViewDescriptors, _compilationMemoryCacheProvider.CompilationMemoryCache, - _logger); + _logger) + { + AllowRecompilingViewsOnFileChange = _viewEngineOptions.AllowRecompilingViewsOnFileChange, + }; } } } diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Properties/AssemblyInfo.cs index 5bd324d5d6..73c4c5a356 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Properties/AssemblyInfo.cs @@ -7,3 +7,4 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.RazorPages.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/RazorViewEngineOptions.cs b/src/Microsoft.AspNetCore.Mvc.Razor/RazorViewEngineOptions.cs index 8ae0120211..6c6148cb24 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/RazorViewEngineOptions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/RazorViewEngineOptions.cs @@ -2,8 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections; using System.Collections.Generic; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Razor.Compilation; using Microsoft.CodeAnalysis; using Microsoft.Extensions.FileProviders; @@ -13,10 +15,21 @@ namespace Microsoft.AspNetCore.Mvc.Razor /// /// Provides programmatic configuration for the . /// - public class RazorViewEngineOptions + public class RazorViewEngineOptions : IEnumerable { + private readonly ICompatibilitySwitch[] _switches; + private readonly CompatibilitySwitch _allowRecompilingViewsOnFileChange; private Action _compilationCallback = c => { }; + public RazorViewEngineOptions() + { + _allowRecompilingViewsOnFileChange = new CompatibilitySwitch(nameof(AllowRecompilingViewsOnFileChange)); + _switches = new[] + { + _allowRecompilingViewsOnFileChange, + }; + } + /// /// Gets a used by the . /// @@ -181,5 +194,52 @@ namespace Microsoft.AspNetCore.Mvc.Razor _compilationCallback = value; } } + + /// + /// Gets or sets a value that determines if Razor files (Razor Views and Razor Pages) are recompiled and updated + /// if files change on disk. + /// + /// When , MVC will use to watch for changes to + /// Razor files in configured instances. + /// + /// + /// + /// The default value is if the version is + /// or earlier. If the version is later and is Development, + /// the default value is . Otherwise, the default value is . + /// + /// + /// + /// This property is associated with a compatibility switch and can provide a different behavior depending on + /// the configured compatibility version for the application. See for + /// guidance and examples of setting the application's compatibility version. + /// + /// + /// Configuring the desired value of the compatibility switch by calling this property's setter will take + /// precedence over the value implied by the application's . + /// + /// + /// If the application's compatibility version is set to or + /// lower then this setting will have the value unless explicitly configured. + /// + /// + /// If the application's compatibility version is set to or + /// higher then this setting will have the value unless + /// is Development or the value is explicitly configured. + /// + /// + public bool AllowRecompilingViewsOnFileChange + { + // Note: When compatibility switches are removed in 3.0, this property should be retained as a regular boolean property. + get => _allowRecompilingViewsOnFileChange.Value; + set => _allowRecompilingViewsOnFileChange.Value = value; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)_switches).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator(); } } diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewEngineOptionsSetup.cs b/src/Microsoft.AspNetCore.Mvc.Razor/RazorViewEngineOptionsSetup.cs similarity index 50% rename from src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewEngineOptionsSetup.cs rename to src/Microsoft.AspNetCore.Mvc.Razor/RazorViewEngineOptionsSetup.cs index e8c49113ba..6747d87726 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewEngineOptionsSetup.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/RazorViewEngineOptionsSetup.cs @@ -2,27 +2,45 @@ // 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 Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -namespace Microsoft.AspNetCore.Mvc.Razor.Internal +namespace Microsoft.AspNetCore.Mvc.Razor { - /// - /// Sets up default options for . - /// - public class RazorViewEngineOptionsSetup : IConfigureOptions + internal class RazorViewEngineOptionsSetup : + ConfigureCompatibilityOptions, + IConfigureOptions { private readonly IHostingEnvironment _hostingEnvironment; - /// - /// Initializes a new instance of . - /// - /// for the application. - public RazorViewEngineOptionsSetup(IHostingEnvironment hostingEnvironment) + public RazorViewEngineOptionsSetup( + IHostingEnvironment hostingEnvironment, + ILoggerFactory loggerFactory, + IOptions compatibilityOptions) + : base(loggerFactory, compatibilityOptions) { _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); } + protected override IReadOnlyDictionary DefaultValues + { + get + { + var values = new Dictionary(); + if (Version < CompatibilityVersion.Version_2_2) + { + // Default to true in 2.1 or earlier. In 2.2, we have to conditionally enable this + // and consequently this switch has no default value. + values[nameof(RazorViewEngineOptions.AllowRecompilingViewsOnFileChange)] = true; + } + + return values; + } + } + public void Configure(RazorViewEngineOptions options) { if (options == null) @@ -41,6 +59,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal options.AreaViewLocationFormats.Add("/Areas/{2}/Views/{1}/{0}" + RazorViewEngine.ViewExtension); options.AreaViewLocationFormats.Add("/Areas/{2}/Views/Shared/{0}" + RazorViewEngine.ViewExtension); options.AreaViewLocationFormats.Add("/Views/Shared/{0}" + RazorViewEngine.ViewExtension); + + if (_hostingEnvironment.IsDevelopment()) + { + options.AllowRecompilingViewsOnFileChange = true; + } } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionDescriptorChangeProvider.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionDescriptorChangeProvider.cs index c68ee3ed65..fadb391b90 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionDescriptorChangeProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/PageActionDescriptorChangeProvider.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Linq; using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.Mvc.Razor.Internal; using Microsoft.AspNetCore.Razor.Language; using Microsoft.Extensions.FileProviders; @@ -18,11 +19,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal private readonly IFileProvider _fileProvider; private readonly string[] _searchPatterns; private readonly string[] _additionalFilesToTrack; + private readonly bool _watchForChanges; public PageActionDescriptorChangeProvider( RazorTemplateEngine templateEngine, IRazorViewEngineFileProviderAccessor fileProviderAccessor, - IOptions razorPagesOptions) + IOptions razorPagesOptions, + IOptions razorViewEngineOptions) { if (templateEngine == null) { @@ -39,6 +42,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal throw new ArgumentNullException(nameof(razorPagesOptions)); } + _watchForChanges = razorViewEngineOptions.Value.AllowRecompilingViewsOnFileChange; + if (!_watchForChanges) + { + // No need to do any additional work if we aren't going to be watching for file changes. + return; + } + _fileProvider = fileProviderAccessor.FileProvider; var rootDirectory = razorPagesOptions.Value.RootDirectory; @@ -84,6 +94,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal public IChangeToken GetChangeToken() { + if (!_watchForChanges) + { + return NullChangeToken.Singleton; + } + var changeTokens = new IChangeToken[_additionalFilesToTrack.Length + _searchPatterns.Length]; for (var i = 0; i < _additionalFilesToTrack.Length; i++) { diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorProjectPageRouteModelProvider.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorProjectPageRouteModelProvider.cs index 81cf7b6a42..ad8187cb78 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorProjectPageRouteModelProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorProjectPageRouteModelProvider.cs @@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal public void OnProvidersExecuting(PageRouteModelProviderContext context) { - // When RootDirectory and AreaRootDirectory overlap, e.g. RootDirectory = /, AreaRootDirectoryy = /Areas; + // When RootDirectory and AreaRootDirectory overlap, e.g. RootDirectory = /, AreaRootDirectory = /Areas; // we need to ensure that the page is only route-able via the area route. By adding area routes first, // we'll ensure non area routes get skipped when it encounters an IsAlreadyRegistered check. @@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal private static bool IsRouteable(RazorProjectItem item) { - // Pages like _ViewImports should not be routable. + // Pages like _ViewImports should not be routeable. return !item.FileName.StartsWith("_", StringComparison.OrdinalIgnoreCase); } } diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Cache/CacheTagKey.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Cache/CacheTagKey.cs index 3d1912cba0..00647c6e2f 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Cache/CacheTagKey.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Cache/CacheTagKey.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache public class CacheTagKey : IEquatable { private static readonly char[] AttributeSeparator = new[] { ',' }; - private static readonly Func CookieAcccessor = (c, key) => c[key]; + private static readonly Func CookieAccessor = (c, key) => c[key]; private static readonly Func HeaderAccessor = (c, key) => c[key]; private static readonly Func QueryAccessor = (c, key) => c[key]; private static readonly Func RouteValueAccessor = (c, key) => c[key]?.ToString(); @@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache _expiresOn = tagHelper.ExpiresOn; _expiresSliding = tagHelper.ExpiresSliding; _varyBy = tagHelper.VaryBy; - _cookies = ExtractCollection(tagHelper.VaryByCookie, request.Cookies, CookieAcccessor); + _cookies = ExtractCollection(tagHelper.VaryByCookie, request.Cookies, CookieAccessor); _headers = ExtractCollection(tagHelper.VaryByHeader, request.Headers, HeaderAccessor); _queries = ExtractCollection(tagHelper.VaryByQuery, request.Query, QueryAccessor); _routeValues = ExtractCollection(tagHelper.VaryByRoute, tagHelper.ViewContext.RouteData.Values, RouteValueAccessor); diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/CacheTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/CacheTagHelper.cs index 09beddee8a..32f0824d04 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/CacheTagHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/CacheTagHelper.cs @@ -141,7 +141,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // can't be put inside a using block. entry.Dispose(); - // Set the result on the TCS once we've commited the entry to the cache since commiting to the cache + // Set the result on the TCS once we've committed the entry to the cache since commiting to the cache // may throw. tcs.SetResult(content); return content; diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/FormActionTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/FormActionTagHelper.cs index 18c89f37e4..66d22ea10c 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/FormActionTagHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/FormActionTagHelper.cs @@ -167,9 +167,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers } /// - /// Does nothing if user provides an formaction attribute. + /// Does nothing if user provides an FormAction attribute. /// - /// Thrown if formaction attribute is provided and , , + /// Thrown if FormAction attribute is provided and , , /// or are non-null or if the user provided asp-route-* attributes. /// Also thrown if and one or both of and /// are non-null @@ -186,7 +186,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers throw new ArgumentNullException(nameof(output)); } - // If "formaction" is already set, it means the user is attempting to use a normal button or input element. + // If "FormAction" is already set, it means the user is attempting to use a normal button or input element. if (output.Attributes.ContainsName(FormAction)) { if (Action != null || @@ -198,7 +198,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers Route != null || (_routeValues != null && _routeValues.Count > 0)) { - // User specified a formaction and one of the bound attributes; can't override that formaction + // User specified a FormAction and one of the bound attributes; can't override that FormAction // attribute. throw new InvalidOperationException( Resources.FormatFormActionTagHelper_CannotOverrideFormAction( diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/RenderAtEndOfFormTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/RenderAtEndOfFormTagHelper.cs index d1e2537044..c819a38c98 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/RenderAtEndOfFormTagHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/RenderAtEndOfFormTagHelper.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers public class RenderAtEndOfFormTagHelper : TagHelper { // This TagHelper's order must be greater than the FormTagHelper's. I.e it must be executed after - // FormTaghelper does. + // FormTagHelper does. /// public override int Order => -900; diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/TagHelperOutputExtensions.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/TagHelperOutputExtensions.cs index 8075b5bf0e..91be1e59de 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/TagHelperOutputExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/TagHelperOutputExtensions.cs @@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var copiedAttribute = false; // We iterate context.AllAttributes backwards since we prioritize TagHelperOutput values occurring - // before the current context.AllAttribtes[i]. + // before the current context.AllAttributes[i]. for (var i = context.AllAttributes.Count - 1; i >= 0; i--) { // We look for the original attribute so we can restore the exact attribute name the user typed in diff --git a/src/Microsoft.AspNetCore.Mvc.Testing/Handlers/RedirectHandler.cs b/src/Microsoft.AspNetCore.Mvc.Testing/Handlers/RedirectHandler.cs index 71198d3d75..8af03645ac 100644 --- a/src/Microsoft.AspNetCore.Mvc.Testing/Handlers/RedirectHandler.cs +++ b/src/Microsoft.AspNetCore.Mvc.Testing/Handlers/RedirectHandler.cs @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Mvc.Testing.Handlers /// /// Creates a new instance of . /// - /// The maximun number of redirect responses to follow. It must be + /// The maximum number of redirect responses to follow. It must be /// equal or greater than 0. public RedirectHandler(int maxRedirects) { diff --git a/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactory.cs b/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactory.cs index c04fe25f45..356bd56d97 100644 --- a/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactory.cs +++ b/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactory.cs @@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Mvc.Testing /// on the assembly containing the functional tests with /// a key equal to the assembly . /// In case an attribute with the right key can't be found, - /// will fall back to searching for a solution file (*.sln) and then appending asembly name + /// will fall back to searching for a solution file (*.sln) and then appending assembly name /// to the solution directory. The application root directory will be used to discover views and content files. /// /// diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Controller.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Controller.cs index 5c680ffaaa..c0aaa0e3b3 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Controller.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Controller.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Mvc /// Gets or sets used by and . /// /// - /// By default, this property is intiailized when activates + /// By default, this property is initialized when activates /// controllers. /// /// This property can be accessed after the controller has been activated, for example, in a controller action diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/PagedBufferedTextWriter.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/PagedBufferedTextWriter.cs index 9148831b6e..3c436b3277 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/PagedBufferedTextWriter.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/PagedBufferedTextWriter.cs @@ -5,6 +5,7 @@ using System; using System.Buffers; using System.Diagnostics; using System.IO; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; @@ -28,14 +29,30 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal // Don't do anything. We'll call FlushAsync. } - public override async Task FlushAsync() + public override Task FlushAsync() => FlushAsyncCore(); + + // private non-virtual for internal calling. + // It first does a fast check to see if async is necessary, we inline this check. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Task FlushAsyncCore() { var length = _charBuffer.Length; if (length == 0) { - return; + + // If nothing sync buffered return CompletedTask, + // so we can fast-path skip async state-machine creation + return Task.CompletedTask; } + return FlushAsyncAwaited(); + } + + private async Task FlushAsyncAwaited() + { + var length = _charBuffer.Length; + Debug.Assert(length > 0); + var pages = _charBuffer.Pages; var count = pages.Count; for (var i = 0; i < count; i++) @@ -89,21 +106,54 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal _charBuffer.Append(value); } - public override async Task WriteAsync(char value) + public override Task WriteAsync(char value) { - await FlushAsync(); + var flushTask = FlushAsyncCore(); + + // FlushAsyncCore will return CompletedTask if nothing sync buffered + // Fast-path and skip async state-machine if only a single async operation + return ReferenceEquals(flushTask, Task.CompletedTask) ? + _inner.WriteAsync(value) : + WriteAsyncAwaited(flushTask, value); + } + + private async Task WriteAsyncAwaited(Task flushTask, char value) + { + await flushTask; await _inner.WriteAsync(value); } - public override async Task WriteAsync(char[] buffer, int index, int count) + public override Task WriteAsync(char[] buffer, int index, int count) { - await FlushAsync(); + var flushTask = FlushAsyncCore(); + + // FlushAsyncCore will return CompletedTask if nothing sync buffered + // Fast-path and skip async state-machine if only a single async operation + return ReferenceEquals(flushTask, Task.CompletedTask) ? + _inner.WriteAsync(buffer, index, count) : + WriteAsyncAwaited(flushTask, buffer, index, count); + } + + private async Task WriteAsyncAwaited(Task flushTask, char[] buffer, int index, int count) + { + await flushTask; await _inner.WriteAsync(buffer, index, count); } - public override async Task WriteAsync(string value) + public override Task WriteAsync(string value) { - await FlushAsync(); + var flushTask = FlushAsyncCore(); + + // FlushAsyncCore will return CompletedTask if nothing sync buffered + // Fast-path and skip async state-machine if only a single async operation + return ReferenceEquals(flushTask, Task.CompletedTask) ? + _inner.WriteAsync(value) : + WriteAsyncAwaited(flushTask, value); + } + + private async Task WriteAsyncAwaited(Task flushTask, string value) + { + await flushTask; await _inner.WriteAsync(value); } diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewBuffer.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewBuffer.cs index 7a39276b7b..dfe23dce7c 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewBuffer.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewBuffer.cs @@ -91,7 +91,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal } /// - // Very common trival method; nudge it to inline https://github.com/aspnet/Mvc/pull/8339 + // Very common trivial method; nudge it to inline https://github.com/aspnet/Mvc/pull/8339 [MethodImpl(MethodImplOptions.AggressiveInlining)] public IHtmlContentBuilder Append(string unencoded) { @@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal } /// - // Very common trival method; nudge it to inline https://github.com/aspnet/Mvc/pull/8339 + // Very common trivial method; nudge it to inline https://github.com/aspnet/Mvc/pull/8339 [MethodImpl(MethodImplOptions.AggressiveInlining)] public IHtmlContentBuilder AppendHtml(IHtmlContent content) { @@ -119,7 +119,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal } /// - // Very common trival method; nudge it to inline https://github.com/aspnet/Mvc/pull/8339 + // Very common trivial method; nudge it to inline https://github.com/aspnet/Mvc/pull/8339 [MethodImpl(MethodImplOptions.AggressiveInlining)] public IHtmlContentBuilder AppendHtml(string encoded) { @@ -131,7 +131,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal return this; } - // Very common trival method; nudge it to inline https://github.com/aspnet/Mvc/pull/8339 + // Very common trivial method; nudge it to inline https://github.com/aspnet/Mvc/pull/8339 [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AppendValue(ViewBufferValue value) { @@ -139,7 +139,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal page.Append(value); } - // Very common trival method; nudge it to inline https://github.com/aspnet/Mvc/pull/8339 + // Very common trivial method; nudge it to inline https://github.com/aspnet/Mvc/pull/8339 [MethodImpl(MethodImplOptions.AggressiveInlining)] private ViewBufferPage GetCurrentPage() { diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewBufferPage.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewBufferPage.cs index 416e329bd7..dfc47673ec 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewBufferPage.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/ViewBufferPage.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal public bool IsFull => Count == Capacity; - // Very common trival method; nudge it to inline https://github.com/aspnet/Mvc/pull/8339 + // Very common trivial method; nudge it to inline https://github.com/aspnet/Mvc/pull/8339 [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Append(ViewBufferValue value) => Buffer[Count++] = value; } diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/SaveTempDataAttribute.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/SaveTempDataAttribute.cs index 908afc2fca..1c9af6ca28 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/SaveTempDataAttribute.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/SaveTempDataAttribute.cs @@ -16,13 +16,13 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures { public SaveTempDataAttribute() { - // Since SaveTempDataFilter registers for a response's OnStarting callback, we want this filter to run - // as early as possible to get the opportunity to register the call back before any other result filter + // Since SaveTempDataFilter registers for a response's OnStarting callback, we want this filter to run + // as early as possible to get the opportunity to register the call back before any other result filter // starts writing to the response stream. Order = int.MinValue + 100; } - // + /// public int Order { get; set; } /// diff --git a/test/Microsoft.AspNetCore.Mvc.ApiExplorer.Test/DefaultApiDescriptionProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.ApiExplorer.Test/DefaultApiDescriptionProviderTest.cs index 224a6b1276..e4a446485d 100644 --- a/test/Microsoft.AspNetCore.Mvc.ApiExplorer.Test/DefaultApiDescriptionProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ApiExplorer.Test/DefaultApiDescriptionProviderTest.cs @@ -1565,10 +1565,10 @@ namespace Microsoft.AspNetCore.Mvc.Description } [Fact] - public void GetApiDescription_ParameterDescription_RedundentMetadata_NotMergedWithParent() + public void GetApiDescription_ParameterDescription_RedundantMetadata_NotMergedWithParent() { // Arrange - var action = CreateActionDescriptor(nameof(AcceptsRedundentMetadata)); + var action = CreateActionDescriptor(nameof(AcceptsRedundantMetadata)); var parameterDescriptor = action.Parameters.Single(); // Act @@ -1590,7 +1590,7 @@ namespace Microsoft.AspNetCore.Mvc.Description } [Fact] - public void GetApiDescription_ParameterDescription_RedundentMetadata_WithParameterMetadata() + public void GetApiDescription_ParameterDescription_RedundantMetadata_WithParameterMetadata() { // Arrange var action = CreateActionDescriptor(nameof(AcceptsPerson)); @@ -2081,7 +2081,7 @@ namespace Microsoft.AspNetCore.Mvc.Description { } - private void AcceptsRedundentMetadata([FromQuery] RedundentMetadata r) + private void AcceptsRedundantMetadata([FromQuery] RedundentMetadata r) { } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/AcceptedAtActionResultTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/AcceptedAtActionResultTests.cs index d6ab7ad228..242405e9ba 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/AcceptedAtActionResultTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/AcceptedAtActionResultTests.cs @@ -219,7 +219,7 @@ namespace Microsoft.AspNetCore.Mvc } [Fact] - public void OnFormatting_NullUrlHelperContextNoRequestServices_ThrowsArgumentNullExeption() + public void OnFormatting_NullUrlHelperContextNoRequestServices_ThrowsArgumentNullException() { // Arrange var context = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ActionResultOfTTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ActionResultOfTTest.cs index 8f5abec7e5..83e1058b0c 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ActionResultOfTTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ActionResultOfTTest.cs @@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Mvc public void Convert_InfersDeclaredTypeFromActionResultTypeParameter() { // Arrange - var value = new DeriviedItem(); + var value = new DerivedItem(); var actionResultOfT = new ActionResult(value); var convertToActionResult = (IConvertToActionResult)actionResultOfT; @@ -85,7 +85,7 @@ namespace Microsoft.AspNetCore.Mvc { } - private class DeriviedItem : BaseItem + private class DerivedItem : BaseItem { } } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ApiConventionMethodAttributeTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ApiConventionMethodAttributeTest.cs index 01fc4f3773..cba34f7b96 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ApiConventionMethodAttributeTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ApiConventionMethodAttributeTest.cs @@ -85,14 +85,14 @@ namespace Microsoft.AspNetCore.Mvc } [Fact] - public void Constructor_ThrowsIfMethodIsAmbigous() + public void Constructor_ThrowsIfMethodIsAmbiguous() { // Arrange var methodName = typeof(ConventionWithProducesAttribute).FullName + '.' + nameof(ConventionWithProducesAttribute.Get); var attribute = typeof(ProducesAttribute); var type = typeof(TestConventions); - var expected = $"Method name 'Method' is ambigous for convention type '{type}'. More than one method found with the name 'Method'."; + var expected = $"Method name 'Method' is ambiguous for convention type '{type}'. More than one method found with the name 'Method'."; // Act & Assert ExceptionAssert.ThrowsArgument( diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ApiExplorer/ApiConventionMatcherTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ApiExplorer/ApiConventionMatcherTest.cs index 72526bbd2b..bbf31785a0 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ApiExplorer/ApiConventionMatcherTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ApiExplorer/ApiConventionMatcherTest.cs @@ -151,7 +151,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer } [Fact] - public void IsNameMatch_WithPrefix_ReturnsFalse_IfNameIsNotProperPrfix() + public void IsNameMatch_WithPrefix_ReturnsFalse_IfNameIsNotProperPrefix() { // Arrange var name = "Postman"; @@ -386,7 +386,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer } [Fact] - public void IsMatch_ReturnsTrue_IfMethodNameAndParametersMatchs() + public void IsMatch_ReturnsTrue_IfMethodNameAndParametersMatches() { // Arrange var method = typeof(TestController).GetMethod(nameof(TestController.Get)); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ConsumesAttributeTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ConsumesAttributeTests.cs index be1999d28d..1ecf35fb8e 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ConsumesAttributeTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ConsumesAttributeTests.cs @@ -80,7 +80,7 @@ namespace Microsoft.AspNetCore.Mvc [InlineData("application/json")] [InlineData("application/json;Parameter1=12")] [InlineData("text/xml")] - public void ActionConstraint_Accept_MatchesForMachingRequestContentType(string contentType) + public void ActionConstraint_Accept_MatchesForMatchingRequestContentType(string contentType) { // Arrange var constraint = new ConsumesAttribute("application/json", "text/xml"); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ControllerBaseTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ControllerBaseTest.cs index d26aa506c7..659260734a 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ControllerBaseTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ControllerBaseTest.cs @@ -1027,10 +1027,10 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test // Arrange var controller = new TestableController(); var pageName = "/Page-Name"; - var routeVaues = new { key = "value" }; + var routeValues = new { key = "value" }; // Act - var result = controller.RedirectToPage(pageName, routeVaues); + var result = controller.RedirectToPage(pageName, routeValues); // Assert Assert.IsType(result); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Filters/MiddlewareFilterAttributeTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Filters/MiddlewareFilterAttributeTest.cs index bedfd14f4a..bcfec63de6 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Filters/MiddlewareFilterAttributeTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Filters/MiddlewareFilterAttributeTest.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal Pipeline1.ConfigurePipeline = (ab) => { configureCallCount++; - ab.Use((httpCtxt, next) => + ab.Use((httpContext, next) => { return next(); }); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatFilterTest.cs index 9610b485b4..84778f73b3 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatFilterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatFilterTest.cs @@ -75,7 +75,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters httpContext.Setup(c => c.Request.Query.ContainsKey("format")).Returns(true); httpContext.Setup(c => c.Request.Query["format"]).Returns("xml"); - // Routedata contains json + // RouteData contains json var data = new RouteData(); data.Values.Add("format", "json"); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/NoContentFormatterTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/NoContentFormatterTests.cs index 408806e727..b8e1d51bc2 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/NoContentFormatterTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/NoContentFormatterTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters { get { - // object value, bool useDeclaredTypeAsString, bool expectedCanwriteResult, bool useNonNullContentType + // object value, bool useDeclaredTypeAsString, bool expectedCanWriteResult, bool useNonNullContentType yield return new object[] { "valid value", true, false, true }; yield return new object[] { "valid value", false, false, true }; yield return new object[] { "", false, false, true }; diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/CompatibilitySwitchTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/CompatibilitySwitchTest.cs index 119113f668..aa91274e77 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/CompatibilitySwitchTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/CompatibilitySwitchTest.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure } [Fact] - public void Constructor_WithNameAndInitalValue_IsValueSetIsFalse() + public void Constructor_WithNameAndInitialValue_IsValueSetIsFalse() { // Arrange & Act var @switch = new CompatibilitySwitch("TestProperty", initialValue: true); @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure var @switch = new CompatibilitySwitch("TestProperty"); // Act - @switch.Value = false; // You don't need to actually change the value, just caling the setting works + @switch.Value = false; // You don't need to actually change the value, just calling the setting works // Assert Assert.False(@switch.Value); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/DefaultActionDescriptorCollectionProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/DefaultActionDescriptorCollectionProviderTest.cs index cac4f58aec..e5eb4b7f94 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/DefaultActionDescriptorCollectionProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/DefaultActionDescriptorCollectionProviderTest.cs @@ -65,7 +65,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure } [Fact] - public void ActionDescriptors_UpdatesAndResubscripes_WhenChangeTokenTriggers() + public void ActionDescriptors_UpdatesAndResubscribes_WhenChangeTokenTriggers() { // Arrange var actionDescriptorProvider = new Mock(); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/ProblemDetalsClientErrorFactoryTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/ProblemDetalsClientErrorFactoryTest.cs index 603b60e381..3a84deabe7 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/ProblemDetalsClientErrorFactoryTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Infrastructure/ProblemDetalsClientErrorFactoryTest.cs @@ -8,7 +8,7 @@ using Xunit; namespace Microsoft.AspNetCore.Mvc.Infrastructure { - public class ProblemDetalsClientErrorFactoryTest + public class ProblemDetailsClientErrorFactoryTest { [Fact] public void GetClientError_ReturnsProblemDetails_IfNoMappingWasFound() diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ApiBehaviorApplicationModelProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ApiBehaviorApplicationModelProviderTest.cs index c4104b9027..23241174ca 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ApiBehaviorApplicationModelProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ApiBehaviorApplicationModelProviderTest.cs @@ -227,7 +227,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal } [Fact] - public void InferBindingSourceForParameter_ReturnsPath_IfParameterAppearsInAnyRoutes_MulitpleRoutes() + public void InferBindingSourceForParameter_ReturnsPath_IfParameterAppearsInAnyRoutes_MultipleRoutes() { // Arrange var actionName = nameof(ParameterBindingController.ParameterInMultipleRoutes); @@ -1112,7 +1112,7 @@ Environment.NewLine + "int b"; } [Fact] - public void DiscoverErrorResponseType_UsesValueFromApiErrorTypeAttribute_SpecifiedOnControllerAsssembly() + public void DiscoverErrorResponseType_UsesValueFromApiErrorTypeAttribute_SpecifiedOnControllerAssembly() { // Arrange var expected = typeof(InvalidEnumArgumentException); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionDescriptorProviderTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionDescriptorProviderTests.cs index 060543dd8b..e35f55a9d9 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionDescriptorProviderTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionDescriptorProviderTests.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ActionConstraints; using Microsoft.AspNetCore.Mvc.ApiExplorer; @@ -252,6 +253,33 @@ namespace Microsoft.AspNetCore.Mvc.Internal Assert.Equal(nameof(ConventionallyRoutedController.ConventionalAction), actionConstraint.Value); } + [Fact] + public void GetDescriptors_EndpointMetadata_ContainsAttributesFromActionAndController() + { + // Arrange & Act + var descriptors = GetDescriptors( + typeof(AuthorizeController).GetTypeInfo()); + + // Assert + Assert.Equal(2, descriptors.Count()); + + var anonymousAction = Assert.Single(descriptors, a => a.RouteValues["action"] == "AllowAnonymousAction"); + + Assert.NotNull(anonymousAction.EndpointMetadata); + + Assert.Collection(anonymousAction.EndpointMetadata, + metadata => Assert.IsType(metadata), + metadata => Assert.IsType(metadata)); + + var authorizeAction = Assert.Single(descriptors, a => a.RouteValues["action"] == "AuthorizeAction"); + + Assert.NotNull(authorizeAction.EndpointMetadata); + + Assert.Collection(authorizeAction.EndpointMetadata, + metadata => Assert.Equal("ActionPolicy", Assert.IsType(metadata).Policy), + metadata => Assert.Equal("ControllerPolicy", Assert.IsType(metadata).Policy)); + } + [Fact] public void GetDescriptors_ActionWithHttpMethods_AddedToEndpointMetadata() { @@ -272,7 +300,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal Assert.False(httpMethodMetadata.AcceptCorsPreflight); Assert.Equal("GET", Assert.Single(httpMethodMetadata.HttpMethods)); - }); + }, + metadata => Assert.IsType(metadata)); } [Fact] @@ -1175,7 +1204,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal [Theory] [InlineData("A", typeof(ApiExplorerEnabledConventionalRoutedController))] [InlineData("A", typeof(ApiExplorerEnabledActionConventionalRoutedController))] - public void ApiExplorer_ThrowsForContentionalRouting(string actionName, Type type) + public void ApiExplorer_ThrowsForConventionalRouting(string actionName, Type type) { // Arrange var assemblyName = type.GetTypeInfo().Assembly.GetName().Name; @@ -1865,6 +1894,16 @@ namespace Microsoft.AspNetCore.Mvc.Internal public void AttributeRoutedAction() { } } + [Authorize("ControllerPolicy")] + private class AuthorizeController + { + [AllowAnonymous] + public void AllowAnonymousAction() { } + + [Authorize("ActionPolicy")] + public void AuthorizeAction() { } + } + private class EmptyController { } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionInvokerTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionInvokerTest.cs index 9d5c551ce1..74090a932c 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionInvokerTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionInvokerTest.cs @@ -1206,7 +1206,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal } [Theory] - [InlineData(nameof(TestController.AsynActionMethodWithTestActionResult))] + [InlineData(nameof(TestController.AsyncActionMethodWithTestActionResult))] [InlineData(nameof(TestController.ActionMethodWithTestActionResult))] public async Task InvokeAction_ReturnTypeAsIActionResult_ReturnsExpected(string methodName) { @@ -1654,7 +1654,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal return new TestActionResult { Value = value }; } - public async Task AsynActionMethodWithTestActionResult(int value) + public async Task AsyncActionMethodWithTestActionResult(int value) { return await Task.FromResult(new TestActionResult { Value = value }); } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/DefaultCollectionValidationStrategyTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/DefaultCollectionValidationStrategyTest.cs index 70a6fb110d..30f964b93d 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/DefaultCollectionValidationStrategyTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/DefaultCollectionValidationStrategyTest.cs @@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal } [Fact] - public void EnumerateElements_TwoEnumerableImplemenations() + public void EnumerateElements_TwoEnumerableImplementations() { // Arrange var model = new TwiceEnumerable(new int[] { 2, 3, 5 }); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/DefaultObjectValidatorTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/DefaultObjectValidatorTests.cs index fad6540560..5450c507c1 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/DefaultObjectValidatorTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/DefaultObjectValidatorTests.cs @@ -1316,7 +1316,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal { { model, new ValidationStateEntry() } }; - var method = GetType().GetMethod(nameof(Validate_Throws_ForTopLeveleMetadataData), BindingFlags.NonPublic | BindingFlags.Instance); + var method = GetType().GetMethod(nameof(Validate_Throws_ForTopLevelMetadataData), BindingFlags.NonPublic | BindingFlags.Instance); var metadata = MetadataProvider.GetMetadataForParameter(method.GetParameters()[0]); // Act & Assert @@ -1465,7 +1465,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal void DoSomething(); } - private void Validate_Throws_ForTopLeveleMetadataData(DepthObject depthObject) { } + private void Validate_Throws_ForTopLevelMetadataData(DepthObject depthObject) { } // Custom validation attribute that returns multiple entries in ValidationResult.MemberNames and those member // names are indexers. An example scenario is an attribute that confirms all entries in a list are unique. diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/DisableRequestSizeLimitFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/DisableRequestSizeLimitFilterTest.cs index 4340460963..6e8907f1a5 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/DisableRequestSizeLimitFilterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/DisableRequestSizeLimitFilterTest.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal { // Arrange var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitFilter(NullLoggerFactory.Instance); - var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter }); + var authorizationFilterContext = CreateAuthorizationFilterContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter }); var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature(); authorizationFilterContext.HttpContext.Features.Set(httpMaxRequestBodySize); @@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal // Arrange var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitFilter(NullLoggerFactory.Instance); var disableRequestSizeLimitResourceFilterFinal = new DisableRequestSizeLimitFilter(NullLoggerFactory.Instance); - var authorizationFilterContext = CreateauthorizationFilterContext( + var authorizationFilterContext = CreateAuthorizationFilterContext( new IFilterMetadata[] { disableRequestSizeLimitResourceFilter, disableRequestSizeLimitResourceFilterFinal }); var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature(); @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal var loggerFactory = new TestLoggerFactory(sink, enabled: true); var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitFilter(loggerFactory); - var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter }); + var authorizationFilterContext = CreateAuthorizationFilterContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter }); // Act disableRequestSizeLimitResourceFilter.OnAuthorization(authorizationFilterContext); @@ -79,7 +79,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal var loggerFactory = new TestLoggerFactory(sink, enabled: true); var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitFilter(loggerFactory); - var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter }); + var authorizationFilterContext = CreateAuthorizationFilterContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter }); var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature(); httpMaxRequestBodySize.IsReadOnly = true; @@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal var loggerFactory = new TestLoggerFactory(sink, enabled: true); var disableRequestSizeLimitResourceFilter = new DisableRequestSizeLimitFilter(loggerFactory); - var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter }); + var authorizationFilterContext = CreateAuthorizationFilterContext(new IFilterMetadata[] { disableRequestSizeLimitResourceFilter }); var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature(); authorizationFilterContext.HttpContext.Features.Set(httpMaxRequestBodySize); @@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal Assert.Equal($"The request body size limit has been disabled.", write.State.ToString()); } - private static AuthorizationFilterContext CreateauthorizationFilterContext(IFilterMetadata[] filters) + private static AuthorizationFilterContext CreateAuthorizationFilterContext(IFilterMetadata[] filters) { return new AuthorizationFilterContext(CreateActionContext(), filters); } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ExplicitIndexCollectionValidationStrategyTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ExplicitIndexCollectionValidationStrategyTest.cs index deeb9f74ae..cf1fecf8f3 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ExplicitIndexCollectionValidationStrategyTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ExplicitIndexCollectionValidationStrategyTest.cs @@ -90,7 +90,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal } [Fact] - public void EnumerateElements_TwoEnumerableImplemenations() + public void EnumerateElements_TwoEnumerableImplementations() { // Arrange var model = new TwiceEnumerable(new int[] { 2, 3, 5 }); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/MiddlewareFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/MiddlewareFilterTest.cs index e6c748784e..5edff31ab3 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/MiddlewareFilterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/MiddlewareFilterTest.cs @@ -36,13 +36,13 @@ namespace Microsoft.AspNetCore.Mvc.Internal { // Arrange Task requestDelegate(HttpContext context) => Task.FromResult(true); - var middlwareFilter = new MiddlewareFilter(requestDelegate); + var middlewareFilter = new MiddlewareFilter(requestDelegate); var httpContext = new DefaultHttpContext(); var resourceExecutingContext = GetResourceExecutingContext(httpContext); var resourceExecutionDelegate = GetResourceExecutionDelegate(httpContext); // Act - await middlwareFilter.OnResourceExecutionAsync(resourceExecutingContext, resourceExecutionDelegate); + await middlewareFilter.OnResourceExecutionAsync(resourceExecutingContext, resourceExecutionDelegate); // Assert var feature = resourceExecutingContext.HttpContext.Features.Get(); @@ -398,7 +398,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal logger, diagnosticSource, mapper, - CreatControllerContext(actionContext, valueProviderFactories, maxAllowedErrorsInModelState), + CreateControllerContext(actionContext, valueProviderFactories, maxAllowedErrorsInModelState), CreateCacheEntry((ControllerActionDescriptor)actionContext.ActionDescriptor, controllerFactory), filters) { @@ -420,7 +420,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal return ObjectMethodExecutor.Create(actionDescriptor.MethodInfo, actionDescriptor.ControllerTypeInfo); } - private static ControllerContext CreatControllerContext( + private static ControllerContext CreateControllerContext( ActionContext actionContext, IReadOnlyList valueProviderFactories, int maxAllowedErrorsInModelState) diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/MvcCoreLoggerExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/MvcCoreLoggerExtensionsTest.cs index 8835d2da8e..2b56c00572 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/MvcCoreLoggerExtensionsTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/MvcCoreLoggerExtensionsTest.cs @@ -112,9 +112,9 @@ namespace Microsoft.AspNetCore.Mvc.Internal var asyncResultFilter = Mock.Of(); var resourceFilter = Mock.Of(); var asyncResourceFilter = Mock.Of(); - var orderedresourceFilterMock = new Mock(); - orderedresourceFilterMock.SetupGet(f => f.Order).Returns(-100); - var orderedResourceFilter = orderedresourceFilterMock.Object; + var orderedResourceFilterMock = new Mock(); + orderedResourceFilterMock.SetupGet(f => f.Order).Returns(-100); + var orderedResourceFilter = orderedResourceFilterMock.Object; var filters = new IFilterMetadata[] { actionFilter, diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/MvcEndpointDataSourceTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/MvcEndpointDataSourceTests.cs index a6f92ddc2c..e15b8225e0 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/MvcEndpointDataSourceTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/MvcEndpointDataSourceTests.cs @@ -377,7 +377,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal var matcherEndpoint = Assert.IsType(endpoint); var routeValuesAddressNameMetadata = matcherEndpoint.Metadata.GetMetadata(); Assert.NotNull(routeValuesAddressNameMetadata); - Assert.Equal(string.Empty, routeValuesAddressNameMetadata.Name); + Assert.Equal(string.Empty, routeValuesAddressNameMetadata.RouteName); } [Fact] @@ -402,7 +402,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal var matcherEndpoint = Assert.IsType(ep); var routeValuesAddressMetadata = matcherEndpoint.Metadata.GetMetadata(); Assert.NotNull(routeValuesAddressMetadata); - Assert.Equal("namedRoute", routeValuesAddressMetadata.Name); + Assert.Equal("namedRoute", routeValuesAddressMetadata.RouteName); Assert.Equal("named/Home/Index/{id?}", matcherEndpoint.RoutePattern.RawText); }, (ep) => @@ -410,7 +410,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal var matcherEndpoint = Assert.IsType(ep); var routeValuesAddressMetadata = matcherEndpoint.Metadata.GetMetadata(); Assert.NotNull(routeValuesAddressMetadata); - Assert.Equal("namedRoute", routeValuesAddressMetadata.Name); + Assert.Equal("namedRoute", routeValuesAddressMetadata.RouteName); Assert.Equal("named/Products/Details/{id?}", matcherEndpoint.RoutePattern.RawText); }); } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/RequestFormLimitsFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/RequestFormLimitsFilterTest.cs index a36dd060e4..7b1234092b 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/RequestFormLimitsFilterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/RequestFormLimitsFilterTest.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal // Arrange var requestFormLimitsFilter = new RequestFormLimitsFilter(NullLoggerFactory.Instance); requestFormLimitsFilter.FormOptions = new FormOptions(); - var authorizationFilterContext = CreateauthorizationFilterContext( + var authorizationFilterContext = CreateAuthorizationFilterContext( new IFilterMetadata[] { requestFormLimitsFilter }); // Set to null explicitly as we want to make sure the filter adds one authorizationFilterContext.HttpContext.Features.Set(null); @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal // Arrange var requestFormLimitsFilter = new RequestFormLimitsFilter(NullLoggerFactory.Instance); requestFormLimitsFilter.FormOptions = new FormOptions(); - var authorizationFilterContext = CreateauthorizationFilterContext( + var authorizationFilterContext = CreateAuthorizationFilterContext( new IFilterMetadata[] { requestFormLimitsFilter }); var oldFormFeature = new FormFeature(authorizationFilterContext.HttpContext.Request); // Set to null explicitly as we want to make sure the filter adds one @@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal var requestFormLimitsFilter = new RequestFormLimitsFilter(loggerFactory); requestFormLimitsFilter.FormOptions = new FormOptions(); - var authorizationFilterContext = CreateauthorizationFilterContext( + var authorizationFilterContext = CreateAuthorizationFilterContext( new IFilterMetadata[] { requestFormLimitsFilter }); authorizationFilterContext.HttpContext.Request.Form = new FormCollection(null); @@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal var requestFormLimitsFilter = new RequestFormLimitsFilter(loggerFactory); requestFormLimitsFilter.FormOptions = new FormOptions(); - var authorizationFilterContext = CreateauthorizationFilterContext( + var authorizationFilterContext = CreateAuthorizationFilterContext( new IFilterMetadata[] { requestFormLimitsFilter }); // Set to null explicitly as we want to make sure the filter adds one authorizationFilterContext.HttpContext.Features.Set(null); @@ -112,7 +112,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal var requestFormLimitsFilter = new RequestFormLimitsFilter(loggerFactory); requestFormLimitsFilter.FormOptions = new FormOptions(); - var authorizationFilterContext = CreateauthorizationFilterContext( + var authorizationFilterContext = CreateAuthorizationFilterContext( new IFilterMetadata[] { requestFormLimitsFilter }); // Set to null explicitly as we want to make sure the filter adds one authorizationFilterContext.HttpContext.Features.Set( @@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal write.State.ToString()); } - private static AuthorizationFilterContext CreateauthorizationFilterContext(IFilterMetadata[] filters) + private static AuthorizationFilterContext CreateAuthorizationFilterContext(IFilterMetadata[] filters) { return new AuthorizationFilterContext(CreateActionContext(), filters); } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/RequestSizeLimitFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/RequestSizeLimitFilterTest.cs index 82c040508d..80be3c2e9a 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/RequestSizeLimitFilterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/RequestSizeLimitFilterTest.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal // Arrange var requestSizeLimitResourceFilter = new RequestSizeLimitFilter(NullLoggerFactory.Instance); requestSizeLimitResourceFilter.Bytes = 12345; - var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { requestSizeLimitResourceFilter }); + var authorizationFilterContext = CreateAuthorizationFilterContext(new IFilterMetadata[] { requestSizeLimitResourceFilter }); var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature(); authorizationFilterContext.HttpContext.Features.Set(httpMaxRequestBodySize); @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal requestSizeLimitResourceFilter.Bytes = 12345; var requestSizeLimitResourceFilterFinal = new RequestSizeLimitFilter(NullLoggerFactory.Instance); requestSizeLimitResourceFilterFinal.Bytes = 0; - var authorizationFilterContext = CreateauthorizationFilterContext( + var authorizationFilterContext = CreateAuthorizationFilterContext( new IFilterMetadata[] { requestSizeLimitResourceFilter, requestSizeLimitResourceFilterFinal }); var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature(); @@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal var requestSizeLimitResourceFilter = new RequestSizeLimitFilter(loggerFactory); requestSizeLimitResourceFilter.Bytes = 12345; - var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { requestSizeLimitResourceFilter }); + var authorizationFilterContext = CreateAuthorizationFilterContext(new IFilterMetadata[] { requestSizeLimitResourceFilter }); // Act requestSizeLimitResourceFilter.OnAuthorization(authorizationFilterContext); @@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal var requestSizeLimitResourceFilter = new RequestSizeLimitFilter(loggerFactory); requestSizeLimitResourceFilter.Bytes = 12345; - var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { requestSizeLimitResourceFilter }); + var authorizationFilterContext = CreateAuthorizationFilterContext(new IFilterMetadata[] { requestSizeLimitResourceFilter }); var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature(); httpMaxRequestBodySize.IsReadOnly = true; @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal var requestSizeLimitResourceFilter = new RequestSizeLimitFilter(loggerFactory); requestSizeLimitResourceFilter.Bytes = 12345; - var authorizationFilterContext = CreateauthorizationFilterContext(new IFilterMetadata[] { requestSizeLimitResourceFilter }); + var authorizationFilterContext = CreateAuthorizationFilterContext(new IFilterMetadata[] { requestSizeLimitResourceFilter }); var httpMaxRequestBodySize = new TestHttpMaxRequestBodySizeFeature(); authorizationFilterContext.HttpContext.Features.Set(httpMaxRequestBodySize); @@ -120,7 +120,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal Assert.Equal($"The maximum request body size has been set to 12345.", write.State.ToString()); } - private static AuthorizationFilterContext CreateauthorizationFilterContext(IFilterMetadata[] filters) + private static AuthorizationFilterContext CreateAuthorizationFilterContext(IFilterMetadata[] filters) { return new AuthorizationFilterContext(CreateActionContext(), filters); } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/BodyModelBinderTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/BodyModelBinderTests.cs index 21a66b0a40..71318bc1c3 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/BodyModelBinderTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/BodyModelBinderTests.cs @@ -467,7 +467,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders [Theory] [MemberData(nameof(DerivedInputFormattersThrowingNonInputFormatterException))] - public async Task BindModel_DerivedXmlInputFormatters_ThrowingNonInputFormatingException_AddsErrorToModelState( + public async Task BindModel_DerivedXmlInputFormatters_ThrowingNonInputFormattingException_AddsErrorToModelState( IInputFormatter formatter, string contentType, InputFormatterExceptionPolicy inputFormatterExceptionPolicy) diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/EnumTypeModelBinderTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/EnumTypeModelBinderTest.cs index e7c4a2bf2b..aa8f50aa79 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/EnumTypeModelBinderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/EnumTypeModelBinderTest.cs @@ -42,14 +42,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding [InlineData(false, typeof(IntEnum))] [InlineData(false, typeof(FlagsEnum))] public async Task BindModel_AddsErrorToModelState_ForEmptyValue_AndNonNullableEnumTypes( - bool suprressBindingUndefinedValueToEnumType, + bool suppressBindingUndefinedValueToEnumType, Type modelType) { // Arrange var message = "The value '' is invalid."; var binderInfo = GetBinderAndContext( modelType, - suprressBindingUndefinedValueToEnumType, + suppressBindingUndefinedValueToEnumType, valueProviderValue: ""); var bindingContext = binderInfo.Item1; var binder = binderInfo.Item2; diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/FormCollectionModelBinderProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/FormCollectionModelBinderProviderTest.cs index 8562af3410..38b5a0d65d 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/FormCollectionModelBinderProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Binders/FormCollectionModelBinderProviderTest.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders { [Theory] [InlineData(typeof(FormCollection))] - [InlineData(typeof(DerviedFormCollection))] + [InlineData(typeof(DerivedFormCollection))] public void Create_ThrowsException_ForFormCollectionModelType(Type modelType) { // Arrange @@ -62,9 +62,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders { } - private class DerviedFormCollection : FormCollection + private class DerivedFormCollection : FormCollection { - public DerviedFormCollection() : base(fields: null, files: null) { } + public DerivedFormCollection() : base(fields: null, files: null) { } } } } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ModelBindingHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ModelBindingHelperTest.cs index 116224e517..eab8c6a860 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ModelBindingHelperTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ModelBindingHelperTest.cs @@ -607,7 +607,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding } [Fact] - public async Task TryUpdataModel_ModelTypeDifferentFromModel_Throws() + public async Task TryUpdateModel_ModelTypeDifferentFromModel_Throws() { // Arrange var metadataProvider = new EmptyModelMetadataProvider(); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/RequestFormLimitsAttributeTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/RequestFormLimitsAttributeTest.cs index 8b8cbfa48d..df9eae7c9c 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/RequestFormLimitsAttributeTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/RequestFormLimitsAttributeTest.cs @@ -21,10 +21,10 @@ namespace Microsoft.AspNetCore.Mvc // Act & Assert foreach (var property in formOptionsProperties) { - var formLimiAttributeProperty = formLimitsAttributeProperties + var formLimitAttributeProperty = formLimitsAttributeProperties .Where(pi => property.Name == pi.Name && pi.PropertyType == property.PropertyType) .SingleOrDefault(); - Assert.NotNull(formLimiAttributeProperty); + Assert.NotNull(formLimitAttributeProperty); } } diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/RequireHttpsAttributeTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/RequireHttpsAttributeTests.cs index bac3672432..e1bd339e4e 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/RequireHttpsAttributeTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/RequireHttpsAttributeTests.cs @@ -196,7 +196,7 @@ namespace Microsoft.AspNetCore.Mvc [InlineData(null, false)] [InlineData(true, false)] [InlineData(false, true)] - public void OnAuthorization_RedirectsToHttpsEndpoint_WithSpecifiedStatusCodeAndrequireHttpsPermanentOption(bool? permanent, bool requireHttpsPermanent) + public void OnAuthorization_RedirectsToHttpsEndpoint_WithSpecifiedStatusCodeAndRequireHttpsPermanentOption(bool? permanent, bool requireHttpsPermanent) { var requestContext = new DefaultHttpContext(); requestContext.RequestServices = CreateServices(null, requireHttpsPermanent); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Routing/KnownRouteValueConstraintTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Routing/KnownRouteValueConstraintTests.cs index 5aecf45a77..61b51de28f 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Routing/KnownRouteValueConstraintTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Routing/KnownRouteValueConstraintTests.cs @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing "testController", "testAction"); actionDescriptor.RouteValues.Add("randomKey", "testRandom"); - var descriptorCollectionProvider = CreateActionDesciprtorCollectionProvider(actionDescriptor); + var descriptorCollectionProvider = CreateActionDescriptorCollectionProvider(actionDescriptor); var services = new ServiceCollection(); services.AddRouting(); @@ -214,7 +214,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing "testAction"); actionDescriptor.RouteValues.Add("randomKey", "testRandom"); - var provider = CreateActionDesciprtorCollectionProvider(actionDescriptor); + var provider = CreateActionDescriptorCollectionProvider(actionDescriptor); var constraint = new KnownRouteValueConstraint(provider); @@ -235,7 +235,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing private static HttpContext GetHttpContext(ActionDescriptor actionDescriptor, bool setupRequestServices = true) { - var descriptorCollectionProvider = CreateActionDesciprtorCollectionProvider(actionDescriptor); + var descriptorCollectionProvider = CreateActionDescriptorCollectionProvider(actionDescriptor); var context = new Mock(); if (setupRequestServices) @@ -247,7 +247,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing return context.Object; } - private static IActionDescriptorCollectionProvider CreateActionDesciprtorCollectionProvider(ActionDescriptor actionDescriptor) + private static IActionDescriptorCollectionProvider CreateActionDescriptorCollectionProvider(ActionDescriptor actionDescriptor) { var actionProvider = new Mock(MockBehavior.Strict); diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Routing/UrlHelperExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Routing/UrlHelperExtensionsTest.cs index c6e00c231e..f6b212c7e5 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Routing/UrlHelperExtensionsTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Routing/UrlHelperExtensionsTest.cs @@ -340,7 +340,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test.Routing } [Fact] - public void Page_UsesValueFromRouteValueIfPageHandlerIsNotExplicitySpecified() + public void Page_UsesValueFromRouteValueIfPageHandlerIsNotExplicitlySpecified() { // Arrange UrlRouteContext actual = null; diff --git a/test/Microsoft.AspNetCore.Mvc.Core.TestCommon/CommonResourceInvokerTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.TestCommon/CommonResourceInvokerTest.cs index 86d2f27071..ed4e80c7ff 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.TestCommon/CommonResourceInvokerTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.TestCommon/CommonResourceInvokerTest.cs @@ -1555,7 +1555,7 @@ namespace Microsoft.AspNetCore.Mvc var invoker = CreateInvoker( new IFilterMetadata[] { - resourceFilter1.Object, // This filter should see the result retured from resourceFilter2 + resourceFilter1.Object, // This filter should see the result returned from resourceFilter2 resourceFilter2.Object, // This filter will short circuit resourceFilter3.Object, // This shouldn't run - it will throw if it does exceptionFilter.Object, // This shouldn't run - it will throw if it does @@ -1603,7 +1603,7 @@ namespace Microsoft.AspNetCore.Mvc var invoker = CreateInvoker( new IFilterMetadata[] { - resourceFilter1.Object, // This filter should see the result retured from resourceFilter2 + resourceFilter1.Object, // This filter should see the result returned from resourceFilter2 resourceFilter2.Object, // This filter will short circuit resourceFilter3.Object, // This shouldn't run - it will throw if it does exceptionFilter.Object, // This shouldn't run - it will throw if it does @@ -1653,7 +1653,7 @@ namespace Microsoft.AspNetCore.Mvc var invoker = CreateInvoker( new IFilterMetadata[] { - resourceFilter1.Object, // This filter should see the result retured from resourceFilter2 + resourceFilter1.Object, // This filter should see the result returned from resourceFilter2 resourceFilter2.Object, resourceFilter3.Object, // This shouldn't run - it will throw if it does resultFilter.Object // This shouldn't run - it will throw if it does diff --git a/test/Microsoft.AspNetCore.Mvc.Core.TestCommon/TestModelMetadataProvider.cs b/test/Microsoft.AspNetCore.Mvc.Core.TestCommon/TestModelMetadataProvider.cs index faff630e0b..2548dc26c3 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.TestCommon/TestModelMetadataProvider.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.TestCommon/TestModelMetadataProvider.cs @@ -181,7 +181,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding { private List> _bindingActions = new List>(); private List> _displayActions = new List>(); - private List> _valiationActions = new List>(); + private List> _validationActions = new List>(); private readonly ModelMetadataIdentity _key; @@ -216,7 +216,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding { if (_key.Equals(context.Key)) { - foreach (var action in _valiationActions) + foreach (var action in _validationActions) { action(context.ValidationMetadata); } @@ -237,7 +237,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding public IMetadataBuilder ValidationDetails(Action action) { - _valiationActions.Add(action); + _validationActions.Add(action); return this; } } diff --git a/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonPatchOperationsArrayProviderTests.cs b/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonPatchOperationsArrayProviderTests.cs index e3c9c4215b..ed140a72e2 100644 --- a/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonPatchOperationsArrayProviderTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonPatchOperationsArrayProviderTests.cs @@ -17,8 +17,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Json public void OnProvidersExecuting_FindsJsonPatchDocuments_ProvidesOperationsArray() { // Arrange - var metadataprovider = new TestModelMetadataProvider(); - var provider = new JsonPatchOperationsArrayProvider(metadataprovider); + var metadataProvider = new TestModelMetadataProvider(); + var provider = new JsonPatchOperationsArrayProvider(metadataProvider); var jsonPatchParameterDescription = new ApiParameterDescription { Type = typeof(JsonPatchDocument) diff --git a/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/Internal/EnumerableWrapperProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/Internal/EnumerableWrapperProviderTest.cs index 59ac66a273..b89802115d 100644 --- a/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/Internal/EnumerableWrapperProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/Internal/EnumerableWrapperProviderTest.cs @@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal [InlineData(typeof(List))] [InlineData(typeof(List))] [InlineData(typeof(PersonList))] - public void ThrowsArugmentExceptionFor_ConcreteEnumerableOfT(Type declaredType) + public void ThrowsArgumentExceptionFor_ConcreteEnumerableOfT(Type declaredType) { // Arrange var expectedMessage = "The type must be an interface and must be or derive from 'IEnumerable`1'."; diff --git a/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/Internal/SerializableWrapperProviderFactoryTest.cs b/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/Internal/SerializableWrapperProviderFactoryTest.cs index e300f1d434..e09a15b43c 100644 --- a/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/Internal/SerializableWrapperProviderFactoryTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/Internal/SerializableWrapperProviderFactoryTest.cs @@ -13,10 +13,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal public void Creates_WrapperProvider_ForSerializableErrorType(bool isSerialization) { // Arrange - var serializableErroWrapperProviderFactory = new SerializableErrorWrapperProviderFactory(); + var serializableErrorWrapperProviderFactory = new SerializableErrorWrapperProviderFactory(); // Act - var wrapperProvider = serializableErroWrapperProviderFactory.GetProvider( + var wrapperProvider = serializableErrorWrapperProviderFactory.GetProvider( new WrapperProviderContext(typeof(SerializableError), isSerialization)); // Assert @@ -28,10 +28,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal public void ReturnsNullFor_NonSerializableErrorTypes() { // Arrange - var serializableErroWrapperProviderFactory = new SerializableErrorWrapperProviderFactory(); + var serializableErrorWrapperProviderFactory = new SerializableErrorWrapperProviderFactory(); // Act - var wrapperProvider = serializableErroWrapperProviderFactory.GetProvider( + var wrapperProvider = serializableErrorWrapperProviderFactory.GetProvider( new WrapperProviderContext(typeof(Person), isSerialization: true)); // Assert diff --git a/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/XmlDataContractSerializerInputFormatterTest.cs b/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/XmlDataContractSerializerInputFormatterTest.cs index 885e231a5a..fdd09e318d 100644 --- a/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/XmlDataContractSerializerInputFormatterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/XmlDataContractSerializerInputFormatterTest.cs @@ -110,7 +110,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml } [Fact] - public void HasProperSuppportedMediaTypes() + public void HasProperSupportedMediaTypes() { // Arrange & Act var formatter = new XmlDataContractSerializerInputFormatter(new MvcOptions()); @@ -123,7 +123,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml } [Fact] - public void HasProperSuppportedEncodings() + public void HasProperSupportedEncodings() { // Arrange & Act var formatter = new XmlDataContractSerializerInputFormatter(new MvcOptions()); diff --git a/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/XmlSerializerInputFormatterTest.cs b/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/XmlSerializerInputFormatterTest.cs index 423edaaa20..c1bf95ba46 100644 --- a/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/XmlSerializerInputFormatterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Formatters.Xml.Test/XmlSerializerInputFormatterTest.cs @@ -349,7 +349,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml } [Fact] - public void HasProperSuppportedMediaTypes() + public void HasProperSupportedMediaTypes() { // Arrange & Act var formatter = new XmlSerializerInputFormatter(new MvcOptions()); @@ -362,7 +362,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml } [Fact] - public void HasProperSuppportedEncodings() + public void HasProperSupportedEncodings() { // Arrange & Act var formatter = new XmlSerializerInputFormatter(new MvcOptions()); diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ApiExplorerTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ApiExplorerTest.cs index 6230542cb0..6b4b7acd73 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ApiExplorerTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ApiExplorerTest.cs @@ -1359,7 +1359,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests } [Fact] - public async Task ApiConvention_ForActionWtihApiConventionMethod() + public async Task ApiConvention_ForActionWithApiConventionMethod() { // Arrange var expectedMediaTypes = new[] { "application/json", "application/xml", "text/json", "text/xml" }; diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ConsumesAttributeTestsBase.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ConsumesAttributeTestsBase.cs index fca64c9dc4..71502e6f24 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ConsumesAttributeTestsBase.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ConsumesAttributeTestsBase.cs @@ -85,7 +85,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests [Theory] [InlineData("application/json")] [InlineData("text/json")] - public async Task ActionLevelAttribute_OveridesClassLevel(string requestContentType) + public async Task ActionLevelAttribute_OverridesClassLevel(string requestContentType) { // Arrange var input = "{SampleString:\"" + requestContentType + "\"}"; diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/DataAnnotationTests.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/DataAnnotationTests.cs index a67fb5dd83..f90e239345 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/DataAnnotationTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/DataAnnotationTests.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests private const string EnumUrl = "http://localhost/Enum/Enum"; [Fact] - public async Task DataAnnotationLocalizionOfEnums_FromDataAnnotationLocalizerProvider() + public async Task DataAnnotationLocalizationOfEnums_FromDataAnnotationLocalizerProvider() { // Arrange & Act var response = await Client.GetAsync(EnumUrl); diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/HtmlGenerationTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/HtmlGenerationTest.cs index 65ba3292dd..1f7e18760b 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/HtmlGenerationTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/HtmlGenerationTest.cs @@ -404,7 +404,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests Assert.Equal(expected2, response2.Trim()); // Act - 3 - // Resend the cookiesless request and cached result from the first response. + // Resend the cookieless request and cached result from the first response. var response3 = await Client.GetStringAsync("/catalog/cart?correlationid=3"); // Assert - 3 diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorFileUpdateTests.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorFileUpdateTests.cs new file mode 100644 index 0000000000..b4aee9ad9c --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorFileUpdateTests.cs @@ -0,0 +1,131 @@ +// Copyright (c) .NET Foundation. 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.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Razor; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.FunctionalTests +{ + // Verifies that updating Razor files (views and pages) with AllowRecompilingViewsOnFileChange=true works + public class RazorFileUpdateTests : IClassFixture> + { + public RazorFileUpdateTests(MvcTestFixture fixture) + { + var factory = fixture.WithWebHostBuilder(builder => + { + builder.UseStartup(); + builder.ConfigureTestServices(services => + { + services.Configure(options => options.AllowRecompilingViewsOnFileChange = true); + }); + }); + Client = factory.CreateDefaultClient(); + } + + public HttpClient Client { get; } + + [Fact] + public async Task RazorViews_AreUpdatedOnChange() + { + // Arrange + var expected1 = "Original content"; + var expected2 = "New content"; + var path = "/Views/UpdateableShared/_Partial.cshtml"; + + // Act - 1 + var body = await Client.GetStringAsync("/UpdateableFileProvider"); + + // Assert - 1 + Assert.Equal(expected1, body.Trim(), ignoreLineEndingDifferences: true); + + // Act - 2 + await UpdateFile(path, expected2); + body = await Client.GetStringAsync("/UpdateableFileProvider"); + + // Assert - 2 + Assert.Equal(expected2, body.Trim(), ignoreLineEndingDifferences: true); + } + + [Fact] + public async Task RazorViews_AreUpdatedWhenViewImportsChange() + { + // Arrange + var content = "@GetType().Assembly.FullName"; + await UpdateFile("/Views/UpdateableIndex/Index.cshtml", content); + var initial = await Client.GetStringAsync("/UpdateableFileProvider"); + + // Act + // Trigger a change in ViewImports + await UpdateFile("/Views/UpdateableIndex/_ViewImports.cshtml", string.Empty); + var updated = await Client.GetStringAsync("/UpdateableFileProvider"); + + // Assert + Assert.NotEqual(initial, updated); + } + + [Fact] + public async Task RazorPages_AreUpdatedOnChange() + { + // Arrange + var expected1 = "Original content"; + var expected2 = "New content"; + + // Act - 1 + var body = await Client.GetStringAsync("/UpdateablePage"); + + // Assert - 1 + Assert.Equal(expected1, body.Trim(), ignoreLineEndingDifferences: true); + + // Act - 2 + await UpdateRazorPages(); + await UpdateFile("/Pages/UpdateablePage.cshtml", "@page" + Environment.NewLine + expected2); + body = await Client.GetStringAsync("/UpdateablePage"); + + // Assert - 2 + Assert.Equal(expected2, body.Trim(), ignoreLineEndingDifferences: true); + } + + [Fact] + public async Task RazorPages_AreUpdatedWhenViewImportsChange() + { + // Arrange + var content = "@GetType().Assembly.FullName"; + await UpdateFile("/Pages/UpdateablePage.cshtml", "@page" + Environment.NewLine + content); + var initial = await Client.GetStringAsync("/UpdateablePage"); + + // Act + // Trigger a change in ViewImports + await UpdateRazorPages(); + await UpdateFile("/Pages/UpdateablePage.cshtml", "@page" + Environment.NewLine + content); + var updated = await Client.GetStringAsync("/UpdateablePage"); + + // Assert + Assert.NotEqual(initial, updated); + } + + private async Task UpdateFile(string path, string content) + { + var updateContent = new FormUrlEncodedContent(new Dictionary + { + { "path", path }, + { "content", content }, + }); + + var response = await Client.PostAsync($"/UpdateableFileProvider/Update", updateContent); + response.EnsureSuccessStatusCode(); + } + + private async Task UpdateRazorPages() + { + var response = await Client.PostAsync($"/UpdateableFileProvider/UpdateRazorPages", new StringContent(string.Empty)); + response.EnsureSuccessStatusCode(); + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs index 3c90af4882..8aca9a9bcf 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs @@ -1422,7 +1422,7 @@ Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary`1[AspNetCore.InjectedPa } [Fact] - public async Task ViewDataAvaialableInPageFilter_AfterHandlerMethod_ReturnsPageResult() + public async Task ViewDataAwaitableInPageFilter_AfterHandlerMethod_ReturnsPageResult() { // Act var content = await Client.GetStringAsync("http://localhost/Pages/ViewDataAvailableAfterHandlerExecuted"); diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesWithBasePathTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesWithBasePathTest.cs index 462e83326d..4518e7b442 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesWithBasePathTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesWithBasePathTest.cs @@ -384,7 +384,7 @@ Hello from /Pages/Shared/"; } [Fact] - public async Task AllowAnonymouseToPageConvention_CanBeAppliedToAreaPages() + public async Task AllowAnonymousToPageConvention_CanBeAppliedToAreaPages() { // Act var response = await Client.GetStringAsync("/Accounts/RequiresAuth/AllowAnonymous"); @@ -395,7 +395,7 @@ Hello from /Pages/Shared/"; // These test is important as it covers a feature that allows razor pages to use a different // model at runtime that wasn't known at compile time. Like a non-generic model used at compile - // time and overrided at runtime with a closed-generic model that performs the actual implementation. + // time and overriden at runtime with a closed-generic model that performs the actual implementation. // An example of this is how the Identity UI library defines a base page model in their views, // like how the Register.cshtml view defines its model as RegisterModel and then, at runtime it replaces // that model with RegisterModel where TUser is the type of the user used to configure identity. @@ -506,7 +506,7 @@ Hello from /Pages/Shared/"; } [Fact] - public async Task ViewDataAttributes_SetInPageModel_AreTransferedToLayout() + public async Task ViewDataAttributes_SetInPageModel_AreTransferredToLayout() { // Arrange var document = await Client.GetHtmlDocumentAsync("/ViewData/ViewDataInPage"); @@ -526,7 +526,7 @@ Hello from /Pages/Shared/"; } [Fact] - public async Task ViewDataAttributes_SetInPageWithoutModel_AreTransferedToLayout() + public async Task ViewDataAttributes_SetInPageWithoutModel_AreTransferredToLayout() { // Arrange var document = await Client.GetHtmlDocumentAsync("/ViewData/ViewDataInPageWithoutModel"); diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RoutingTestsBase.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RoutingTestsBase.cs index 7917d36c7d..f3ee418fb5 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RoutingTestsBase.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RoutingTestsBase.cs @@ -921,7 +921,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests } [Fact] - public virtual async Task AttributeRoutedAction_LinkWithName_WithNameOverrridenFromController() + public virtual async Task AttributeRoutedAction_LinkWithName_WithNameOverridenFromController() { // Arrange & Act var response = await Client.DeleteAsync("http://localhost/api/Company/5"); diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/SimpleTests.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/SimpleTests.cs index b5169c96ab..214fcc0eb5 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/SimpleTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/SimpleTests.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests public HttpClient Client { get; } [Fact] - public async Task JsonSerializeFormated() + public async Task JsonSerializeFormatted() { // Arrange var expected = "{" + Environment.NewLine diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/TagHelpersTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/TagHelpersTest.cs index 9c807942ea..e6559100f4 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/TagHelpersTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/TagHelpersTest.cs @@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests } [Fact] - public async Task ReregisteringAntiforgeryTokenInsideFormTagHelper_DoesNotAddDuplicateAntiforgeryTokenFields() + public async Task ReRegisteringAntiforgeryTokenInsideFormTagHelper_DoesNotAddDuplicateAntiforgeryTokenFields() { // Arrange var expectedMediaType = MediaTypeHeaderValue.Parse("text/html; charset=utf-8"); diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ViewEngineTests.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ViewEngineTests.cs index 363f534469..7c23e4c377 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ViewEngineTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ViewEngineTests.cs @@ -270,28 +270,6 @@ Hello from Shared/_EmbeddedPartial Assert.Equal(expected, body.Trim(), ignoreLineEndingDifferences: true); } - [Fact] - public async Task RazorViewEngine_UpdatesViewsReferencedViaRelativePathsOnChange() - { - // Arrange - var expected1 = "Original content"; - var expected2 = "New content"; - - // Act - 1 - var body = await Client.GetStringAsync("/UpdateableFileProvider"); - - // Assert - 1 - Assert.Equal(expected1, body.Trim(), ignoreLineEndingDifferences: true); - - // Act - 2 - var response = await Client.PostAsync("/UpdateableFileProvider/Update", new StringContent(string.Empty)); - response.EnsureSuccessStatusCode(); - body = await Client.GetStringAsync("/UpdateableFileProvider"); - - // Assert - 1 - Assert.Equal(expected2, body.Trim(), ignoreLineEndingDifferences: true); - } - [Fact] public async Task LayoutValueIsPassedBetweenNestedViewStarts() { diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs index 9080f544e9..054b28d7cb 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs @@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests } [Fact] - public async Task ActionThrowsHttpResponseException_EnsureGlobalHttpresponseExceptionActionFilter_IsInvoked() + public async Task ActionThrowsHttpResponseException_EnsureGlobalHttpResponseExceptionActionFilter_IsInvoked() { // Arrange & Act var response = await Client.GetAsync( diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/XmlDataContractSerializerInputFormatterTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/XmlDataContractSerializerInputFormatterTest.cs index 3b97473fdd..1b1b74a591 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/XmlDataContractSerializerInputFormatterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/XmlDataContractSerializerInputFormatterTest.cs @@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests // Verifies that the model state has errors related to body model validation. [Fact] - public async Task DataMissingForRefereneceTypeProperties_AndModelIsBound_AndHasMixedValidationErrors() + public async Task DataMissingForReferenceTypeProperties_AndModelIsBound_AndHasMixedValidationErrors() { // Arrange var input = " throw new Exception("Can't call me"); + var result2 = await viewCompiler.CompileAsync(path); + + // Assert 2 + Assert.Same(result1, result2); + } + + [Fact] + public async Task CompileAsync_InvalidatesCache_IfChangeTokenExpires_WhenWatchingForFileChanges() + { + // Arrange + var path = "/Views/Home/Index.cshtml"; + var fileProvider = new TestFileProvider(); + var fileInfo = fileProvider.AddFile(path, "some content"); + var viewCompiler = GetViewCompiler(fileProvider); + viewCompiler.AllowRecompilingViewsOnFileChange = true; // Act 1 var result1 = await viewCompiler.CompileAsync(path); @@ -125,6 +189,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal var fileProvider = new TestFileProvider(); var fileInfo = fileProvider.AddFile(path, "some content"); var viewCompiler = GetViewCompiler(fileProvider); + viewCompiler.AllowRecompilingViewsOnFileChange = true; var expected2 = new CompiledViewDescriptor(); // Act 1 @@ -151,6 +216,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal var fileProvider = new TestFileProvider(); var fileInfo = fileProvider.AddFile(path, "some content"); var viewCompiler = GetViewCompiler(fileProvider); + viewCompiler.AllowRecompilingViewsOnFileChange = true; var expected2 = new CompiledViewDescriptor(); // Act 1 @@ -327,6 +393,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal }; var viewCompiler = GetViewCompiler(fileProvider, precompiledViews: new[] { precompiledView }); + viewCompiler.AllowRecompilingViewsOnFileChange = true; // Act var result = await viewCompiler.CompileAsync(path); @@ -371,7 +438,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal } [Fact] - public async Task CompileAsync_PrecompiledViewWithChecksum_CanRecompile() + public async Task CompileAsync_PrecompiledViewWithChecksum_DoesNotAddExpirationTokens() { // Arrange var path = "/Views/Home/Index.cshtml"; @@ -392,11 +459,43 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal var viewCompiler = GetViewCompiler(fileProvider, precompiledViews: new[] { precompiledView }); + // Act + var result = await viewCompiler.CompileAsync(path); + + // Assert + Assert.Same(precompiledView.Item, result.Item); + Assert.Empty(result.ExpirationTokens); + } + + [Fact] + public async Task CompileAsync_PrecompiledViewWithChecksum_CanRecompile() + { + // Arrange + var path = "/Views/Home/Index.cshtml"; + + var fileProvider = new TestFileProvider(); + var fileInfo = fileProvider.AddFile(path, "some content"); + + var expected2 = new CompiledViewDescriptor(); + + var precompiledView = new CompiledViewDescriptor + { + RelativePath = path, + Item = new TestRazorCompiledItem(typeof(string), "mvc.1.0.view", path, new object[] + { + new RazorSourceChecksumAttribute("SHA1", GetChecksum("some content"), path), + }), + }; + + var viewCompiler = GetViewCompiler(fileProvider, precompiledViews: new[] { precompiledView }); + viewCompiler.AllowRecompilingViewsOnFileChange = true; + // Act - 1 var result = await viewCompiler.CompileAsync(path); // Assert - 1 Assert.Same(precompiledView.Item, result.Item); + Assert.NotEmpty(result.ExpirationTokens); // Act - 2 fileInfo.Content = "some other content"; @@ -427,6 +526,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal }; var viewCompiler = GetViewCompiler(fileProvider, precompiledViews: new[] { precompiledView }); + viewCompiler.AllowRecompilingViewsOnFileChange = true; // Act - 1 var result = await viewCompiler.CompileAsync(path); @@ -463,6 +563,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal }; var viewCompiler = GetViewCompiler(fileProvider, precompiledViews: new[] { precompiledView }); + viewCompiler.AllowRecompilingViewsOnFileChange = true; viewCompiler.Compile = _ => expected1; // Act - 1 @@ -504,6 +605,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal }; var viewCompiler = GetViewCompiler(fileProvider, precompiledViews: new[] { precompiledView }); + viewCompiler.AllowRecompilingViewsOnFileChange = true; // Act - 1 var result = await viewCompiler.CompileAsync(path); @@ -731,7 +833,7 @@ this should fail"; } [Fact] - public void Compile_InvokessCallback() + public void Compile_InvokesCallback() { // Arrange var content = "public class MyTestType {}"; diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewEngineOptionsSetupTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewEngineOptionsSetupTest.cs index 1351b64fa5..fc28afe325 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewEngineOptionsSetupTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewEngineOptionsSetupTest.cs @@ -2,7 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; using Moq; using Xunit; @@ -19,7 +23,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal var hostingEnv = new Mock(); hostingEnv.SetupGet(e => e.ContentRootFileProvider) .Returns(expected); - var optionsSetup = new RazorViewEngineOptionsSetup(hostingEnv.Object); + + var optionsSetup = GetSetup(hostingEnvironment: hostingEnv.Object); // Act optionsSetup.Configure(options); @@ -28,5 +33,128 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal var fileProvider = Assert.Single(options.FileProviders); Assert.Same(expected, fileProvider); } + + [Fact] + public void PostConfigure_SetsAllowRecompilingViewsOnFileChange_For21() + { + // Arrange + var options = new RazorViewEngineOptions(); + var optionsSetup = GetSetup(CompatibilityVersion.Version_2_1); + + // Act + optionsSetup.Configure(options); + optionsSetup.PostConfigure(string.Empty, options); + + // Assert + Assert.True(options.AllowRecompilingViewsOnFileChange); + } + + [Theory] + [InlineData(CompatibilityVersion.Version_2_2)] + [InlineData(CompatibilityVersion.Latest)] + public void PostConfigure_SetsAllowRecompilingViewsOnFileChange_InDevelopmentMode(CompatibilityVersion compatibilityVersion) + { + // Arrange + var options = new RazorViewEngineOptions(); + var hostingEnv = Mock.Of(env => env.EnvironmentName == EnvironmentName.Development); + var optionsSetup = GetSetup(compatibilityVersion, hostingEnv); + + // Act + optionsSetup.Configure(options); + optionsSetup.PostConfigure(string.Empty, options); + + // Assert + Assert.True(options.AllowRecompilingViewsOnFileChange); + } + + [Theory] + [InlineData(CompatibilityVersion.Version_2_2)] + [InlineData(CompatibilityVersion.Latest)] + public void PostConfigure_DoesNotSetAllowRecompilingViewsOnFileChange_WhenNotInDevelopment(CompatibilityVersion compatibilityVersion) + { + // Arrange + var options = new RazorViewEngineOptions(); + var hostingEnv = Mock.Of(env => env.EnvironmentName == EnvironmentName.Staging); + var optionsSetup = GetSetup(compatibilityVersion, hostingEnv); + + // Act + optionsSetup.Configure(options); + optionsSetup.PostConfigure(string.Empty, options); + + // Assert + Assert.False(options.AllowRecompilingViewsOnFileChange); + } + + [Fact] + public void RazorViewEngineOptionsSetup_DoesNotOverwriteAllowRecompilingViewsOnFileChange_In21CompatMode() + { + // Arrange + var hostingEnv = Mock.Of(env => env.EnvironmentName == EnvironmentName.Staging); + var compatibilityVersion = new MvcCompatibilityOptions { CompatibilityVersion = CompatibilityVersion.Version_2_1 }; + var optionsSetup = GetSetup(CompatibilityVersion.Version_2_1, hostingEnv); + var serviceProvider = new ServiceCollection() + .AddOptions() + .AddSingleton>(optionsSetup) + .Configure(o => o.AllowRecompilingViewsOnFileChange = false) + .BuildServiceProvider(); + + // Act + var options = serviceProvider.GetRequiredService>(); + + // Assert + Assert.False(options.Value.AllowRecompilingViewsOnFileChange); + } + + [Fact] + public void RazorViewEngineOptionsSetup_ConfiguresAllowRecompilingViewsOnFileChange() + { + // Arrange + var hostingEnv = Mock.Of(env => env.EnvironmentName == EnvironmentName.Production); + var compatibilityVersion = new MvcCompatibilityOptions { CompatibilityVersion = CompatibilityVersion.Version_2_2 }; + var optionsSetup = GetSetup(CompatibilityVersion.Version_2_2, hostingEnv); + var serviceProvider = new ServiceCollection() + .AddOptions() + .AddSingleton>(optionsSetup) + .BuildServiceProvider(); + + // Act + var options = serviceProvider.GetRequiredService>(); + + // Assert + Assert.False(options.Value.AllowRecompilingViewsOnFileChange); + } + + [Fact] + public void RazorViewEngineOptionsSetup_DoesNotOverwriteAllowRecompilingViewsOnFileChange() + { + // Arrange + var hostingEnv = Mock.Of(env => env.EnvironmentName == EnvironmentName.Production); + var optionsSetup = GetSetup(CompatibilityVersion.Version_2_2, hostingEnv); + var serviceProvider = new ServiceCollection() + .AddOptions() + .AddSingleton>(optionsSetup) + .Configure(o => o.AllowRecompilingViewsOnFileChange = true) + .BuildServiceProvider(); + + // Act + var options = serviceProvider.GetRequiredService>(); + + // Assert + Assert.True(options.Value.AllowRecompilingViewsOnFileChange); + } + + private static RazorViewEngineOptionsSetup GetSetup( + CompatibilityVersion compatibilityVersion = CompatibilityVersion.Latest, + IHostingEnvironment hostingEnvironment = null) + { + hostingEnvironment = hostingEnvironment ?? Mock.Of(); + var compatibilityOptions = new MvcCompatibilityOptions { CompatibilityVersion = compatibilityVersion }; + + return new RazorViewEngineOptionsSetup( + hostingEnvironment, + NullLoggerFactory.Instance, + Options.Create(compatibilityOptions)); + } + } } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageActivatorTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageActivatorTest.cs index 34a8b0926b..f96d2ba439 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageActivatorTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageActivatorTest.cs @@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor Assert.Same(DiagnosticSource, instance.DiagnosticSource); Assert.Same(HtmlEncoder, instance.HtmlEncoder); - // When we don't have a model property, the activator will just leave viewdata alone. + // When we don't have a model property, the activator will just leave ViewData alone. Assert.NotNull(viewContext.ViewData); } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageTest.cs index 2d7ba2df96..73a92e8232 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageTest.cs @@ -303,7 +303,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor Assert.Equal(1, bufferScope.CreatedBuffers.Count); Assert.Equal(0, bufferScope.ReturnedBuffers.Count); - v.Write("Level:1-A"); // Creates a new buffer for the taghelper. + v.Write("Level:1-A"); // Creates a new buffer for the TagHelper. Assert.Equal(2, bufferScope.CreatedBuffers.Count); Assert.Equal(0, bufferScope.ReturnedBuffers.Count); @@ -318,7 +318,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor Assert.Equal(2, bufferScope.CreatedBuffers.Count); Assert.Equal(0, bufferScope.ReturnedBuffers.Count); - v.Write(outputLevel1); // Writing the taghelper to output returns a buffer. + v.Write(outputLevel1); // Writing the TagHelper to output returns a buffer. Assert.Equal(2, bufferScope.CreatedBuffers.Count); Assert.Equal(1, bufferScope.ReturnedBuffers.Count); } @@ -335,7 +335,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor Assert.Equal(2, bufferScope.CreatedBuffers.Count); Assert.Equal(1, bufferScope.ReturnedBuffers.Count); - v.Write("Level:1-B"); // Creates a new buffer for the taghelper. + v.Write("Level:1-B"); // Creates a new buffer for the TagHelper. Assert.Equal(3, bufferScope.CreatedBuffers.Count); Assert.Equal(1, bufferScope.ReturnedBuffers.Count); @@ -351,7 +351,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor Assert.Equal(3, bufferScope.CreatedBuffers.Count); Assert.Equal(1, bufferScope.ReturnedBuffers.Count); - v.Write("Level:2"); // Creates a new buffer for the taghelper. + v.Write("Level:2"); // Creates a new buffer for the TagHelper. Assert.Equal(4, bufferScope.CreatedBuffers.Count); Assert.Equal(1, bufferScope.ReturnedBuffers.Count); @@ -366,7 +366,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor Assert.Equal(4, bufferScope.CreatedBuffers.Count); Assert.Equal(1, bufferScope.ReturnedBuffers.Count); - v.Write(outputLevel2); // Writing the taghelper to output returns a buffer. + v.Write(outputLevel2); // Writing the TagHelper to output returns a buffer. Assert.Equal(4, bufferScope.CreatedBuffers.Count); Assert.Equal(2, bufferScope.ReturnedBuffers.Count); } @@ -382,7 +382,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor Assert.Equal(4, bufferScope.CreatedBuffers.Count); Assert.Equal(2, bufferScope.ReturnedBuffers.Count); - v.Write(outputLevel1); // Writing the taghelper to output returns a buffer. + v.Write(outputLevel1); // Writing the TagHelper to output returns a buffer. Assert.Equal(4, bufferScope.CreatedBuffers.Count); Assert.Equal(3, bufferScope.ReturnedBuffers.Count); } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorViewEngineTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorViewEngineTest.cs index be418aa7e3..f522b54a49 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorViewEngineTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorViewEngineTest.cs @@ -8,6 +8,7 @@ using System.Threading; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Razor.Compilation; using Microsoft.AspNetCore.Mvc.Razor.Internal; using Microsoft.AspNetCore.Mvc.Routing; @@ -749,7 +750,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor } [Fact] - public void FindView_NoramlizesPaths_ReturnedByViewLocationExpanders() + public void FindView_NormalizesPaths_ReturnedByViewLocationExpanders() { // Arrange var pageFactory = new Mock(); @@ -1979,7 +1980,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor IEnumerable areaViewLocationFormats = null, IEnumerable pageViewLocationFormats = null) { - var optionsSetup = new RazorViewEngineOptionsSetup(Mock.Of()); + var optionsSetup = new RazorViewEngineOptionsSetup( + Mock.Of(), + NullLoggerFactory.Instance, + Options.Create(new MvcCompatibilityOptions())); var options = new RazorViewEngineOptions(); optionsSetup.Configure(options); @@ -2040,8 +2044,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor routeData.Values.Add(kvp.Key, kvp.Value); } - var actionDesciptor = new ActionDescriptor(); - return new ActionContext(httpContext, routeData, actionDesciptor); + var actionDescriptor = new ActionDescriptor(); + return new ActionContext(httpContext, routeData, actionDescriptor); } private static ActionContext GetActionContextWithActionDescriptor( diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs index 4b1e2c4429..2573072e01 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs @@ -203,7 +203,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure } [Fact] - public void GetDescriptors_CopiesEndPointMetadataFromModel() + public void GetDescriptors_CopiesEndpointMetadataFromModel() { // Arrange var expected = new object(); diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/AuthorizationPageApplicationModelProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/AuthorizationPageApplicationModelProviderTest.cs index 85b51820df..c15912dede 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/AuthorizationPageApplicationModelProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/AuthorizationPageApplicationModelProviderTest.cs @@ -20,12 +20,12 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal { // Arrange var policyProvider = new DefaultAuthorizationPolicyProvider(Options.Create(new AuthorizationOptions())); - var autorizationProvider = new AuthorizationPageApplicationModelProvider(policyProvider); + var authorizationProvider = new AuthorizationPageApplicationModelProvider(policyProvider); var typeInfo = typeof(PageWithAuthorizeHandlers).GetTypeInfo(); var context = GetApplicationProviderContext(typeInfo); // Act - autorizationProvider.OnProvidersExecuting(context); + authorizationProvider.OnProvidersExecuting(context); // Assert Assert.Collection( @@ -53,11 +53,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal { // Arrange var policyProvider = new DefaultAuthorizationPolicyProvider(Options.Create(new AuthorizationOptions())); - var autorizationProvider = new AuthorizationPageApplicationModelProvider(policyProvider); + var authorizationProvider = new AuthorizationPageApplicationModelProvider(policyProvider); var context = GetApplicationProviderContext(typeof(TestPage).GetTypeInfo()); // Act - autorizationProvider.OnProvidersExecuting(context); + authorizationProvider.OnProvidersExecuting(context); // Assert Assert.Collection( @@ -90,12 +90,12 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal options.Value.AddPolicy("Derived", policy => policy.RequireClaim("Derived")); var policyProvider = new DefaultAuthorizationPolicyProvider(options); - var autorizationProvider = new AuthorizationPageApplicationModelProvider(policyProvider); + var authorizationProvider = new AuthorizationPageApplicationModelProvider(policyProvider); var context = GetApplicationProviderContext(typeof(TestPageWithDerivedModel).GetTypeInfo()); // Act - autorizationProvider.OnProvidersExecuting(context); + authorizationProvider.OnProvidersExecuting(context); // Assert AuthorizeFilter authorizeFilter = null; @@ -133,11 +133,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal { // Arrange var policyProvider = new DefaultAuthorizationPolicyProvider(Options.Create(new AuthorizationOptions())); - var autorizationProvider = new AuthorizationPageApplicationModelProvider(policyProvider); + var authorizationProvider = new AuthorizationPageApplicationModelProvider(policyProvider); var context = GetApplicationProviderContext(typeof(PageWithAnonymousModel).GetTypeInfo()); // Act - autorizationProvider.OnProvidersExecuting(context); + authorizationProvider.OnProvidersExecuting(context); // Assert Assert.Collection( diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/CompiledPageActionDescriptorBuilderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/CompiledPageActionDescriptorBuilderTest.cs index 7d12648d04..4627d28c89 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/CompiledPageActionDescriptorBuilderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/CompiledPageActionDescriptorBuilderTest.cs @@ -251,7 +251,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal } [Fact] - public void CreateHandlerMethods_CopiesParameterDecriptorsFromParameterModel() + public void CreateHandlerMethods_CopiesParameterDescriptorsFromParameterModel() { // Arrange var actionDescriptor = new PageActionDescriptor(); diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/CompiledPageRouteModelProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/CompiledPageRouteModelProviderTest.cs index fa00d8bd60..1e2ced5c55 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/CompiledPageRouteModelProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/CompiledPageRouteModelProviderTest.cs @@ -520,7 +520,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal public void OnProvidersExecuting_UsesTheFirstDescriptorForEachPath() { // ViewsFeature may contain duplicate entries for the same Page - for instance when an app overloads a library's views. - // It picks the first entry for each path. In the ordinary case, this should ensure that the app's Razor Pages are prefered + // It picks the first entry for each path. In the ordinary case, this should ensure that the app's Razor Pages are preferred // to a Razor Page added by a library. // Arrange diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/DefaultPageApplicationModelProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/DefaultPageApplicationModelProviderTest.cs index 1a82c834ec..2ad90a08a8 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/DefaultPageApplicationModelProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/DefaultPageApplicationModelProviderTest.cs @@ -455,7 +455,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal Assert.Same(typeof(EmptyPage).GetTypeInfo(), pageModel.PageType); } - // We want to test the 'empty' page and pagemodel has no bound properties, and no handler methods. + // We want to test the 'empty' page and PageModel has no bound properties, and no handler methods. [Fact] public void OnProvidersExecuting_EmptyPageModel() { diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionDescriptorChangeProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionDescriptorChangeProviderTest.cs index 21f9db7215..48c7cb3454 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionDescriptorChangeProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageActionDescriptorChangeProviderTest.cs @@ -30,8 +30,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal var templateEngine = new RazorTemplateEngine( RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem).Engine, fileSystem); - var options = Options.Create(new RazorPagesOptions()); - var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, accessor, options); + var razorPageOptions = Options.Create(new RazorPagesOptions()); + var razorViewEngineOptions = Options.Create(new RazorViewEngineOptions { AllowRecompilingViewsOnFileChange = true }); + var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, accessor, razorPageOptions, razorViewEngineOptions); // Act var changeToken = changeProvider.GetChangeToken(); @@ -57,8 +58,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal fileSystem); var options = Options.Create(new RazorPagesOptions()); options.Value.RootDirectory = rootDirectory; + var razorViewEngineOptions = Options.Create(new RazorViewEngineOptions { AllowRecompilingViewsOnFileChange = true }); - var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, accessor, options); + var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, accessor, options, razorViewEngineOptions); // Act var changeToken = changeProvider.GetChangeToken(); @@ -81,7 +83,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem).Engine, fileSystem); var options = Options.Create(new RazorPagesOptions { AllowAreas = true }); - var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, accessor, options); + var razorViewEngineOptions = Options.Create(new RazorViewEngineOptions { AllowRecompilingViewsOnFileChange = true }); + var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, accessor, options, razorViewEngineOptions); // Act var changeToken = changeProvider.GetChangeToken(); @@ -104,8 +107,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal templateEngine.Options.ImportsFileName = "_ViewImports.cshtml"; var options = Options.Create(new RazorPagesOptions()); options.Value.RootDirectory = "/dir1/dir2"; + var razorViewEngineOptions = Options.Create(new RazorViewEngineOptions { AllowRecompilingViewsOnFileChange = true }); - var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, accessor, options); + var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, accessor, options, razorViewEngineOptions); // Act & Assert var compositeChangeToken = Assert.IsType(changeProvider.GetChangeToken()); @@ -131,7 +135,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal options.Value.RootDirectory = "/dir1/dir2"; options.Value.AllowAreas = true; - var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, accessor, options); + var razorViewEngineOptions = Options.Create(new RazorViewEngineOptions { AllowRecompilingViewsOnFileChange = true }); + var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, accessor, options, razorViewEngineOptions); // Act & Assert var compositeChangeToken = Assert.IsType(changeProvider.GetChangeToken()); @@ -155,8 +160,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal fileSystem); templateEngine.Options.ImportsFileName = "_ViewImports.cshtml"; var options = Options.Create(new RazorPagesOptions { AllowAreas = false }); + var razorViewEngineOptions = Options.Create(new RazorViewEngineOptions { AllowRecompilingViewsOnFileChange = true }); - var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, accessor, options); + var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, accessor, options, razorViewEngineOptions); // Act & Assert var compositeChangeToken = Assert.IsType(changeProvider.GetChangeToken()); @@ -164,5 +170,27 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal changeToken => Assert.Same(fileProvider.GetChangeToken("/_ViewImports.cshtml"), changeToken), changeToken => Assert.Same(fileProvider.GetChangeToken("/Pages/**/*.cshtml"), changeToken)); } + + [Fact] + public void GetChangeToken_DoesNotWatch_WhenOptionIsReset() + { + // Arrange + var fileProvider = new Mock(MockBehavior.Strict); + var accessor = Mock.Of(a => a.FileProvider == fileProvider.Object); + + var fileSystem = new FileProviderRazorProjectFileSystem(accessor, _hostingEnvironment); + var templateEngine = new RazorTemplateEngine( + RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem).Engine, + fileSystem); + templateEngine.Options.ImportsFileName = "_ViewImports.cshtml"; + var options = Options.Create(new RazorPagesOptions()); + var razorViewEngineOptions = Options.Create(new RazorViewEngineOptions()); + + var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, accessor, options, razorViewEngineOptions); + + // Act & Assert + var compositeChangeToken = Assert.IsType(changeProvider.GetChangeToken()); + fileProvider.Verify(f => f.Watch(It.IsAny()), Times.Never()); + } } } diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageHandlerResultFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageHandlerResultFilterTest.cs index 46b7996080..bbe92dd6da 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageHandlerResultFilterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/PageHandlerResultFilterTest.cs @@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal } [Fact] - public async Task OnResultExecutionAsyn_ExecutesSyncFilters() + public async Task OnResultExecutionAsync_ExecutesSyncFilters() { // Arrange var pageContext = new PageContext(new ActionContext( diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorPagesRazorViewEngineOptionsSetupTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorPagesRazorViewEngineOptionsSetupTest.cs index e1571e451f..b0690ea559 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorPagesRazorViewEngineOptionsSetupTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorPagesRazorViewEngineOptionsSetupTest.cs @@ -2,9 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Razor; -using Microsoft.AspNetCore.Mvc.Razor.Internal; using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure; +using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Moq; using Xunit; @@ -186,7 +187,10 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal private static RazorViewEngineOptions GetViewEngineOptions() { - var defaultSetup = new RazorViewEngineOptionsSetup(Mock.Of()); + var defaultSetup = new RazorViewEngineOptionsSetup( + Mock.Of(), + NullLoggerFactory.Instance, + Options.Create(new MvcCompatibilityOptions())); var options = new RazorViewEngineOptions(); defaultSetup.Configure(options); diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageModelTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageModelTest.cs index 3decf16891..bfb8d6991c 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageModelTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageModelTest.cs @@ -1021,10 +1021,10 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages // Arrange var pageModel = new TestPageModel(); var pageName = "/Page-Name"; - var routeVaues = new { key = "value" }; + var routeValues = new { key = "value" }; // Act - var result = pageModel.RedirectToPage(pageName, routeVaues); + var result = pageModel.RedirectToPage(pageName, routeValues); // Assert Assert.IsType(result); diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageTest.cs index 2e4e50cf91..3a0e7ad2b1 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/PageTest.cs @@ -1096,10 +1096,10 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages // Arrange var page = new TestPage(); var pageName = "/Page-Name"; - var routeVaues = new { key = "value" }; + var routeValues = new { key = "value" }; // Act - var result = page.RedirectToPage(pageName, routeVaues); + var result = page.RedirectToPage(pageName, routeValues); // Assert Assert.IsType(result); diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ImageTagHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ImageTagHelperTest.cs index f913e6a59b..b3787dccec 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ImageTagHelperTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ImageTagHelperTest.cs @@ -146,10 +146,10 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers for (var i = 0; i < expectedOutput.Attributes.Count; i++) { - var expectedAtribute = expectedOutput.Attributes[i]; + var expectedAttribute = expectedOutput.Attributes[i]; var actualAttribute = output.Attributes[i]; - Assert.Equal(expectedAtribute.Name, actualAttribute.Name); - Assert.Equal(expectedAtribute.Value.ToString(), actualAttribute.Value.ToString()); + Assert.Equal(expectedAttribute.Name, actualAttribute.Name); + Assert.Equal(expectedAttribute.Value.ToString(), actualAttribute.Value.ToString()); } } diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/AttributeMatcherTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/AttributeMatcherTest.cs index a4aff7f9ab..2fc93f6c91 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/AttributeMatcherTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/AttributeMatcherTest.cs @@ -65,7 +65,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal } [Fact] - public void DetermineMode_SetsModeWithHigestValue() + public void DetermineMode_SetsModeWithHighestValue() { // Arrange var modeInfos = new[] diff --git a/test/Microsoft.AspNetCore.Mvc.Test/IntegrationTest/CompatibilitySwitchIntegrationTest.cs b/test/Microsoft.AspNetCore.Mvc.Test/IntegrationTest/CompatibilitySwitchIntegrationTest.cs index 2413eb34bf..2281f4d602 100644 --- a/test/Microsoft.AspNetCore.Mvc.Test/IntegrationTest/CompatibilitySwitchIntegrationTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Test/IntegrationTest/CompatibilitySwitchIntegrationTest.cs @@ -1,11 +1,14 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.ObjectPool; using Microsoft.Extensions.Options; +using Moq; using Xunit; namespace Microsoft.AspNetCore.Mvc.IntegrationTest @@ -32,6 +35,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest var jsonOptions = services.GetRequiredService>().Value; var razorPagesOptions = services.GetRequiredService>().Value; var apiBehaviorOptions = services.GetRequiredService>().Value; + var razorViewEngineOptions = services.GetRequiredService>().Value; // Assert Assert.False(mvcOptions.AllowCombiningAuthorizeFilters); @@ -44,6 +48,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest Assert.Null(mvcOptions.MaxValidationDepth); Assert.True(apiBehaviorOptions.SuppressUseValidationProblemDetailsForInvalidModelStateResponses); Assert.True(apiBehaviorOptions.SuppressMapClientErrors); + Assert.True(razorViewEngineOptions.AllowRecompilingViewsOnFileChange); } [Fact] @@ -61,6 +66,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest var jsonOptions = services.GetRequiredService>().Value; var razorPagesOptions = services.GetRequiredService>().Value; var apiBehaviorOptions = services.GetRequiredService>().Value; + var razorViewEngineOptions = services.GetRequiredService>().Value; // Assert Assert.True(mvcOptions.AllowCombiningAuthorizeFilters); @@ -73,6 +79,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest Assert.Null(mvcOptions.MaxValidationDepth); Assert.True(apiBehaviorOptions.SuppressUseValidationProblemDetailsForInvalidModelStateResponses); Assert.True(apiBehaviorOptions.SuppressMapClientErrors); + Assert.True(razorViewEngineOptions.AllowRecompilingViewsOnFileChange); } [Fact] @@ -90,6 +97,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest var jsonOptions = services.GetRequiredService>().Value; var razorPagesOptions = services.GetRequiredService>().Value; var apiBehaviorOptions = services.GetRequiredService>().Value; + var razorViewEngineOptions = services.GetRequiredService>().Value; // Assert Assert.True(mvcOptions.AllowCombiningAuthorizeFilters); @@ -102,6 +110,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest Assert.Equal(32, mvcOptions.MaxValidationDepth); Assert.False(apiBehaviorOptions.SuppressUseValidationProblemDetailsForInvalidModelStateResponses); Assert.False(apiBehaviorOptions.SuppressMapClientErrors); + Assert.False(razorViewEngineOptions.AllowRecompilingViewsOnFileChange); } [Fact] @@ -119,6 +128,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest var jsonOptions = services.GetRequiredService>().Value; var razorPagesOptions = services.GetRequiredService>().Value; var apiBehaviorOptions = services.GetRequiredService>().Value; + var razorViewEngineOptions = services.GetRequiredService>().Value; // Assert Assert.True(mvcOptions.AllowCombiningAuthorizeFilters); @@ -131,11 +141,13 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest Assert.Equal(32, mvcOptions.MaxValidationDepth); Assert.False(apiBehaviorOptions.SuppressUseValidationProblemDetailsForInvalidModelStateResponses); Assert.False(apiBehaviorOptions.SuppressMapClientErrors); + Assert.False(razorViewEngineOptions.AllowRecompilingViewsOnFileChange); } // This just does the minimum needed to be able to resolve these options. private static void AddHostingServices(IServiceCollection serviceCollection) { + serviceCollection.AddSingleton(Mock.Of()); serviceCollection.AddLogging(); serviceCollection.AddSingleton(); } diff --git a/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs index f2700f2a97..b4c06b2613 100644 --- a/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs @@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Mvc services.AddSingleton(GetHostingEnvironment()); // Register a mock implementation of each service, AddMvcServices should add another implementation. - foreach (var serviceType in MutliRegistrationServiceTypes) + foreach (var serviceType in MultiRegistrationServiceTypes) { var mockType = typeof(Mock<>).MakeGenericType(serviceType.Key); services.Add(ServiceDescriptor.Transient(serviceType.Key, mockType)); @@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Mvc services.AddMvc(); // Assert - foreach (var serviceType in MutliRegistrationServiceTypes) + foreach (var serviceType in MultiRegistrationServiceTypes) { AssertServiceCountEquals(services, serviceType.Key, serviceType.Value.Length + 1); @@ -163,7 +163,7 @@ namespace Microsoft.AspNetCore.Mvc } [Fact] - public void AddMvcTwice_DoesNotAddDuplicateFramewokrParts() + public void AddMvcTwice_DoesNotAddDuplicateFrameworkParts() { // Arrange var mvcRazorAssembly = typeof(UrlResolutionTagHelper).GetTypeInfo().Assembly; @@ -323,7 +323,7 @@ namespace Microsoft.AspNetCore.Mvc services.AddSingleton(GetHostingEnvironment()); services.AddMvc(); - var multiRegistrationServiceTypes = MutliRegistrationServiceTypes; + var multiRegistrationServiceTypes = MultiRegistrationServiceTypes; return services .Where(sd => !multiRegistrationServiceTypes.Keys.Contains(sd.ServiceType)) .Where(sd => sd.ServiceType.GetTypeInfo().Assembly.FullName.Contains("Mvc")) @@ -331,7 +331,7 @@ namespace Microsoft.AspNetCore.Mvc } } - private Dictionary MutliRegistrationServiceTypes + private Dictionary MultiRegistrationServiceTypes { get { diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ControllerTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ControllerTest.cs index 6abab5d7a5..07567c78b9 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ControllerTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ControllerTest.cs @@ -439,7 +439,7 @@ namespace Microsoft.AspNetCore.Mvc.Test var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary()); var tempData = new TempDataDictionary(httpContext, Mock.Of()); - var valiatorProviders = new[] + var validatorProviders = new[] { new DataAnnotationsModelValidatorProvider( new ValidationAttributeAdapterProvider(), @@ -458,7 +458,7 @@ namespace Microsoft.AspNetCore.Mvc.Test { ControllerContext = controllerContext, MetadataProvider = metadataProvider, - ObjectValidator = new DefaultObjectValidator(metadataProvider, valiatorProviders, new MvcOptions()), + ObjectValidator = new DefaultObjectValidator(metadataProvider, validatorProviders, new MvcOptions()), TempData = tempData, ViewData = viewData, }; diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/ExpressionHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/ExpressionHelperTest.cs index eee3b4fb66..f316eea6be 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/ExpressionHelperTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/ExpressionHelperTest.cs @@ -393,7 +393,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal [Theory] [MemberData(nameof(IndexerExpressions))] [MemberData(nameof(UnsupportedExpressions))] - public void GetExpressionText_DoesNotCacheIndexerOrUnspportedExpression(LambdaExpression expression) + public void GetExpressionText_DoesNotCacheIndexerOrUnsupportedExpression(LambdaExpression expression) { // Act - 1 var text1 = ExpressionHelper.GetExpressionText(expression, _expressionTextCache); diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/ExpressionMetadataProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/ExpressionMetadataProviderTest.cs index 44d421c376..c47802cfd0 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/ExpressionMetadataProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/ExpressionMetadataProviderTest.cs @@ -93,7 +93,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal } [Fact] - public void FromLambaExpression_SetsContainerAsExpected() + public void FromLambdaExpression_SetsContainerAsExpected() { // Arrange var myModel = new TestModel { SelectedCategory = new Category() }; diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/MemberExpressionCacheKeyComparerTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/MemberExpressionCacheKeyComparerTest.cs index 164b899151..eca38d7dc2 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/MemberExpressionCacheKeyComparerTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/MemberExpressionCacheKeyComparerTest.cs @@ -186,12 +186,12 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures Assert.NotEqual(cachedKeyHashCode1, hashCode2); } - private static MemberExpressionCacheKey GetKey(Expression> expresssion) - => GetKey(expresssion); + private static MemberExpressionCacheKey GetKey(Expression> expression) + => GetKey(expression); - private static MemberExpressionCacheKey GetKey(Expression> expresssion) + private static MemberExpressionCacheKey GetKey(Expression> expression) { - var memberExpression = Assert.IsAssignableFrom(expresssion.Body); + var memberExpression = Assert.IsAssignableFrom(expression.Body); return new MemberExpressionCacheKey(typeof(TModel), memberExpression); } diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/MemberExpressionCacheKeyTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/MemberExpressionCacheKeyTest.cs index 5de4c308c3..eb4cebb948 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/MemberExpressionCacheKeyTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/MemberExpressionCacheKeyTest.cs @@ -70,9 +70,9 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures Assert.Equal(expected, actual); } - private static MemberExpressionCacheKey GetKey(Expression> expresssion) + private static MemberExpressionCacheKey GetKey(Expression> expression) { - var memberExpression = Assert.IsAssignableFrom(expresssion.Body); + var memberExpression = Assert.IsAssignableFrom(expression.Body); return new MemberExpressionCacheKey(typeof(TestModel), memberExpression); } diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperFormExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperFormExtensionsTest.cs index 13beb13337..0624f2aa95 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperFormExtensionsTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperFormExtensionsTest.cs @@ -708,7 +708,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering [Theory] [MemberData(nameof(ActionNameControllerNameRouteValuesAndMethodDataSet))] - public void BeginFormWithActionNameContollerNameRouteValuesAndMethodParameters_CallsHtmlGeneratorWithExpectedValues( + public void BeginFormWithActionNameControllerNameRouteValuesAndMethodParameters_CallsHtmlGeneratorWithExpectedValues( string actionName, string controllerName, object routeValues, @@ -754,7 +754,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering [Theory] [MemberData(nameof(ActionNameControllerNameMethodAndHtmlAttributesDataSet))] - public void BeginFormWithActionNameContollerNameMethodAndHtmlAttributesParameters_CallsHtmlGeneratorWithExpectedValues( + public void BeginFormWithActionNameControllerNameMethodAndHtmlAttributesParameters_CallsHtmlGeneratorWithExpectedValues( string actionName, string controllerName, FormMethod method, @@ -800,7 +800,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering [Theory] [MemberData(nameof(ActionNameControllerNameMethodAndHtmlAttributesDataSet))] - public void BeginFormWithActionNameContollerNameMethodAndHtmlAttributesParameters_WithAntiforgery_CallsHtmlGeneratorWithExpectedValues( + public void BeginFormWithActionNameControllerNameMethodAndHtmlAttributesParameters_WithAntiforgery_CallsHtmlGeneratorWithExpectedValues( string actionName, string controllerName, FormMethod method, @@ -848,7 +848,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering [Theory] [MemberData(nameof(ActionNameControllerNameMethodAndHtmlAttributesDataSet))] - public void BeginFormWithActionNameContollerNameMethodAndHtmlAttributesParameters_SuppressAntiforgery_CallsHtmlGeneratorWithExpectedValues( + public void BeginFormWithActionNameControllerNameMethodAndHtmlAttributesParameters_SuppressAntiforgery_CallsHtmlGeneratorWithExpectedValues( string actionName, string controllerName, FormMethod method, diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperSelectTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperSelectTest.cs index 56ddb2c7a2..41050775f2 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperSelectTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/HtmlHelperSelectTest.cs @@ -1037,7 +1037,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering } [Fact] - public void ListBoxFor_WithUnreleatedExpression_GeneratesExpectedValue() + public void ListBoxFor_WithUnrelatedExpression_GeneratesExpectedValue() { // Arrange var unrelated = new[] { "2" }; diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewDataDictionaryOfTModelTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewDataDictionaryOfTModelTest.cs index 31f0d036d6..2a2a355257 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewDataDictionaryOfTModelTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewDataDictionaryOfTModelTest.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures public class ViewDataDictionaryOfTModelTest { [Fact] - public void Constructor_InitalizesMembers() + public void Constructor_InitializesMembers() { // Arrange var metadataProvider = new EmptyModelMetadataProvider(); @@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures } [Fact] - public void CopyConstructors_InitalizeModelAndModelMetadataBasedOnSource() + public void CopyConstructors_InitializeModelAndModelMetadataBasedOnSource() { // Arrange var metadataProvider = new EmptyModelMetadataProvider(); @@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures } [Fact] - public void CopyConstructors_InitalizeModelAndModelMetadataBasedOnSource_NullModel() + public void CopyConstructors_InitializeModelAndModelMetadataBasedOnSource_NullModel() { // Arrange var metadataProvider = new EmptyModelMetadataProvider(); @@ -112,7 +112,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures } [Fact] - public void CopyConstructor_InitalizesModelAndModelMetadataBasedOnSource_ModelOfSubclass() + public void CopyConstructor_InitializesModelAndModelMetadataBasedOnSource_ModelOfSubclass() { // Arrange var metadataProvider = new EmptyModelMetadataProvider(); diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewDataDictionaryTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewDataDictionaryTest.cs index cfcb4bf426..bd2b2e47ba 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewDataDictionaryTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewDataDictionaryTest.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures public class ViewDataDictionaryTest { [Fact] - public void ConstructorWithOneParameterInitalizesMembers() + public void ConstructorWithOneParameterInitializesMembers() { // Arrange var metadataProvider = new EmptyModelMetadataProvider(); @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures } [Fact] - public void ConstructorInitalizesMembers() + public void ConstructorInitializesMembers() { // Arrange var metadataProvider = new EmptyModelMetadataProvider(); @@ -186,7 +186,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures } [Fact] - public void CopyConstructorInitalizesModelAndModelMetadataBasedOnSource() + public void CopyConstructorInitializesModelAndModelMetadataBasedOnSource() { // Arrange var metadataProvider = new EmptyModelMetadataProvider(); diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs index f55d3a91fd..7fc8949fa3 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs @@ -140,11 +140,11 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures // Arrange var tempDataNull = false; var viewDataNull = false; - var deligateHit = false; + var delegateHit = false; var view = CreateView(async (v) => { - deligateHit = true; + delegateHit = true; tempDataNull = v.TempData == null; viewDataNull = v.ViewData == null; @@ -174,7 +174,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures // Assert Assert.Equal(200, context.Response.StatusCode); - Assert.True(deligateHit); + Assert.True(delegateHit); Assert.False(viewDataNull); Assert.False(tempDataNull); } diff --git a/test/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest/TestUtils/TestDataSetAttribute.cs b/test/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest/TestUtils/TestDataSetAttribute.cs index 33a5897181..0f891bb34a 100644 --- a/test/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest/TestUtils/TestDataSetAttribute.cs +++ b/test/Microsoft.AspNetCore.Mvc.WebApiCompatShimTest/TestUtils/TestDataSetAttribute.cs @@ -185,14 +185,14 @@ namespace Microsoft.TestCommon private static IEnumerable GetDataSetFromTestDataCollection(IEnumerable testDataCollection, TestDataVariations variations) { - foreach (TestData testdataInstance in testDataCollection) + foreach (TestData testDataInstance in testDataCollection) { - foreach (TestDataVariations variation in testdataInstance.GetSupportedTestDataVariations()) + foreach (TestDataVariations variation in testDataInstance.GetSupportedTestDataVariations()) { if ((variation & variations) == variation) { - Type variationType = testdataInstance.GetAsTypeOrNull(variation); - object testData = testdataInstance.GetAsTestDataOrNull(variation); + Type variationType = testDataInstance.GetAsTypeOrNull(variation); + object testData = testDataInstance.GetAsTestDataOrNull(variation); if (AsSingleInstances(variation)) { foreach (object obj in (IEnumerable)testData) diff --git a/test/Mvc.Api.Analyzers.Test/ApiConventionAnalyzerIntegrationTest.cs b/test/Mvc.Api.Analyzers.Test/ApiConventionAnalyzerIntegrationTest.cs index 13942b0046..f611c8d421 100644 --- a/test/Mvc.Api.Analyzers.Test/ApiConventionAnalyzerIntegrationTest.cs +++ b/test/Mvc.Api.Analyzers.Test/ApiConventionAnalyzerIntegrationTest.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers { public class ApiConventionAnalyzerIntegrationTest { - private MvcDiagnosticAnalyzerRunner Executor { get; } = new ApiCoventionWith1006DiagnosticEnabledRunner(); + private MvcDiagnosticAnalyzerRunner Executor { get; } = new ApiConventionWith1006DiagnosticEnabledRunner(); [Fact] public Task NoDiagnosticsAreReturned_ForNonApiController() @@ -129,9 +129,9 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers Assert.Equal(string.Format(descriptor.MessageFormat.ToString(), args), diagnostic.GetMessage()); }); } - private class ApiCoventionWith1006DiagnosticEnabledRunner : MvcDiagnosticAnalyzerRunner + private class ApiConventionWith1006DiagnosticEnabledRunner : MvcDiagnosticAnalyzerRunner { - public ApiCoventionWith1006DiagnosticEnabledRunner() : base(new ApiConventionAnalyzer()) + public ApiConventionWith1006DiagnosticEnabledRunner() : base(new ApiConventionAnalyzer()) { } diff --git a/test/Mvc.Api.Analyzers.Test/SymbolApiConventionMatcherTest.cs b/test/Mvc.Api.Analyzers.Test/SymbolApiConventionMatcherTest.cs index 041d148624..864a6b3791 100644 --- a/test/Mvc.Api.Analyzers.Test/SymbolApiConventionMatcherTest.cs +++ b/test/Mvc.Api.Analyzers.Test/SymbolApiConventionMatcherTest.cs @@ -159,7 +159,7 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers } [Fact] - public void IsNameMatch_WithPrefix_ReturnsFalse_IfNameIsNotProperPrfix() + public void IsNameMatch_WithPrefix_ReturnsFalse_IfNameIsNotProperPrefix() { // Arrange var name = "Postman"; @@ -303,7 +303,7 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers } [Fact] - public async Task IsTypeMatch_WithAssinableFrom_ReturnsTrueForDerived() + public async Task IsTypeMatch_WithAssignableFrom_ReturnsTrueForDerived() { // Arrange var compilation = await GetCompilationAsync(); @@ -320,7 +320,7 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers } [Fact] - public async Task IsTypeMatch_WithAssinableFrom_ReturnsFalseForBaseTypes() + public async Task IsTypeMatch_WithAssignableFrom_ReturnsFalseForBaseTypes() { // Arrange var compilation = await GetCompilationAsync(); @@ -336,7 +336,7 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers } [Fact] - public async Task IsTypeMatch_WithAssinableFrom_ReturnsFalseForUnrelated() + public async Task IsTypeMatch_WithAssignableFrom_ReturnsFalseForUnrelated() { // Arrange var compilation = await GetCompilationAsync(); @@ -396,7 +396,7 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers } [Fact] - public Task IsMatch_ReturnsTrue_IfMethodNameAndParametersMatchs() + public Task IsMatch_ReturnsTrue_IfMethodNameAndParametersMatches() { // Arrange var methodName = nameof(TestController.Get); diff --git a/test/Mvc.Api.Analyzers.Test/SymbolApiResponseMetadataProviderTest.cs b/test/Mvc.Api.Analyzers.Test/SymbolApiResponseMetadataProviderTest.cs index e6ccc12470..483901ffa1 100644 --- a/test/Mvc.Api.Analyzers.Test/SymbolApiResponseMetadataProviderTest.cs +++ b/test/Mvc.Api.Analyzers.Test/SymbolApiResponseMetadataProviderTest.cs @@ -258,7 +258,7 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers [Fact] public Task GetResponseMetadata_IgnoresAttributesWithIncorrectStatusCodeType() { - return GetResponseMetadata_WorksForInvalidOrUnsupportedAttribues( + return GetResponseMetadata_WorksForInvalidOrUnsupportedAttributes( nameof(GetResponseMetadata_ControllerActionWithAttributes), nameof(GetResponseMetadata_ControllerActionWithAttributes.ActionWithProducesResponseTypeWithIncorrectStatusCodeType)); } @@ -266,12 +266,12 @@ namespace Microsoft.AspNetCore.Mvc.Api.Analyzers [Fact] public Task GetResponseMetadata_IgnoresDerivedAttributesWithoutPropertyOnConstructorArguments() { - return GetResponseMetadata_WorksForInvalidOrUnsupportedAttribues( + return GetResponseMetadata_WorksForInvalidOrUnsupportedAttributes( nameof(GetResponseMetadata_ControllerActionWithAttributes), nameof(GetResponseMetadata_ControllerActionWithAttributes.ActionWithCustomProducesResponseTypeAttributeWithoutArguments)); } - private async Task GetResponseMetadata_WorksForInvalidOrUnsupportedAttribues(string typeName, string methodName) + private async Task GetResponseMetadata_WorksForInvalidOrUnsupportedAttributes(string typeName, string methodName) { // Arrange var compilation = await GetResponseMetadataCompilation(); diff --git a/test/WebSites/RazorPagesWebSite/NonWatchingPhysicalFileProvider.cs b/test/WebSites/RazorPagesWebSite/NonWatchingPhysicalFileProvider.cs new file mode 100644 index 0000000000..c93dba01e3 --- /dev/null +++ b/test/WebSites/RazorPagesWebSite/NonWatchingPhysicalFileProvider.cs @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation. 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.Extensions.FileProviders; +using Microsoft.Extensions.Primitives; + +namespace RazorPagesWebSite +{ + public class NonWatchingPhysicalFileProvider : PhysicalFileProvider, IFileProvider + { + public NonWatchingPhysicalFileProvider(string root) : base(root) + { + } + + IChangeToken IFileProvider.Watch(string filter) => throw new ArgumentException("This method should not be called."); + } +} diff --git a/test/WebSites/RazorPagesWebSite/StartupWithBasePath.cs b/test/WebSites/RazorPagesWebSite/StartupWithBasePath.cs index 0ded866ccf..93d36cea31 100644 --- a/test/WebSites/RazorPagesWebSite/StartupWithBasePath.cs +++ b/test/WebSites/RazorPagesWebSite/StartupWithBasePath.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using RazorPagesWebSite.Conventions; @@ -11,11 +12,18 @@ namespace RazorPagesWebSite { public class StartupWithBasePath { + private readonly IHostingEnvironment _hostingEnvironment; + + public StartupWithBasePath(IHostingEnvironment hostingEnvironment) + { + _hostingEnvironment = hostingEnvironment; + } + public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => options.LoginPath = "/Login"); - services.AddMvc() + var builder = services.AddMvc() .AddCookieTempDataProvider() .AddRazorPagesOptions(options => { @@ -27,6 +35,14 @@ namespace RazorPagesWebSite options.Conventions.Add(new CustomModelTypeConvention()); }) .SetCompatibilityVersion(CompatibilityVersion.Latest); + + // Ensure we don't have code paths that call IFileProvider.Watch in the default code path. + // Comment this code block if you happen to run this site in Development. + builder.AddRazorOptions(options => + { + options.FileProviders.Clear(); + options.FileProviders.Add(new NonWatchingPhysicalFileProvider(_hostingEnvironment.ContentRootPath)); + }); } public void Configure(IApplicationBuilder app) diff --git a/test/WebSites/RazorWebSite/Controllers/UpdateableFileProviderController.cs b/test/WebSites/RazorWebSite/Controllers/UpdateableFileProviderController.cs index a504b11cb6..ed5a12a6f2 100644 --- a/test/WebSites/RazorWebSite/Controllers/UpdateableFileProviderController.cs +++ b/test/WebSites/RazorWebSite/Controllers/UpdateableFileProviderController.cs @@ -10,9 +10,16 @@ namespace RazorWebSite public IActionResult Index() => View("/Views/UpdateableIndex/Index.cshtml"); [HttpPost] - public IActionResult Update([FromServices] UpdateableFileProvider fileProvider) + public IActionResult Update([FromServices] UpdateableFileProvider fileProvider, string path, string content) { - fileProvider.UpdateContent("/Views/UpdateableShared/_Partial.cshtml", "New content"); + fileProvider.UpdateContent(path, content); + return Ok(); + } + + [HttpPost] + public IActionResult UpdateRazorPages([FromServices] UpdateableFileProvider fileProvider) + { + fileProvider.CancelRazorPages(); return Ok(); } } diff --git a/test/WebSites/RazorWebSite/Services/UpdateableFileProvider.cs b/test/WebSites/RazorWebSite/Services/UpdateableFileProvider.cs index 0e3ef8aaac..5613ffda9a 100644 --- a/test/WebSites/RazorWebSite/Services/UpdateableFileProvider.cs +++ b/test/WebSites/RazorWebSite/Services/UpdateableFileProvider.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; @@ -13,8 +14,14 @@ namespace RazorWebSite { public class UpdateableFileProvider : IFileProvider { + public CancellationTokenSource _pagesTokenSource = new CancellationTokenSource(); + private readonly Dictionary _content = new Dictionary() { + { + "/Views/UpdateableIndex/_ViewImports.cshtml", + new TestFileInfo(string.Empty) + }, { "/Views/UpdateableIndex/Index.cshtml", new TestFileInfo(@"@Html.Partial(""../UpdateableShared/_Partial.cshtml"")") @@ -23,9 +30,21 @@ namespace RazorWebSite "/Views/UpdateableShared/_Partial.cshtml", new TestFileInfo("Original content") }, + { + "/Pages/UpdateablePage.cshtml", + new TestFileInfo("@page" + Environment.NewLine + "Original content") + }, }; - public IDirectoryContents GetDirectoryContents(string subpath) => new NotFoundDirectoryContents(); + public IDirectoryContents GetDirectoryContents(string subpath) + { + if (subpath == "/Pages") + { + return new PagesDirectoryContents(); + } + + return new NotFoundDirectoryContents(); + } public void UpdateContent(string subpath, string content) { @@ -34,10 +53,16 @@ namespace RazorWebSite _content[subpath] = new TestFileInfo(content); } + public void CancelRazorPages() + { + var oldToken = _pagesTokenSource; + _pagesTokenSource = new CancellationTokenSource(); + oldToken.Cancel(); + } + public IFileInfo GetFileInfo(string subpath) { - TestFileInfo fileInfo; - if (!_content.TryGetValue(subpath, out fileInfo)) + if (!_content.TryGetValue(subpath, out var fileInfo)) { fileInfo = new TestFileInfo(null); } @@ -47,8 +72,12 @@ namespace RazorWebSite public IChangeToken Watch(string filter) { - TestFileInfo fileInfo; - if (_content.TryGetValue(filter, out fileInfo)) + if (filter == "/Pages/**/*.cshtml") + { + return new CancellationChangeToken(_pagesTokenSource.Token); + } + + if (_content.TryGetValue(filter, out var fileInfo)) { return fileInfo.ChangeToken; } @@ -71,7 +100,7 @@ namespace RazorWebSite public bool IsDirectory => false; public DateTimeOffset LastModified => DateTimeOffset.MinValue; public long Length => -1; - public string Name => null; + public string Name { get; set; } public string PhysicalPath => null; public CancellationTokenSource TokenSource { get; } = new CancellationTokenSource(); public CancellationChangeToken ChangeToken { get; } @@ -81,5 +110,23 @@ namespace RazorWebSite return new MemoryStream(Encoding.UTF8.GetBytes(_content)); } } + + private class PagesDirectoryContents : IDirectoryContents + { + public bool Exists => true; + + public IEnumerator GetEnumerator() + { + var file = new TestFileInfo("@page" + Environment.NewLine + "Original content") + { + Name = "UpdateablePage.cshtml" + }; + + var files = new List { file }; + return files.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } } }