File: Internal\ExtensionMessageHandlerWrapper.cs
Web Access
Project: src\src\Tools\ExternalAccess\Extensions\Microsoft.CodeAnalysis.ExternalAccess.Extensions.csproj (Microsoft.CodeAnalysis.ExternalAccess.Extensions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ExternalAccess.Extensions;
 
namespace Microsoft.CodeAnalysis.Extensions;
 
internal abstract class ExtensionHandlerWrapper<TArgument>
    : IExtensionMessageHandlerWrapper<TArgument>
{
    private readonly object _handler;
    private readonly MethodInfo _executeAsyncMethod;
    private readonly PropertyInfo _responseTaskResultProperty;
 
    protected ExtensionHandlerWrapper(object handler, Type customMessageHandlerInterface, string extensionIdentifier)
    {
        _handler = handler;
 
        Name = handler.GetType().FullName;
        MessageType = customMessageHandlerInterface.GenericTypeArguments[0];
        ResponseType = customMessageHandlerInterface.GenericTypeArguments[1];
        ExtensionIdentifier = extensionIdentifier;
 
        _executeAsyncMethod = customMessageHandlerInterface.GetMethod(nameof(ExecuteAsync));
        _responseTaskResultProperty = typeof(Task<>).MakeGenericType(ResponseType).GetProperty(nameof(Task<int>.Result));
    }
 
    public Type MessageType { get; }
 
    public Type ResponseType { get; }
 
    public string Name { get; }
 
    public string ExtensionIdentifier { get; }
 
    public async Task<object?> ExecuteAsync(object? message, TArgument argument, CancellationToken cancellationToken)
    {
        if ((message is null && MessageType.IsValueType) || (message is not null && !MessageType.IsAssignableFrom(message.GetType())))
        {
            throw new InvalidOperationException(string.Format(ExternalAccessExtensionsResources.The_message_type_0_is_not_assignable_to_1, message?.GetType().FullName ?? "null", MessageType.FullName));
        }
 
        var responseTask = ExecuteAsync(_executeAsyncMethod, _handler, message, argument, cancellationToken);
        await responseTask.ConfigureAwait(false);
        var response = _responseTaskResultProperty.GetValue(responseTask);
 
        if ((response is null && ResponseType.IsValueType) || (response is not null && !ResponseType.IsAssignableFrom(response.GetType())))
        {
            throw new InvalidOperationException(string.Format(ExternalAccessExtensionsResources.The_message_type_0_is_not_assignable_to_1, response?.GetType().FullName ?? "null", ResponseType.FullName));
        }
 
        return response;
    }
 
    protected abstract Task ExecuteAsync(MethodInfo executeAsyncMethod, object handler, object? message, TArgument argument, CancellationToken cancellationToken);
}