Merge branch 'merge/release/2.2-to-master' of https://github.com/dotnet-maestro-bot/Mvc into dotnet-maestro-bot-merge/release/2.2-to-master
This commit is contained in:
commit
f7d9271d71
17
Mvc.sln
17
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}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
@page
|
||||
@model Pages.PageA
|
||||
@using static System.Convert
|
||||
|
||||
@section Subcategories {
|
||||
<partial name="_Subcategories" />
|
||||
}
|
||||
|
||||
@section Tabs {
|
||||
<span class="dialog-tab@(Model.Condition ? " selected" : "")"><span class="link" data-url="/Category/PageA">Sub cat A</span></span>
|
||||
<span class="dialog-tab"><span class="link" data-url="/Category/PageB/@Model.Value1/@Model.Value2">Sub cat B</span></span>
|
||||
<span class="dialog-tab"><span class="link" data-url="/Category/PageC/@((int)Model.Value3)">Sub cat C</span></span>
|
||||
<span class="dialog-tab@(!Model.Condition ? " selected" : "")"><span class="link" data-url="/Category/PageD/@((int)Model.Value3)">Sub cat D</span></span>
|
||||
}
|
||||
|
||||
@switch (Model.Value)
|
||||
{
|
||||
case 0:
|
||||
<h1>@Model.Name Type A</h1>
|
||||
break;
|
||||
case 1:
|
||||
<h1>@Model.Name Type B</h1>
|
||||
break;
|
||||
case 2:
|
||||
<h1>@Model.Name Type C</h1>
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
<h3 style="clear:both;">Something Something</h3>
|
||||
<div>
|
||||
<table class="generic small oddeven middle center">
|
||||
<tr>
|
||||
<th style="width: 24px;"></th>
|
||||
<th>Something</th>
|
||||
<th style="width: 270px;">Something Something</th>
|
||||
@if (Model.Value3 != 0)
|
||||
{
|
||||
<th style="width: 70px;" class="dull right">Something</th>
|
||||
}
|
||||
<th style="width: 130px;"></th>
|
||||
</tr>
|
||||
@{
|
||||
foreach (var data in Model.Data1)
|
||||
{
|
||||
<tr>
|
||||
<td class="left">@data.Icon</td>
|
||||
<td class="left">@data.Name</td>
|
||||
<td style="text-align:center">@data.Html</td>
|
||||
@if (Model.Value3 != 0)
|
||||
{
|
||||
<td class="dull right">
|
||||
@(new TimeSpan(0, 0, (int)data.Seconds)) <br />
|
||||
(@data.PerHour.ToString("N2") p/h)
|
||||
</td>
|
||||
}
|
||||
<td>
|
||||
<form asp-page-handler="Make">
|
||||
<input type="hidden" name="Id" value="@((int)Model.Value3)" />
|
||||
<input type="hidden" name="ResType" value="@data.Id" />
|
||||
<input type="text" name="Quantity" style="width: 35px; font-size: 11px; text-align: left;" placeholder="@data.Max.ToString(System.Globalization.NumberFormatInfo.InvariantInfo)" />
|
||||
<a href="#" class="max">max</a>
|
||||
<button class="small">Make</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3 style="clear:both;">Something something something</h3>
|
||||
<div>
|
||||
@{
|
||||
if (Model.Data2.Count > 0)
|
||||
{
|
||||
<table class="oddeven" style="font-size: 11px;">
|
||||
<tr>
|
||||
<th style="width:20px"></th>
|
||||
<th class="left">SomethingA</th>
|
||||
<th style="width: 80px;">SomethingB</th>
|
||||
<th style="width: 60px">SomethingC</th>
|
||||
<th>SomethingD</th>
|
||||
<th style="width: 60px">SomethingE</th>
|
||||
<th style="width: 90px;">SomethingF</th>
|
||||
<th style="width: 56px;"></th>
|
||||
</tr>
|
||||
|
||||
@foreach (var data in Model.Data2)
|
||||
{
|
||||
var StartDate = data.StartDate;
|
||||
var CompleteDate = data.CompleteDate;
|
||||
|
||||
<tr>
|
||||
<td>@data.Icon</td>
|
||||
<td class="left">@data.Name</td>
|
||||
<td>@data.Value</td>
|
||||
<td class="center">@StartDate.ToString("dd MMM HH:mm:ss")</td>
|
||||
@{
|
||||
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);
|
||||
}
|
||||
<td>
|
||||
<div class="progBar">
|
||||
<div class="progProgress" data-start="@startDate" data-end="@endDate" style="width: @(percentage.ToString("N0"))%;"></div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="center">@CompleteDate.ToString("dd MMM HH:mm:ss")</td>
|
||||
<td>
|
||||
<span class="progTime" data-start="@startDate" data-end="@endDate">@(CompleteDate.Subtract(DateTime.UtcNow).ToString())</span>
|
||||
</td>
|
||||
<td>
|
||||
<form method="post" asp-page-handler="Cancel">
|
||||
<input type="hidden" name="id" value="@data.Id" />
|
||||
<button class="small">Cancel</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Something @Model.Name something something something something.</span>
|
||||
}
|
||||
|
||||
}
|
||||
</div>
|
||||
|
|
@ -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<DataA> Data1 { get; }
|
||||
public List<DataB> Data2 { get; }
|
||||
|
||||
public PageA(List<DataA> dataA, List<DataB> dataB, ILogger<PageA> logger) : base(logger)
|
||||
{
|
||||
Data1 = dataA;
|
||||
Data2 = dataB;
|
||||
}
|
||||
|
||||
public async Task OnGetAsync()
|
||||
{
|
||||
PageTitle = "PageA Title";
|
||||
PageIcon = "sicon dialogue_pagea";
|
||||
await Task.Delay(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
@model Pages.Page
|
||||
|
||||
<div class="dialog-subcat">
|
||||
<div data-url="/Category/PageA" title="PageA Title" class="sicon dialogue_pagea"></div>
|
||||
<div data-url="/Category/PageB" title="PageB Title" class="sicon dialogue_pageb"></div>
|
||||
<div data-url="/Category/PageC" title="PageC Title" class="sicon dialogue_pagec"></div>
|
||||
<div data-url="/Category/PageD" title="PageD Title" class="sicon dialogue_paged"></div>
|
||||
<div data-url="/Category/PageE" title="PageE Title" class="sicon dialogue_pagee"></div>
|
||||
<div data-url="/Category/PageF" title="PageF Title" class="sicon dialogue_pagef"></div>
|
||||
<div data-url="/Category/PageG" title="PageG Title" class="sicon dialogue_pageg"></div>
|
||||
</div>
|
||||
<div class="licon micon dialogue_category"></div>
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
@model Pages.Page
|
||||
|
||||
@RenderSection("Subcategories")
|
||||
<div class="dialog-title-icon @Model.PageIcon"></div>
|
||||
<div class="dialog-title">@Model.PageTitle</div>
|
||||
@{
|
||||
var hasTabs = IsSectionDefined("Tabs");
|
||||
}
|
||||
<div class="dialog-body@(hasTabs ? "-tabs" : "")">
|
||||
@if (hasTabs)
|
||||
{
|
||||
<div class="dialog-tabs">
|
||||
@RenderSection("Tabs", required: false)
|
||||
</div>
|
||||
}
|
||||
<div class="dialog-parch-bottom@(hasTabs ? " tabs" : "")">
|
||||
<div id="contentScroll" tabindex="20" class="dialog-parch-scroll@(hasTabs ? " tabs" : "")">
|
||||
<div class="dialog-parch-left">
|
||||
<div class="dialog-parch-right">
|
||||
<div id="contentWindow" class="dialog-parch@(hasTabs ? " tabs" : "")">
|
||||
@RenderBody()
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-parch-shadow@(hasTabs ? " tabs" : "")"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-close-icon icon_close"></div>
|
||||
<div class="dialog-bottom-left-edge"></div>
|
||||
<div class="dialog-bottom-edge"></div>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netcoreapp2.2</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- These references are used when running locally -->
|
||||
<ItemGroup Condition="'$(BenchmarksTargetFramework)' == ''">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="$(MicrosoftExtensionsConfigurationCommandLinePackageVersion)" />
|
||||
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc\Microsoft.AspNetCore.Mvc.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
These references are used when running on the Benchmarks Server.
|
||||
-->
|
||||
<ItemGroup Condition="'$(BenchmarksTargetFramework)' != ''">
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="$(MicrosoftNETCoreApp22PackageVersion)" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1 @@
|
|||
Url: /Category/PageA
|
||||
|
|
@ -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<List<DataA>>(_ => DataA);
|
||||
services.AddScoped<List<DataB>>(_ => DataB);
|
||||
services.AddMvc()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest);
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||
{
|
||||
app.UseMvc();
|
||||
}
|
||||
|
||||
private static List<DataA> DataA = GenerateDataA();
|
||||
|
||||
private static List<DataA> GenerateDataA()
|
||||
{
|
||||
var dataA = new List<DataA>();
|
||||
|
||||
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> DataB = GenerateDataB();
|
||||
|
||||
private static List<DataB> GenerateDataB()
|
||||
{
|
||||
var utc = DateTimeOffset.UtcNow;
|
||||
var dataB = new List<DataB>();
|
||||
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<Startup>();
|
||||
}
|
||||
}
|
||||
|
|
@ -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<ActionDescriptor> NaiveSelectCandiates(ActionDescriptor[] actions, RouteValueDictionary routeValues)
|
||||
private static IReadOnlyList<ActionDescriptor> NaiveSelectCandidates(ActionDescriptor[] actions, RouteValueDictionary routeValues)
|
||||
{
|
||||
var results = new List<ActionDescriptor>();
|
||||
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.");
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@
|
|||
<MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreRazorTagHelpersTestingSourcesPackageVersion>
|
||||
<MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion>
|
||||
<MicrosoftAspNetCoreResponseCachingPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreResponseCachingPackageVersion>
|
||||
<MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>
|
||||
<MicrosoftAspNetCoreRoutingPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreRoutingPackageVersion>
|
||||
<MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>3.0.0-a-alpha1-link-generator-master-16955</MicrosoftAspNetCoreRoutingAbstractionsPackageVersion>
|
||||
<MicrosoftAspNetCoreRoutingPackageVersion>3.0.0-a-alpha1-link-generator-master-16955</MicrosoftAspNetCoreRoutingPackageVersion>
|
||||
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
|
||||
<MicrosoftAspNetCoreServerKestrelPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreServerKestrelPackageVersion>
|
||||
<MicrosoftAspNetCoreSessionPackageVersion>3.0.0-alpha1-10400</MicrosoftAspNetCoreSessionPackageVersion>
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ namespace Microsoft.AspNetCore.Mvc.Abstractions
|
|||
/// </summary>
|
||||
public IList<IActionConstraintMetadata> ActionConstraints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the endpoint metadata for this action.
|
||||
/// </summary>
|
||||
public IList<object> EndpointMetadata { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -31,15 +31,11 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// <param name="actionContext">The <see cref="ActionContext"/> to copy.</param>
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -136,4 +132,4 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
get; set;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Intializes a new instance of <see cref="ActionResult{TValue}"/> using the specified <see cref="ActionResult"/>.
|
||||
/// Initializes a new instance of <see cref="ActionResult{TValue}"/> using the specified <see cref="ActionResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="result">The <see cref="ActionResult"/>.</param>
|
||||
public ActionResult(ActionResult result)
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationParts
|
|||
/// Gets the list of <see cref="ApplicationPart"/> instances.
|
||||
/// <para>
|
||||
/// Instances in this collection are stored in precedence order. An <see cref="ApplicationPart"/> that appears
|
||||
/// earlier in the list has a higher precendence.
|
||||
/// earlier in the list has a higher precedence.
|
||||
/// An <see cref="IApplicationFeatureProvider"/> may choose to use this an interface as a way to resolve conflicts when
|
||||
/// multiple <see cref="ApplicationPart"/> instances resolve equivalent feature values.
|
||||
/// </para>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default, this maps to <see cref="ProblemDetails.Title"/> and should not change
|
||||
/// between multiple occurences of the same error.
|
||||
/// between multiple occurrences of the same error.
|
||||
/// </remarks>
|
||||
public string Title { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
namespace Microsoft.AspNetCore.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the version compatibility of runtime behaviors configured by <see cref="MvcOptions"/>.
|
||||
/// Specifies the version compatibility of runtime behaviors configured by <see cref="MvcOptions"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The best way to set a compatibility version is by using
|
||||
/// The best way to set a compatibility version is by using
|
||||
/// <see cref="MvcCoreMvcBuilderExtensions.SetCompatibilityVersion"/> or
|
||||
/// <see cref="MvcCoreMvcCoreBuilderExtensions.SetCompatibilityVersion"/> in your application's
|
||||
/// <c>ConfigureServices</c> method.
|
||||
|
|
@ -20,32 +20,32 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// public class Startup
|
||||
/// {
|
||||
/// ...
|
||||
///
|
||||
///
|
||||
/// public void ConfigureServices(IServiceCollection services)
|
||||
/// {
|
||||
/// services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
|
||||
/// }
|
||||
///
|
||||
///
|
||||
/// ...
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// 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.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public enum CompatibilityVersion
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the default value of settings on <see cref="MvcOptions"/> to match the behavior of
|
||||
/// Sets the default value of settings on <see cref="MvcOptions"/> to match the behavior of
|
||||
/// ASP.NET Core MVC 2.0.
|
||||
/// </summary>
|
||||
Version_2_0,
|
||||
|
||||
/// <summary>
|
||||
/// Sets the default value of settings on <see cref="MvcOptions"/> to match the behavior of
|
||||
/// Sets the default value of settings on <see cref="MvcOptions"/> to match the behavior of
|
||||
/// ASP.NET Core MVC 2.1.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
///
|
||||
/// <code>
|
||||
/// [HttpGet]
|
||||
/// public ProductModel GetProduct([FromServices] IProductModelRequestService productModelReqest)
|
||||
/// public ProductModel GetProduct([FromServices] IProductModelRequestService productModelRequest)
|
||||
/// {
|
||||
/// return productModelReqest.Value;
|
||||
/// return productModelRequest.Value;
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ using Microsoft.Extensions.Options;
|
|||
namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||
{
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// <see cref="CompatibilityVersion"/>. This is framework infrastructure and should not be used
|
||||
/// by application code.
|
||||
/// </summary>
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
///</para>
|
||||
///<para>
|
||||
/// To be reactively notified of changes, downcast to <see cref="ActionDescriptorCollectionProvider"/> and
|
||||
/// subcribe to the change token returned from <see cref="ActionDescriptorCollectionProvider.GetChangeToken"/>
|
||||
/// subscribe to the change token returned from <see cref="ActionDescriptorCollectionProvider.GetChangeToken"/>
|
||||
/// using <see cref="ChangeToken.OnChange(System.Func{IChangeToken}, System.Action)"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
/// </summary>
|
||||
/// <typeparam name="TResult">The type of <see cref="IActionResult"/>.</typeparam>
|
||||
/// <remarks>
|
||||
/// Implementions of <see cref="IActionResultExecutor{TResult}"/> are typically called by the
|
||||
/// Implementations of <see cref="IActionResultExecutor{TResult}"/> are typically called by the
|
||||
/// <see cref="IActionResult.ExecuteResultAsync(ActionContext)"/> method of the corresponding action result type.
|
||||
/// Implementations should be registered as singleton services.
|
||||
/// </remarks>
|
||||
public interface IActionResultExecutor<in TResult> where TResult : IActionResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Asynchronously excecutes the action result, by modifying the <see cref="HttpResponse"/>.
|
||||
/// Asynchronously executes the action result, by modifying the <see cref="HttpResponse"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ActionContext"/> associated with the current request."/></param>
|
||||
/// <param name="result">The action result to execute.</param>
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
=> typeof(Task<IActionResult>).IsAssignableFrom(executor.MethodReturnType);
|
||||
}
|
||||
|
||||
// Task<PhysicalfileResult> DownloadFile(..)
|
||||
// Task<PhysicalFileResult> DownloadFile(..)
|
||||
// ValueTask<ViewResult> GetViewsAsync(..)
|
||||
private class TaskOfActionResultExecutor : ActionMethodExecutor
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -138,10 +138,12 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
ActionModel action)
|
||||
{
|
||||
var defaultControllerConstraints = Enumerable.Empty<IActionConstraintMetadata>();
|
||||
var defaultControllerEndpointMetadata = Enumerable.Empty<object>();
|
||||
if (controller.Selectors.Count > 0)
|
||||
{
|
||||
defaultControllerConstraints = controller.Selectors[0].ActionConstraints
|
||||
.Where(constraint => !(constraint is IRouteTemplateProvider));
|
||||
defaultControllerEndpointMetadata = controller.Selectors[0].EndpointMetadata;
|
||||
}
|
||||
|
||||
var actionDescriptors = new List<ControllerActionDescriptor>();
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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<Endpoint> _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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<string, StringValues> GetValues(
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1509,18 +1509,18 @@ namespace Microsoft.AspNetCore.Mvc.Core
|
|||
=> string.Format(CultureInfo.CurrentCulture, GetString("ApiConvention_UnsupportedAttributesOnConvention"), p0, p1, p2);
|
||||
|
||||
/// <summary>
|
||||
/// 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}'.
|
||||
/// </summary>
|
||||
internal static string ApiConventionMethod_AmbigiousMethodName
|
||||
internal static string ApiConventionMethod_AmbiguousMethodName
|
||||
{
|
||||
get => GetString("ApiConventionMethod_AmbigiousMethodName");
|
||||
get => GetString("ApiConventionMethod_AmbiguousMethodName");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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}'.
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// A method named '{0}' was not found on convention type '{1}'.
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
|
|
@ -26,36 +26,36 @@
|
|||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
|
|
@ -451,8 +451,8 @@
|
|||
<data name="ApiConvention_UnsupportedAttributesOnConvention" xml:space="preserve">
|
||||
<value>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}.</value>
|
||||
</data>
|
||||
<data name="ApiConventionMethod_AmbigiousMethodName" xml:space="preserve">
|
||||
<value>Method name '{0}' is ambigous for convention type '{1}'. More than one method found with the name '{0}'.</value>
|
||||
<data name="ApiConventionMethod_AmbiguousMethodName" xml:space="preserve">
|
||||
<value>Method name '{0}' is ambiguous for convention type '{1}'. More than one method found with the name '{0}'.</value>
|
||||
</data>
|
||||
<data name="ApiConventionMethod_NoMethodFound" xml:space="preserve">
|
||||
<value>A method named '{0}' was not found on convention type '{1}'.</value>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -201,6 +201,68 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a URI from the provided components.
|
||||
/// </summary>
|
||||
/// <param name="protocol">The URI scheme/protocol.</param>
|
||||
/// <param name="host">The URI host.</param>
|
||||
/// <param name="path">The URI path and remaining portions (path, query, and fragment).</param>
|
||||
/// <returns>
|
||||
/// An absolute URI if the <paramref name="protocol"/> or <paramref name="host"/> is specified, otherwise generates a
|
||||
/// URI with an absolute path.
|
||||
/// </returns>
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
public class ValidationProblemDetails : ProblemDetails
|
||||
{
|
||||
/// <summary>
|
||||
/// Intializes a new instance of <see cref="ValidationProblemDetails"/>.
|
||||
/// Initializes a new instance of <see cref="ValidationProblemDetails"/>.
|
||||
/// </summary>
|
||||
public ValidationProblemDetails()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// <see cref="JsonInputFormatter"/> will be added to the <see cref="ModelStateDictionary"/>. The default
|
||||
/// value is <c>false</c>, meaning that a generic error message will be used instead.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<RazorCompiledItemFeatureProvider>().Any())
|
||||
{
|
||||
builder.PartManager.FeatureProviders.Add(new RazorCompiledItemFeatureProvider());
|
||||
|
|
@ -159,6 +159,9 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, RazorViewEngineOptionsSetup>());
|
||||
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IPostConfigureOptions<RazorViewEngineOptions>, RazorViewEngineOptionsSetup>());
|
||||
|
||||
services.TryAddSingleton<
|
||||
IRazorViewEngineFileProviderAccessor,
|
||||
DefaultRazorViewEngineFileProviderAccessor>();
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<CompiledViewDescriptor> CompileAsync(string relativePath)
|
||||
{
|
||||
|
|
@ -254,16 +256,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
|
||||
// Used to validate and recompile
|
||||
NormalizedPath = normalizedPath,
|
||||
ExpirationTokens = new List<IChangeToken>(),
|
||||
};
|
||||
|
||||
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<IChangeToken>()
|
||||
IList<IChangeToken> expirationTokens = Array.Empty<IChangeToken>();
|
||||
|
||||
if (AllowRecompilingViewsOnFileChange)
|
||||
{
|
||||
_fileProvider.Watch(normalizedPath),
|
||||
};
|
||||
var changeToken = _fileProvider.Watch(normalizedPath);
|
||||
expirationTokens = new List<IChangeToken> { 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<IChangeToken> GetExpirationTokens(CompiledViewDescriptor precompiledView)
|
||||
{
|
||||
if (!AllowRecompilingViewsOnFileChange)
|
||||
{
|
||||
return Array.Empty<IChangeToken>();
|
||||
}
|
||||
|
||||
var checksums = precompiledView.Item.GetChecksumMetadata();
|
||||
var expirationTokens = new List<IChangeToken>(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<IChangeToken> 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<IImportProjectFeature>().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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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
|
|||
/// <summary>
|
||||
/// Provides programmatic configuration for the <see cref="RazorViewEngine"/>.
|
||||
/// </summary>
|
||||
public class RazorViewEngineOptions
|
||||
public class RazorViewEngineOptions : IEnumerable<ICompatibilitySwitch>
|
||||
{
|
||||
private readonly ICompatibilitySwitch[] _switches;
|
||||
private readonly CompatibilitySwitch<bool> _allowRecompilingViewsOnFileChange;
|
||||
private Action<RoslynCompilationContext> _compilationCallback = c => { };
|
||||
|
||||
public RazorViewEngineOptions()
|
||||
{
|
||||
_allowRecompilingViewsOnFileChange = new CompatibilitySwitch<bool>(nameof(AllowRecompilingViewsOnFileChange));
|
||||
_switches = new[]
|
||||
{
|
||||
_allowRecompilingViewsOnFileChange,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="IList{IViewLocationExpander}"/> used by the <see cref="RazorViewEngine"/>.
|
||||
/// </summary>
|
||||
|
|
@ -181,5 +194,52 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
_compilationCallback = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that determines if Razor files (Razor Views and Razor Pages) are recompiled and updated
|
||||
/// if files change on disk.
|
||||
/// <para>
|
||||
/// When <see langword="true"/>, MVC will use <see cref="IFileProvider.Watch(string)"/> to watch for changes to
|
||||
/// Razor files in configured <see cref="IFileProvider"/> instances.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The default value is <see langword="true"/> if the version is <see cref = "CompatibilityVersion.Version_2_1" />
|
||||
/// or earlier. If the version is later and <see cref= "IHostingEnvironment.EnvironmentName" /> is <c>Development</c>,
|
||||
/// the default value is <see langword="true"/>. Otherwise, the default value is <see langword="false" />.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This property is associated with a compatibility switch and can provide a different behavior depending on
|
||||
/// the configured compatibility version for the application. See <see cref="CompatibilityVersion"/> for
|
||||
/// guidance and examples of setting the application's compatibility version.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// 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 <see cref="CompatibilityVersion"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_1"/> or
|
||||
/// lower then this setting will have the value <see langword="true"/> unless explicitly configured.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_2"/> or
|
||||
/// higher then this setting will have the value <see langword="false"/> unless
|
||||
/// <see cref="IHostingEnvironment.EnvironmentName"/> is <c>Development</c> or the value is explicitly configured.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
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<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<ICompatibilitySwitch>)_switches).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets up default options for <see cref="RazorViewEngineOptions"/>.
|
||||
/// </summary>
|
||||
public class RazorViewEngineOptionsSetup : IConfigureOptions<RazorViewEngineOptions>
|
||||
internal class RazorViewEngineOptionsSetup :
|
||||
ConfigureCompatibilityOptions<RazorViewEngineOptions>,
|
||||
IConfigureOptions<RazorViewEngineOptions>
|
||||
{
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="RazorViewEngineOptions"/>.
|
||||
/// </summary>
|
||||
/// <param name="hostingEnvironment"><see cref="IHostingEnvironment"/> for the application.</param>
|
||||
public RazorViewEngineOptionsSetup(IHostingEnvironment hostingEnvironment)
|
||||
public RazorViewEngineOptionsSetup(
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<MvcCompatibilityOptions> compatibilityOptions)
|
||||
: base(loggerFactory, compatibilityOptions)
|
||||
{
|
||||
_hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
|
||||
}
|
||||
|
||||
protected override IReadOnlyDictionary<string, object> DefaultValues
|
||||
{
|
||||
get
|
||||
{
|
||||
var values = new Dictionary<string, object>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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> razorPagesOptions)
|
||||
IOptions<RazorPagesOptions> razorPagesOptions,
|
||||
IOptions<RazorViewEngineOptions> 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++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache
|
|||
public class CacheTagKey : IEquatable<CacheTagKey>
|
||||
{
|
||||
private static readonly char[] AttributeSeparator = new[] { ',' };
|
||||
private static readonly Func<IRequestCookieCollection, string, string> CookieAcccessor = (c, key) => c[key];
|
||||
private static readonly Func<IRequestCookieCollection, string, string> CookieAccessor = (c, key) => c[key];
|
||||
private static readonly Func<IHeaderDictionary, string, string> HeaderAccessor = (c, key) => c[key];
|
||||
private static readonly Func<IQueryCollection, string, string> QueryAccessor = (c, key) => c[key];
|
||||
private static readonly Func<RouteValueDictionary, string, string> 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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -167,9 +167,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <remarks>Does nothing if user provides an <c>formaction</c> attribute.</remarks>
|
||||
/// <remarks>Does nothing if user provides an <c>FormAction</c> attribute.</remarks>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if <c>formaction</c> attribute is provided and <see cref="Action"/>, <see cref="Controller"/>,
|
||||
/// Thrown if <c>FormAction</c> attribute is provided and <see cref="Action"/>, <see cref="Controller"/>,
|
||||
/// <see cref="Fragment"/> or <see cref="Route"/> are non-<c>null</c> or if the user provided <c>asp-route-*</c> attributes.
|
||||
/// Also thrown if <see cref="Route"/> and one or both of <see cref="Action"/> and <see cref="Controller"/>
|
||||
/// are non-<c>null</c>
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
/// <inheritdoc />
|
||||
public override int Order => -900;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Mvc.Testing.Handlers
|
|||
/// <summary>
|
||||
/// Creates a new instance of <see cref="RedirectHandler"/>.
|
||||
/// </summary>
|
||||
/// <param name="maxRedirects">The maximun number of redirect responses to follow. It must be
|
||||
/// <param name="maxRedirects">The maximum number of redirect responses to follow. It must be
|
||||
/// equal or greater than 0.</param>
|
||||
public RedirectHandler(int maxRedirects)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Mvc.Testing
|
|||
/// <see cref="WebApplicationFactoryContentRootAttribute"/> on the assembly containing the functional tests with
|
||||
/// a key equal to the <typeparamref name="TEntryPoint"/> assembly <see cref="Assembly.FullName"/>.
|
||||
/// In case an attribute with the right key can't be found, <see cref="WebApplicationFactory{TEntryPoint}"/>
|
||||
/// will fall back to searching for a solution file (*.sln) and then appending <typeparamref name="TEntryPoint"/> asembly name
|
||||
/// will fall back to searching for a solution file (*.sln) and then appending <typeparamref name="TEntryPoint"/> assembly name
|
||||
/// to the solution directory. The application root directory will be used to discover views and content files.
|
||||
/// </para>
|
||||
/// <para>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// Gets or sets <see cref="ViewDataDictionary"/> used by <see cref="ViewResult"/> and <see cref="ViewBag"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default, this property is intiailized when <see cref="Controllers.IControllerActivator"/> activates
|
||||
/// By default, this property is initialized when <see cref="Controllers.IControllerActivator"/> activates
|
||||
/// controllers.
|
||||
/// <para>
|
||||
/// This property can be accessed after the controller has been activated, for example, in a controller action
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
// 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
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
// 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
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
// 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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
// <inheritdoc />
|
||||
/// <inheritdoc />
|
||||
public int Order { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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<BaseItem>(value);
|
||||
var convertToActionResult = (IConvertToActionResult)actionResultOfT;
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
{
|
||||
}
|
||||
|
||||
private class DeriviedItem : BaseItem
|
||||
private class DerivedItem : BaseItem
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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<RedirectToPageResult>(result);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
Pipeline1.ConfigurePipeline = (ab) =>
|
||||
{
|
||||
configureCallCount++;
|
||||
ab.Use((httpCtxt, next) =>
|
||||
ab.Use((httpContext, next) =>
|
||||
{
|
||||
return next();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -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<bool>("TestProperty", initialValue: true);
|
||||
|
|
@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
var @switch = new CompatibilitySwitch<bool>("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);
|
||||
|
|
|
|||
|
|
@ -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<IActionDescriptorProvider>();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ using Xunit;
|
|||
|
||||
namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||
{
|
||||
public class ProblemDetalsClientErrorFactoryTest
|
||||
public class ProblemDetailsClientErrorFactoryTest
|
||||
{
|
||||
[Fact]
|
||||
public void GetClientError_ReturnsProblemDetails_IfNoMappingWasFound()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<AllowAnonymousAttribute>(metadata),
|
||||
metadata => Assert.IsType<AuthorizeAttribute>(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<AuthorizeAttribute>(metadata).Policy),
|
||||
metadata => Assert.Equal("ControllerPolicy", Assert.IsType<AuthorizeAttribute>(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<RouteAttribute>(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
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<TestActionResult> AsynActionMethodWithTestActionResult(int value)
|
||||
public async Task<TestActionResult> AsyncActionMethodWithTestActionResult(int value)
|
||||
{
|
||||
return await Task.FromResult<TestActionResult>(new TestActionResult { Value = value });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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<IHttpMaxRequestBodySizeFeature>(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<IHttpMaxRequestBodySizeFeature>(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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
|
|
|
|||
|
|
@ -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<IMiddlewareFilterFeature>();
|
||||
|
|
@ -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<IValueProviderFactory> valueProviderFactories,
|
||||
int maxAllowedErrorsInModelState)
|
||||
|
|
|
|||
|
|
@ -112,9 +112,9 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
var asyncResultFilter = Mock.Of<IAsyncResultFilter>();
|
||||
var resourceFilter = Mock.Of<IResourceFilter>();
|
||||
var asyncResourceFilter = Mock.Of<IAsyncResourceFilter>();
|
||||
var orderedresourceFilterMock = new Mock<IOrderedResourceFilter>();
|
||||
orderedresourceFilterMock.SetupGet(f => f.Order).Returns(-100);
|
||||
var orderedResourceFilter = orderedresourceFilterMock.Object;
|
||||
var orderedResourceFilterMock = new Mock<IOrderedResourceFilter>();
|
||||
orderedResourceFilterMock.SetupGet(f => f.Order).Returns(-100);
|
||||
var orderedResourceFilter = orderedResourceFilterMock.Object;
|
||||
var filters = new IFilterMetadata[]
|
||||
{
|
||||
actionFilter,
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
var matcherEndpoint = Assert.IsType<RouteEndpoint>(endpoint);
|
||||
var routeValuesAddressNameMetadata = matcherEndpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
|
||||
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<RouteEndpoint>(ep);
|
||||
var routeValuesAddressMetadata = matcherEndpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
|
||||
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<RouteEndpoint>(ep);
|
||||
var routeValuesAddressMetadata = matcherEndpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
|
||||
Assert.NotNull(routeValuesAddressMetadata);
|
||||
Assert.Equal("namedRoute", routeValuesAddressMetadata.Name);
|
||||
Assert.Equal("namedRoute", routeValuesAddressMetadata.RouteName);
|
||||
Assert.Equal("named/Products/Details/{id?}", matcherEndpoint.RoutePattern.RawText);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<IFormFeature>(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<IFormFeature>(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<IFormFeature>(
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<IHttpMaxRequestBodySizeFeature>(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<IHttpMaxRequestBodySizeFeature>(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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<HttpContext>();
|
||||
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<IActionDescriptorProvider>(MockBehavior.Strict);
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue