Creare un plug-in personalizzato

A colpo d'occhio
Obiettivo: Creare un plug-in dev proxy personalizzato
Tempo: 30 minuti
Plugin: Plug-in personalizzato
Prerequisiti:Configurare Dev Proxy, .NET 10 SDK

Questo articolo illustra come creare un plug-in personalizzato per il proxy di sviluppo. Creando plug-in per Dev Proxy, è possibile estenderne le funzionalità e aggiungere funzionalità personalizzate in base alle proprie esigenze.

Plugin HTTP vs. plugin stdio

Dev Proxy supporta due tipi di plug-in a seconda del traffico che si vuole intercettare:

  • I plug-in HTTP intercettano le richieste e le risposte HTTP tra l'app e le API. Ereditano da BasePlugin ed eseguono l'override di metodi come BeforeRequestAsync e BeforeResponseAsync. Usare plug-in HTTP quando si vogliono simulare errori dell'API, aggiungere risposte fittizie, convalidare le intestazioni delle richieste o controllare e modificare in altro modo il traffico HTTP.

  • I plug-in Stdio intercettano i messaggi inviati tramite input/output standard (stdin, stdout, stderr) tra un processo padre e un processo figlio. Implementano l'interfaccia IStdioPlugin (che anche BasePlugin implementa) e ridefiniscono metodi come BeforeStdinAsync, AfterStdoutAsync e AfterStderrAsync. Usare i plugin stdio quando si utilizzano strumenti che comunicano tramite stdio, come i server MCP (Model Context Protocol).

Una singola classe di plug-in può gestire il traffico HTTP e stdio eseguendo l'override dei metodi di entrambi i set.

Prerequisiti

Prima di iniziare a creare un plug-in personalizzato, assicurarsi di avere i prerequisiti seguenti:

Creare un nuovo plug-in

Seguire i passaggi successivi per creare un nuovo progetto:

  1. Creare un nuovo progetto di libreria di classi usando il dotnet new classlib comando .

    dotnet new classlib -n MyCustomPlugin
    
  2. Aprire il progetto appena creato in Visual Studio Code.

    code MyCustomPlugin
    
  3. Aggiungere il pacchetto NuGet Dev Proxy Abstractions al progetto.

    dotnet add package DevProxy.Abstractions
    
  4. Escludere dall'output di compilazione le librerie di dipendenza con collegamento dinamico (DLL) aggiungendo un tag ExcludeAssets per ogni PackageReference nel file MyCustomPlugin.csproj.

    <ExcludeAssets>runtime</ExcludeAssets>
    
  5. Creare una nuova classe che eredita dalla BaseProxy classe .

    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. Crea il progetto.

    dotnet build
    

Usare il plug-in personalizzato

Per usare il plug-in personalizzato, è necessario aggiungerlo al file di configurazione di Dev Proxy:

  1. Aggiungere la nuova configurazione del plug-in nel devproxyrc.json file.

    File: devproxyrc.json

    {
      "plugins": [{
        "name": "CatchApiCallsPlugin",
        "enabled": true,
        "pluginPath": "./bin/Debug/net10.0/MyCustomPlugin.dll",
      }]
    }
    
  2. Eseguire il proxy di sviluppo.

    devproxy
    

Il plug-in di esempio controlla tutti gli URL corrispondenti per l'intestazione richiesta Authorization . Se l'intestazione non è presente, viene visualizzato un messaggio di avviso.

Aggiunta di una configurazione personalizzata al plug-in (facoltativo)

È possibile estendere la logica del plug-in aggiungendo una configurazione personalizzata:

  1. Ereditare dalla BasePlugin<TConfiguration> classe . Dev Proxy espone la configurazione del plug-in analizzato in fase di esecuzione tramite la Configuration proprietà .

    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. Crea il progetto.

    dotnet build
    
  3. Aggiornare il devproxyrc.json file in modo da includere la nuova configurazione.

    File: devproxyrc.json

    {
      "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.0.0/rc.schema.json",
      "plugins": [{
        "name": "CatchApiCallsPlugin",
        "enabled": true,
        "pluginPath": "./bin/Debug/net10.0/MyCustomPlugin.dll",
        "configSection": "catchApiCalls"
      }],
      "catchApiCalls": {
        "requiredHeader": "Authorization"
      }
    }
    
  4. Eseguire il proxy di sviluppo.

    devproxy
    

Vedere anche