Создайте настраиваемый подключаемый модуль

На первый взгляд
Цель: Создание настраиваемого подключаемого модуля Прокси для разработки
Время: 30 минут
Плагины: Настраиваемый плагин
Предварительные требования:настройка прокси-сервера разработки, .NET 10 SDK

Из этой статьи вы узнаете, как создать пользовательский плагин для Dev-прокси. Создавая подключаемые модули для прокси-сервера разработки, вы можете расширить функциональные возможности и добавить пользовательские функции в соответствии с вашими потребностями.

Плагины HTTP и плагины stdio

Dev Proxy поддерживает два типа плагинов в зависимости от трафика, который вы хотите перехватывать.

  • HTTP-плагины перехватывают HTTP(S)-запросы и ответы между вашим приложением и API. Они наследуются от BasePlugin и переопределяют такие методы, как BeforeRequestAsync и BeforeResponseAsync. Используйте подключаемые модули HTTP, если вы хотите имитировать ошибки API, добавлять макеты ответов, проверять заголовки запросов или иначе проверять и изменять HTTP-трафик.

  • Подключаемые модули Stdio перехватывают сообщения, отправленные по стандартным входным и выходным данным (stdin, stdout, stderr) между родительским процессом и дочерним процессом. Они реализуют IStdioPlugin интерфейс (который BasePlugin также реализует) и переопределяют такие методы, как BeforeStdinAsync, AfterStdoutAsyncи AfterStderrAsync. Используйте подключаемые модули stdio при работе с инструментами, которые взаимодействуют через stdio, например серверы протокола контекста модели (MCP).

Один класс подключаемого модуля может обрабатывать трафик HTTP и stdio, переопределяя методы из обоих наборов.

Предварительные условия

Прежде чем приступить к созданию пользовательского плагина, убедитесь, что у вас есть следующие требования:

Создайте новый подключаемый модуль

Выполните следующие действия, чтобы создать новый проект:

  1. Создайте проект библиотеки классов с помощью dotnet new classlib команды.

    dotnet new classlib -n MyCustomPlugin
    
  2. Откройте созданный проект в Visual Studio Code.

    code MyCustomPlugin
    
  3. Добавьте пакет NuGet Dev Proxy Abstractions в свой проект.

    dotnet add package DevProxy.Abstractions
    
  4. Исключите библиотеки DLL зависимостей из выходных файлов сборки, добавив тег ExcludeAssets для каждого PackageReference в файл MyCustomPlugin.csproj.

    <ExcludeAssets>runtime</ExcludeAssets>
    
  5. Создайте новый класс, наследующий от BaseProxy класса.

    using DevProxy.Abstractions.Plugins;
    using DevProxy.Abstractions.Proxy;
    using Microsoft.Extensions.Logging;
    
    namespace MyCustomPlugin;
    
    public sealed class CatchApiCallsPlugin(
        ILogger<CatchApiCallsPlugin> logger,
        ISet<UrlToWatch> urlsToWatch) : BasePlugin(logger, urlsToWatch)
    {
        public override string Name => nameof(CatchApiCallsPlugin);
    
        public override Task BeforeRequestAsync(ProxyRequestArgs e, CancellationToken cancellationToken)
        {
            Logger.LogTrace("{Method} called", nameof(BeforeRequestAsync));
    
            ArgumentNullException.ThrowIfNull(e);
    
            if (!e.HasRequestUrlMatch(UrlsToWatch))
            {
                Logger.LogRequest("URL not matched", MessageType.Skipped, new(e.Session));
                return Task.CompletedTask;
            }
    
            var headers = e.Session.HttpClient.Request.Headers;
            var header = headers.Where(h => h.Name == "Authorization").FirstOrDefault();
            if (header is null)
            {
                Logger.LogRequest($"Does not contain the Authorization header", MessageType.Warning, new LoggingContext(e.Session));
                return Task.CompletedTask;
            }
    
            Logger.LogTrace("Left {Name}", nameof(BeforeRequestAsync));
            return Task.CompletedTask;
        }
    }
    
  6. Создайте свой проект.

    dotnet build
    

Использование пользовательского подключаемого модуля

Чтобы использовать настраиваемый подключаемый модуль, необходимо добавить его в файл конфигурации тестового прокси-сервера.

  1. Добавьте новую конфигурацию плагина в файл devproxyrc.json.

    Файл: devproxyrc.json

    {
      "plugins": [{
        "name": "CatchApiCallsPlugin",
        "enabled": true,
        "pluginPath": "./bin/Debug/net10.0/MyCustomPlugin.dll",
      }]
    }
    
  2. Запустите прокси-сервер разработки.

    devproxy
    

Пример плагина проверяет все соответствующие URL-адреса на предмет требуемого Authorization заголовка. Если заголовок отсутствует, отображается предупреждение.

Добавление настраиваемой конфигурации в подключаемый модуль (необязательно)

Вы можете расширить логику вашего плагина, добавив пользовательскую конфигурацию.

  1. Наследуется от BasePlugin<TConfiguration> класса. Прокси-сервер разработки на этапе выполнения предоставляет проанализированную конфигурацию подключаемого модуля через свойство Configuration.

    using DevProxy.Abstractions.Plugins;
    using DevProxy.Abstractions.Proxy;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Logging;
    
    namespace MyCustomPlugin;
    
    public sealed class CatchApiCallsConfiguration
    {
        public string? RequiredHeader { get; set; }
    }
    
    public sealed class CatchApiCallsPlugin(
        HttpClient httpClient,
        ILogger<CatchApiCallsPlugin> logger,
        ISet<UrlToWatch> urlsToWatch,
        IProxyConfiguration proxyConfiguration,
        IConfigurationSection pluginConfigurationSection) :
        BasePlugin<CatchApiCallsConfiguration>(
            httpClient,
            logger,
            urlsToWatch,
            proxyConfiguration,
            pluginConfigurationSection)
    {
        public override string Name => nameof(CatchApiCallsPlugin);
    
        public override Task BeforeRequestAsync(ProxyRequestArgs e, CancellationToken cancellationToken)
        {
            Logger.LogTrace("{Method} called", nameof(BeforeRequestAsync));
    
            ArgumentNullException.ThrowIfNull(e);
    
            if (!e.HasRequestUrlMatch(UrlsToWatch))
            {
                Logger.LogRequest("URL not matched", MessageType.Skipped, new(e.Session));
                return Task.CompletedTask;
            }
    
            // Start using your custom configuration
            var requiredHeader = Configuration.RequiredHeader ?? string.Empty;
            if (string.IsNullOrEmpty(requiredHeader))
            {
                // Required header is not set, so we don't need to do anything
                Logger.LogRequest("Required header not set", MessageType.Skipped, new LoggingContext(e.Session));
                return Task.CompletedTask;
            }
    
            var headers = e.Session.HttpClient.Request.Headers;
            var header = headers.Where(h => h.Name == requiredHeader).FirstOrDefault();
            if (header is null)
            {
                Logger.LogRequest($"Does not contain the {requiredHeader} header", MessageType.Warning, new LoggingContext(e.Session));
                return Task.CompletedTask;
            }
    
            Logger.LogTrace("Left {Name}", nameof(BeforeRequestAsync));
            return Task.CompletedTask;
        }
    }
    
  2. Создайте свой проект.

    dotnet build
    
  3. Обновите devproxyrc.json файл, чтобы включить новую конфигурацию.

    Файл: devproxyrc.json

    {
      "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.1.0/rc.schema.json",
      "plugins": [{
        "name": "CatchApiCallsPlugin",
        "enabled": true,
        "pluginPath": "./bin/Debug/net10.0/MyCustomPlugin.dll",
        "configSection": "catchApiCalls"
      }],
      "catchApiCalls": {
        "requiredHeader": "Authorization"
      }
    }
    
  4. Запустите прокси-сервер разработки.

    devproxy
    

См. также