Developing custom plugins for the Microsoft's Dev Proxy

For a training project I was working on, I needed to be able to intercept some API calls for some audit logging. To do this, I decided to use Microsoft’s Dev Proxy tool, which you use to simulate, mock, and test APIs.

As the Dev Proxy did not have the functionality I needed out of the box, I decided to develop a custom plugin with the help of Waldek Mastykarz.

In this blog post, I will show you how you can develop custom plugins for the Dev Proxy.

Things you need to get started

Before you can start developing custom plugins for the Dev Proxy, you need to have the following tools installed:

important

The Dev Proxy Abstractions DLL is available on the Microsoft’s Dev Proxy GitHub releases page.

Show image Dev Proxy Abstractions DLL
Dev Proxy Abstractions DLL

Setting up the project

Once you install all the prerequisites, you can start setting up the project.

  • Start creating the new project by running the following command in your terminal:
Create a new class library project
1
dotnet new classlib -n DevProxyCustomPlugin
  • Next, navigate to the newly created project folder:
Open the project folder
1
cd DevProxyCustomPlugin
  • Open the project in Visual Studio Code
  • Add the Dev Proxy Abstractions DLL to the project
  • Open the DevProxyCustomPlugin.csproj file and add the following lines in the project group:
Add the Dev Proxy Abstractions DLL reference for the project
1
2
3
4
5
6
7
<ItemGroup>
  <Reference Include="dev-proxy-abstractions">
    <HintPath>.\dev-proxy-abstractions.dll</HintPath>
    <Private>false</Private>
    <ExcludeAssets>runtime</ExcludeAssets>
  </Reference>
</ItemGroup>
important

Make sure to exclude the DLL as it is not requires for the plugin. You can do this by setting the ExcludeAssets to runtime.

  • Add the required packages:
Add the required packages
1
2
3
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Binder
dotnet add package Titanium.Web.Proxy
  • Similar to the dev-proxy-abstractions.dll configuration, make sure to exclude the new packages’ assets by adding the ExcludeAssets property to the PackageReference element in the DevProxyCustomPlugin.csproj file:
Exclude the assets for the new packages
1
2
3
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0">
  <ExcludeAssets>runtime</ExcludeAssets>
</PackageReference>
  • Update the Class1.cs file with the name of your plugin class:
Starter code for the plugin class
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
using Microsoft.DevProxy.Abstractions;
using Microsoft.Extensions.Configuration;

namespace DevProxyCustomPlugin;

public class RedirectCalls : BaseProxyPlugin
{
  public override string Name => nameof(RedirectCalls);

  public override void Register(IPluginEvents pluginEvents,
                                IProxyContext context,
                                ISet<UrlToWatch> urlsToWatch,
                                IConfigurationSection? configSection = null)
  {
    base.Register(pluginEvents, context, urlsToWatch, configSection);
  }
}
info

For this sample, I created a plugin which you can use to redirect API calls to your local API, which is useful when locally developing a project.

With this in place, you can start developing your custom plugin for the Dev Proxy.

Show image Start developing your custom plugin
Start developing your custom plugin

Adding a before-request event handler

You can add a before-request event handler to the plugin to intercept the API calls. In the Register method, you can add the following code:

Add a before request event handler
1
2
3
4
5
6
7
8
9
public override void Register(IPluginEvents pluginEvents,
                              IProxyContext context,
                              ISet<UrlToWatch> urlsToWatch,
                              IConfigurationSection? configSection = null)
{
  base.Register(pluginEvents, context, urlsToWatch, configSection);

  pluginEvents.BeforeRequest += OnBeforeRequest;
}

Create a new method, OnBeforeRequest to handle the event:

Add the OnBeforeRequest method
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
private void OnBeforeRequest(object sender, BeforeRequestEventArgs e)
{
  if (_urlsToWatch is null ||
    !e.HasRequestUrlMatch(_urlsToWatch))
  {
    // No match for the URL, so we don't need to do anything
    return Task.CompletedTask;
  }

  // Replace the following lines with your custom logic
  if (e.Session.HttpClient.Request.RequestUri.AbsoluteUri.Contains("https://frontmatter.codes"))
  {
    var url = e.Session.HttpClient.Request.RequestUri.AbsoluteUri;
    e.Session.HttpClient.Request.RequestUri = new Uri(url.Replace("https://frontmatter.codes", "http://localhost:3000"));
  }

  return Task.CompletedTask;
}

In this example, the OnBeforeRequest method checks if the request URL contains https://frontmatter.codes. If it does, it replaces the URL with http://localhost:3000. That way, I can test the API calls locally while developing the project.

info

Change the code in the OnBeforeRequest method to fit your needs.

Once you have added the OnBeforeRequest method’s code, you can build the plugin by running the following command in the terminal:

Build the plugin
1
dotnet build

Testing the plugin

To test the plugin, add it to the Dev Proxy configuration. You can do this by adding the following lines to the devproxyrc.json file:

Add the plugin to the Dev Proxy configuration
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  "$schema": "https://raw.githubusercontent.com/microsoft/dev-proxy/main/schemas/v0.16.0/rc.schema.json",
  "plugins": [{
    "name": "RedirectCalls",
    "enabled": true,
    "pluginPath": "./bin/Debug/net8.0/DevProxyCustomPlugin.dll"
  }],
  "githubCopilotListener": {
    "logPath": "./logs"
  },
  "urlsToWatch": [
    "https://frontmatter.codes/api/*"
  ],
  "labelMode": "text",
  "logLevel": "debug",
  "newVersionNotification": "stable"
}

Start the Dev Proxy by running the following command in the terminal:

Start the Dev Proxy
1
devproxy

Now, you can test the plugin by requesting the URL specified in the urlsToWatch configuration. In my example, when I call the https://frontmatter.codes/api/stars API, the request gets redirected to http://localhost:5000/api/stars, and I can see the response from my local API.

Show image Test the plugin by making a request
Test the plugin by making a request

Adding some plugin configuration

To make the plugin more flexible, you can add some configuration options. For instance, you can define the root URL and the local URL to redirect the API calls to.

To do this, you can add the following configuration to the devproxyrc.json file:

Add the plugin configuration to the Dev Proxy configuration
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{
  "$schema": "https://raw.githubusercontent.com/microsoft/dev-proxy/main/schemas/v0.15.0/rc.schema.json",
  "plugins": [{
    "name": "RedirectCalls",
    "enabled": true,
    "pluginPath": "./bin/Debug/net8.0/DevProxyCustomPlugin.dll",
    "configSection": "redirectCalls"
  }],
  "redirectCalls": {
    "fromUrl": "https://frontmatter.codes",
    "toUrl": "http://localhost:3000"
  },
  "urlsToWatch": [
    "https://frontmatter.codes/api/*"
  ],
  "labelMode": "text",
  "logLevel": "debug",
  "newVersionNotification": "stable"
}

In the RedirectCalls plugin sections, I added a configSection property with the value redirectCalls. This configuration allows me to access the plugin’s configuration.

In the redirectCalls section, I added the fromUrl and toUrl properties, which define the root URL and the local URL to which the API calls should be redirected.

To access the configuration in the plugin, you need to bind the configuration. The whole code for the plugin class should look like this:

Redirect Calls plugin class with configuration
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
using Microsoft.DevProxy.Abstractions;
using Microsoft.Extensions.Configuration;

namespace DevProxyCustomPlugin;

public class RedirectCallsConfiguration
{
  public string? FromUrl { get; set; }
  public string? ToUrl { get; set; }
}

public class RedirectCalls : BaseProxyPlugin
{
  public override string Name => nameof(RedirectCalls);
  private readonly RedirectCallsConfiguration _configuration = new();

  public override void Register(IPluginEvents pluginEvents,
                                IProxyContext context,
                                ISet<UrlToWatch> urlsToWatch,
                                IConfigurationSection? configSection = null)
  {
    base.Register(pluginEvents, context, urlsToWatch, configSection);

    configSection?.Bind(_configuration);

    pluginEvents.BeforeRequest += OnBeforeRequest;
  }

  private Task OnBeforeRequest(object sender, ProxyRequestArgs e)
  {
    if (_urlsToWatch is null ||
      !e.HasRequestUrlMatch(_urlsToWatch))
    {
      // No match for the URL, so we don't need to do anything
      return Task.CompletedTask;
    }

    var fromUrl = _configuration?.FromUrl ?? string.Empty;
    var toUrl = _configuration?.ToUrl ?? string.Empty;

    if (string.IsNullOrEmpty(fromUrl) || string.IsNullOrEmpty(toUrl))
    {
      return Task.CompletedTask;
    }

    if (e.Session.HttpClient.Request.RequestUri.AbsoluteUri.Contains(fromUrl))
    {
      var url = e.Session.HttpClient.Request.RequestUri.AbsoluteUri;
      e.Session.HttpClient.Request.RequestUri = new Uri(url.Replace(fromUrl, toUrl));
    }

    return Task.CompletedTask;
  }
}

With this configuration in place, you can test the plugin with the new configuration options.

Show image Test the plugin with the new configuration options
Test the plugin with the new configuration options

The example above is available on my GitHub devproxy-redirect-plugin repository.

Conclusion

Developing custom plugins for Microsoft’s Dev Proxy is a great way to extend the tool’s functionality. With the help of the Dev Proxy Abstractions DLL, you can easily create custom plugins that can intercept API calls, modify requests and responses, and much more.

Comments

Back to top