Skip to content

Commit 07726b8

Browse files
committed
MapAction MVP (WIP)
1 parent 1c8da41 commit 07726b8

39 files changed

+1150
-146
lines changed

AspNetCore.sln

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,6 +1553,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Te
15531553
EndProject
15541554
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mvc.Testing.Tasks", "Mvc.Testing.Tasks", "{34465A80-3BAF-4059-81B3-9090C0DB598F}"
15551555
EndProject
1556+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Http.Api", "Http.Api", "{CF128C76-CE42-49A4-90BD-24EEF8C679A0}"
1557+
EndProject
1558+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http.Api.Abstractions", "src\Http\Http.Api.Abstractions\src\Microsoft.AspNetCore.Http.Api.Abstractions.csproj", "{FC207C53-1C0C-44D2-B391-018C270F7721}"
1559+
EndProject
1560+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http.Api", "src\Http\Http.Api\src\Microsoft.AspNetCore.Http.Api.csproj", "{BE407DBB-0890-4429-B7FF-B620641021A4}"
1561+
EndProject
1562+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http.Api.Tests", "src\Http\Http.Api\test\Microsoft.AspNetCore.Http.Api.Tests.csproj", "{DDF82B37-944C-4FF7-9EFA-18B28F352DBF}"
1563+
EndProject
1564+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Http.Api.Abstractions", "Http.Api.Abstractions", "{3FFB0F1C-F056-499D-8305-8513182B4B76}"
1565+
EndProject
1566+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpApiSampleApp", "src\Http\samples\HttpApiSampleApp\HttpApiSampleApp.csproj", "{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8}"
1567+
EndProject
15561568
Global
15571569
GlobalSection(SolutionConfigurationPlatforms) = preSolution
15581570
Debug|Any CPU = Debug|Any CPU
@@ -7417,6 +7429,54 @@ Global
74177429
{5C50FA92-5488-4470-B42E-48EFEBA51D5A}.Release|x64.Build.0 = Release|Any CPU
74187430
{5C50FA92-5488-4470-B42E-48EFEBA51D5A}.Release|x86.ActiveCfg = Release|Any CPU
74197431
{5C50FA92-5488-4470-B42E-48EFEBA51D5A}.Release|x86.Build.0 = Release|Any CPU
7432+
{FC207C53-1C0C-44D2-B391-018C270F7721}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
7433+
{FC207C53-1C0C-44D2-B391-018C270F7721}.Debug|Any CPU.Build.0 = Debug|Any CPU
7434+
{FC207C53-1C0C-44D2-B391-018C270F7721}.Debug|x64.ActiveCfg = Debug|Any CPU
7435+
{FC207C53-1C0C-44D2-B391-018C270F7721}.Debug|x64.Build.0 = Debug|Any CPU
7436+
{FC207C53-1C0C-44D2-B391-018C270F7721}.Debug|x86.ActiveCfg = Debug|Any CPU
7437+
{FC207C53-1C0C-44D2-B391-018C270F7721}.Debug|x86.Build.0 = Debug|Any CPU
7438+
{FC207C53-1C0C-44D2-B391-018C270F7721}.Release|Any CPU.ActiveCfg = Release|Any CPU
7439+
{FC207C53-1C0C-44D2-B391-018C270F7721}.Release|Any CPU.Build.0 = Release|Any CPU
7440+
{FC207C53-1C0C-44D2-B391-018C270F7721}.Release|x64.ActiveCfg = Release|Any CPU
7441+
{FC207C53-1C0C-44D2-B391-018C270F7721}.Release|x64.Build.0 = Release|Any CPU
7442+
{FC207C53-1C0C-44D2-B391-018C270F7721}.Release|x86.ActiveCfg = Release|Any CPU
7443+
{FC207C53-1C0C-44D2-B391-018C270F7721}.Release|x86.Build.0 = Release|Any CPU
7444+
{BE407DBB-0890-4429-B7FF-B620641021A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
7445+
{BE407DBB-0890-4429-B7FF-B620641021A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
7446+
{BE407DBB-0890-4429-B7FF-B620641021A4}.Debug|x64.ActiveCfg = Debug|Any CPU
7447+
{BE407DBB-0890-4429-B7FF-B620641021A4}.Debug|x64.Build.0 = Debug|Any CPU
7448+
{BE407DBB-0890-4429-B7FF-B620641021A4}.Debug|x86.ActiveCfg = Debug|Any CPU
7449+
{BE407DBB-0890-4429-B7FF-B620641021A4}.Debug|x86.Build.0 = Debug|Any CPU
7450+
{BE407DBB-0890-4429-B7FF-B620641021A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
7451+
{BE407DBB-0890-4429-B7FF-B620641021A4}.Release|Any CPU.Build.0 = Release|Any CPU
7452+
{BE407DBB-0890-4429-B7FF-B620641021A4}.Release|x64.ActiveCfg = Release|Any CPU
7453+
{BE407DBB-0890-4429-B7FF-B620641021A4}.Release|x64.Build.0 = Release|Any CPU
7454+
{BE407DBB-0890-4429-B7FF-B620641021A4}.Release|x86.ActiveCfg = Release|Any CPU
7455+
{BE407DBB-0890-4429-B7FF-B620641021A4}.Release|x86.Build.0 = Release|Any CPU
7456+
{DDF82B37-944C-4FF7-9EFA-18B28F352DBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
7457+
{DDF82B37-944C-4FF7-9EFA-18B28F352DBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
7458+
{DDF82B37-944C-4FF7-9EFA-18B28F352DBF}.Debug|x64.ActiveCfg = Debug|Any CPU
7459+
{DDF82B37-944C-4FF7-9EFA-18B28F352DBF}.Debug|x64.Build.0 = Debug|Any CPU
7460+
{DDF82B37-944C-4FF7-9EFA-18B28F352DBF}.Debug|x86.ActiveCfg = Debug|Any CPU
7461+
{DDF82B37-944C-4FF7-9EFA-18B28F352DBF}.Debug|x86.Build.0 = Debug|Any CPU
7462+
{DDF82B37-944C-4FF7-9EFA-18B28F352DBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
7463+
{DDF82B37-944C-4FF7-9EFA-18B28F352DBF}.Release|Any CPU.Build.0 = Release|Any CPU
7464+
{DDF82B37-944C-4FF7-9EFA-18B28F352DBF}.Release|x64.ActiveCfg = Release|Any CPU
7465+
{DDF82B37-944C-4FF7-9EFA-18B28F352DBF}.Release|x64.Build.0 = Release|Any CPU
7466+
{DDF82B37-944C-4FF7-9EFA-18B28F352DBF}.Release|x86.ActiveCfg = Release|Any CPU
7467+
{DDF82B37-944C-4FF7-9EFA-18B28F352DBF}.Release|x86.Build.0 = Release|Any CPU
7468+
{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
7469+
{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
7470+
{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8}.Debug|x64.ActiveCfg = Debug|Any CPU
7471+
{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8}.Debug|x64.Build.0 = Debug|Any CPU
7472+
{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8}.Debug|x86.ActiveCfg = Debug|Any CPU
7473+
{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8}.Debug|x86.Build.0 = Debug|Any CPU
7474+
{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
7475+
{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8}.Release|Any CPU.Build.0 = Release|Any CPU
7476+
{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8}.Release|x64.ActiveCfg = Release|Any CPU
7477+
{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8}.Release|x64.Build.0 = Release|Any CPU
7478+
{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8}.Release|x86.ActiveCfg = Release|Any CPU
7479+
{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8}.Release|x86.Build.0 = Release|Any CPU
74207480
EndGlobalSection
74217481
GlobalSection(SolutionProperties) = preSolution
74227482
HideSolutionNode = FALSE
@@ -8193,6 +8253,12 @@ Global
81938253
{5FD94164-7D13-4618-93AD-7346B0EA0CDD} = {C1409A8F-555A-4A88-B803-C6D3E8B6C3B0}
81948254
{5C50FA92-5488-4470-B42E-48EFEBA51D5A} = {34465A80-3BAF-4059-81B3-9090C0DB598F}
81958255
{34465A80-3BAF-4059-81B3-9090C0DB598F} = {1A0EFF9F-E699-4303-AE50-BFAF9804EEB6}
8256+
{CF128C76-CE42-49A4-90BD-24EEF8C679A0} = {627BE8B3-59E6-4F1D-8C9C-76B804D41724}
8257+
{FC207C53-1C0C-44D2-B391-018C270F7721} = {3FFB0F1C-F056-499D-8305-8513182B4B76}
8258+
{BE407DBB-0890-4429-B7FF-B620641021A4} = {CF128C76-CE42-49A4-90BD-24EEF8C679A0}
8259+
{DDF82B37-944C-4FF7-9EFA-18B28F352DBF} = {CF128C76-CE42-49A4-90BD-24EEF8C679A0}
8260+
{3FFB0F1C-F056-499D-8305-8513182B4B76} = {627BE8B3-59E6-4F1D-8C9C-76B804D41724}
8261+
{A64CD3C4-5C5D-4873-9B6F-A89F17D321C8} = {EB5E294B-9ED5-43BF-AFA9-1CD2327F3DC1}
81968262
EndGlobalSection
81978263
GlobalSection(ExtensibilityGlobals) = postSolution
81988264
SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F}

eng/ProjectReferences.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Authentication.Core" ProjectPath="$(RepoRoot)src\Http\Authentication.Core\src\Microsoft.AspNetCore.Authentication.Core.csproj" />
2727
<ProjectReferenceProvider Include="Microsoft.Net.Http.Headers" ProjectPath="$(RepoRoot)src\Http\Headers\src\Microsoft.Net.Http.Headers.csproj" />
2828
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Http.Abstractions" ProjectPath="$(RepoRoot)src\Http\Http.Abstractions\src\Microsoft.AspNetCore.Http.Abstractions.csproj" />
29+
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Http.Api.Abstractions" ProjectPath="$(RepoRoot)src\Http\Http.Api.Abstractions\src\Microsoft.AspNetCore.Http.Api.Abstractions.csproj" />
30+
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Http.Api" ProjectPath="$(RepoRoot)src\Http\Http.Api\src\Microsoft.AspNetCore.Http.Api.csproj" />
2931
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Http.Extensions" ProjectPath="$(RepoRoot)src\Http\Http.Extensions\src\Microsoft.AspNetCore.Http.Extensions.csproj" />
3032
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Http.Features" ProjectPath="$(RepoRoot)src\Http\Http.Features\src\Microsoft.AspNetCore.Http.Features.csproj" />
3133
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Http" ProjectPath="$(RepoRoot)src\Http\Http\src\Microsoft.AspNetCore.Http.csproj" />

eng/SharedFramework.Local.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Authentication.Core" />
4747
<AspNetCoreAppReference Include="Microsoft.Net.Http.Headers" />
4848
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Http.Abstractions" />
49+
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Http.Api.Abstractions" />
50+
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Http.Api" />
4951
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Http.Extensions" />
5052
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Http" />
5153
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Routing.Abstractions" />

src/Mvc/Mvc.Core/src/Routing/IActionHttpMethodProvider.cs renamed to src/Http/Http.Api.Abstractions/src/IActionHttpMethodProvider.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4-
#nullable enable
5-
64
using System.Collections.Generic;
75

86
namespace Microsoft.AspNetCore.Mvc.Routing
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.AspNetCore.Http.Api.Abstractions
5+
{
6+
/// <summary>
7+
/// Interface marking attributes that specify a parameter or property should be bound using the request body.
8+
/// </summary>
9+
public interface IFromBodyAttribute
10+
{
11+
}
12+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.AspNetCore.Http.Api.Abstractions
5+
{
6+
/// <summary>
7+
/// Interface marking attributes that specify a parameter or property should be bound using route-data from the current request.
8+
/// </summary>
9+
public interface IFromRouteAttribute
10+
{
11+
/// <summary>
12+
/// The <see cref="HttpRequest.RouteValues"/> name.
13+
/// </summary>
14+
string Name { get; }
15+
}
16+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Threading.Tasks;
5+
6+
namespace Microsoft.AspNetCore.Http.Api.Abstractions
7+
{
8+
/// <summary>
9+
/// Defines a contract that represents the result of an HTTP endpoint.
10+
/// </summary>
11+
public interface IResult
12+
{
13+
/// <summary>
14+
/// Write an HTTP response reflecting the result.
15+
/// </summary>
16+
/// <param name="httpContext">The <see cref="HttpContext"/> for the current request.</param>
17+
/// <returns>A task that represents the asynchronous execute operation.</returns>
18+
ValueTask WriteResponseAsync(HttpContext httpContext);
19+
}
20+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
5+
<Description>ASP.NET Core types for describing HTTP APIs.</Description>
6+
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
7+
<IsAspNetCoreApp>true</IsAspNetCoreApp>
8+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
9+
<PackageTags>aspnetcore</PackageTags>
10+
<IsPackable>false</IsPackable>
11+
<Nullable>enable</Nullable>
12+
</PropertyGroup>
13+
14+
<ItemGroup>
15+
<Reference Include="Microsoft.AspNetCore.Http.Abstractions" />
16+
</ItemGroup>
17+
18+
</Project>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Runtime.CompilerServices;
5+
6+
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Http.Api.Abstractions.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#nullable enable
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#nullable enable
2+
Microsoft.AspNetCore.Http.Api.Abstractions.IFromBodyAttribute
3+
Microsoft.AspNetCore.Http.Api.Abstractions.IFromRouteAttribute
4+
Microsoft.AspNetCore.Http.Api.Abstractions.IFromRouteAttribute.Name.get -> string!
5+
Microsoft.AspNetCore.Http.Api.Abstractions.IResult
6+
Microsoft.AspNetCore.Http.Api.Abstractions.IResult.WriteResponseAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext) -> System.Threading.Tasks.ValueTask
7+
Microsoft.AspNetCore.Mvc.Routing.IActionHttpMethodProvider
8+
Microsoft.AspNetCore.Mvc.Routing.IActionHttpMethodProvider.HttpMethods.get -> System.Collections.Generic.IEnumerable<string!>!
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Linq;
6+
using System.Reflection;
7+
using System.Runtime.CompilerServices;
8+
9+
namespace Microsoft.AspNetCore.Http.Api
10+
{
11+
internal readonly struct AwaitableInfo
12+
{
13+
public Type AwaiterType { get; }
14+
public PropertyInfo AwaiterIsCompletedProperty { get; }
15+
public MethodInfo AwaiterGetResultMethod { get; }
16+
public MethodInfo AwaiterOnCompletedMethod { get; }
17+
public MethodInfo? AwaiterUnsafeOnCompletedMethod { get; }
18+
public Type ResultType { get; }
19+
public MethodInfo GetAwaiterMethod { get; }
20+
21+
public AwaitableInfo(
22+
Type awaiterType,
23+
PropertyInfo awaiterIsCompletedProperty,
24+
MethodInfo awaiterGetResultMethod,
25+
MethodInfo awaiterOnCompletedMethod,
26+
MethodInfo? awaiterUnsafeOnCompletedMethod,
27+
Type resultType,
28+
MethodInfo getAwaiterMethod)
29+
{
30+
AwaiterType = awaiterType;
31+
AwaiterIsCompletedProperty = awaiterIsCompletedProperty;
32+
AwaiterGetResultMethod = awaiterGetResultMethod;
33+
AwaiterOnCompletedMethod = awaiterOnCompletedMethod;
34+
AwaiterUnsafeOnCompletedMethod = awaiterUnsafeOnCompletedMethod;
35+
ResultType = resultType;
36+
GetAwaiterMethod = getAwaiterMethod;
37+
}
38+
39+
public static bool IsTypeAwaitable(Type type, out AwaitableInfo awaitableInfo)
40+
{
41+
// Based on Roslyn code: http://source.roslyn.io/#Microsoft.CodeAnalysis.Workspaces/Shared/Extensions/ISymbolExtensions.cs,db4d48ba694b9347
42+
43+
// Awaitable must have method matching "object GetAwaiter()"
44+
var getAwaiterMethod = type.GetMethods().FirstOrDefault(m =>
45+
m.Name.Equals("GetAwaiter", StringComparison.Ordinal)
46+
&& m.GetParameters().Length == 0
47+
&& m.ReturnType != null);
48+
if (getAwaiterMethod == null)
49+
{
50+
awaitableInfo = default(AwaitableInfo);
51+
return false;
52+
}
53+
54+
var awaiterType = getAwaiterMethod.ReturnType;
55+
56+
// Awaiter must have property matching "bool IsCompleted { get; }"
57+
var isCompletedProperty = awaiterType.GetProperties().FirstOrDefault(p =>
58+
p.Name.Equals("IsCompleted", StringComparison.Ordinal)
59+
&& p.PropertyType.Equals(typeof(bool))
60+
&& p.GetMethod != null);
61+
if (isCompletedProperty == null)
62+
{
63+
awaitableInfo = default(AwaitableInfo);
64+
return false;
65+
}
66+
67+
// Awaiter must implement INotifyCompletion
68+
var awaiterInterfaces = awaiterType.GetInterfaces();
69+
var implementsINotifyCompletion = awaiterInterfaces.Any(t => t.Equals(typeof(INotifyCompletion)));
70+
if (!implementsINotifyCompletion)
71+
{
72+
awaitableInfo = default(AwaitableInfo);
73+
return false;
74+
}
75+
76+
// INotifyCompletion supplies a method matching "void OnCompleted(Action action)"
77+
//var iNotifyCompletionMap = awaiterType
78+
// .GetTypeInfo()
79+
// .DeclaredMethods
80+
// .GetRuntimeInterfaceMap(getType(typeof(INotifyCompletion)));
81+
var onCompletedMethod = awaiterType.GetMethods().Single(m =>
82+
m.Name.Equals("OnCompleted", StringComparison.Ordinal)
83+
&& m.ReturnType.Equals(typeof(void))
84+
&& m.GetParameters().Length == 1
85+
&& m.GetParameters()[0].ParameterType.Equals(typeof(Action)));
86+
87+
// Awaiter optionally implements ICriticalNotifyCompletion
88+
var implementsICriticalNotifyCompletion = awaiterInterfaces.Any(t => t.Equals(typeof(ICriticalNotifyCompletion)));
89+
MethodInfo? unsafeOnCompletedMethod;
90+
if (implementsICriticalNotifyCompletion)
91+
{
92+
// ICriticalNotifyCompletion supplies a method matching "void UnsafeOnCompleted(Action action)"
93+
//var iCriticalNotifyCompletionMap = awaiterType
94+
// .GetTypeInfo()
95+
// .GetRuntimeInterfaceMap(typeof(ICriticalNotifyCompletion));
96+
unsafeOnCompletedMethod = awaiterType.GetMethods().Single(m =>
97+
m.Name.Equals("UnsafeOnCompleted", StringComparison.Ordinal)
98+
&& m.ReturnType.Equals(typeof(void))
99+
&& m.GetParameters().Length == 1
100+
&& m.GetParameters()[0].ParameterType.Equals(typeof(Action)));
101+
}
102+
else
103+
{
104+
unsafeOnCompletedMethod = null;
105+
}
106+
107+
// Awaiter must have method matching "void GetResult" or "T GetResult()"
108+
var getResultMethod = awaiterType.GetMethods().FirstOrDefault(m =>
109+
m.Name.Equals("GetResult", StringComparison.Ordinal)
110+
&& m.GetParameters().Length == 0);
111+
if (getResultMethod == null)
112+
{
113+
awaitableInfo = default(AwaitableInfo);
114+
return false;
115+
}
116+
117+
awaitableInfo = new AwaitableInfo(
118+
awaiterType,
119+
isCompletedProperty,
120+
getResultMethod,
121+
onCompletedMethod,
122+
unsafeOnCompletedMethod,
123+
getResultMethod.ReturnType,
124+
getAwaiterMethod);
125+
return true;
126+
}
127+
}
128+
}

0 commit comments

Comments
 (0)