Skip to content

Commit d0c8628

Browse files
Adds Dev Proxy API
1 parent c0808d8 commit d0c8628

18 files changed

+351
-141
lines changed

.vscode/launch.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
1717
"console": "integratedTerminal",
1818
"stopAtEntry": false,
19-
"launchSettingsProfile": "Default"
19+
"launchSettingsProfile": "Default",
20+
"env": {
21+
"ASPNETCORE_ENVIRONMENT": "Development"
22+
}
2023
},
2124
{
2225
"name": ".NET Core Attach",

dev-proxy-abstractions/IProxyConfiguration.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,18 @@ public enum LabelMode
1818

1919
public interface IProxyConfiguration
2020
{
21-
int Port { get; }
21+
int ApiPort { get; }
22+
bool AsSystemProxy { get; }
2223
string? IPAddress { get; }
24+
string ConfigFile { get; }
25+
bool InstallCert { get; }
26+
MockRequestHeader[]? FilterByHeaders { get; }
2327
LabelMode LabelMode { get; }
24-
bool Record { get; }
2528
LogLevel LogLevel { get; }
29+
bool NoFirstRun { get; }
30+
int Port { get; }
31+
int Rate { get; }
32+
bool Record { get; }
2633
IEnumerable<int> WatchPids { get; }
2734
IEnumerable<string> WatchProcessNames { get; }
28-
int Rate { get; }
29-
string ConfigFile { get; }
3035
}

dev-proxy-abstractions/PluginEvents.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,15 @@ public interface IPluginEvents
218218
/// Raised when user requested issuing mock requests.
219219
/// </summary>
220220
event AsyncEventHandler<EventArgs>? MockRequest;
221+
222+
void RaiseInit(InitArgs args);
223+
void RaiseOptionsLoaded(OptionsLoadedArgs args);
224+
Task RaiseProxyBeforeRequest(ProxyRequestArgs args, ExceptionHandler? exceptionFunc = null);
225+
Task RaiseProxyBeforeResponse(ProxyResponseArgs args, ExceptionHandler? exceptionFunc = null);
226+
Task RaiseProxyAfterResponse(ProxyResponseArgs args, ExceptionHandler? exceptionFunc = null);
227+
void RaiseRequestLogged(RequestLogArgs args);
228+
Task RaiseRecordingStopped(RecordingArgs args, ExceptionHandler? exceptionFunc = null);
229+
Task RaiseMockRequest(EventArgs args, ExceptionHandler? exceptionFunc = null);
221230
}
222231

223232
public class PluginEvents : IPluginEvents
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.AspNetCore.Mvc;
5+
6+
namespace Microsoft.DevProxy.ApiControllers;
7+
8+
[ApiController]
9+
[Route("[controller]")]
10+
public class ProxyController : ControllerBase
11+
{
12+
private readonly IProxyState _proxyState;
13+
14+
public ProxyController(IProxyState proxyState)
15+
{
16+
_proxyState = proxyState;
17+
}
18+
19+
[HttpGet]
20+
public ProxyInfo Get() => ProxyInfo.From(_proxyState);
21+
22+
[HttpPost]
23+
public IActionResult Set([FromBody] ProxyInfo proxyInfo)
24+
{
25+
if (proxyInfo.ConfigFile != null)
26+
{
27+
return BadRequest("ConfigFile cannot be set");
28+
}
29+
30+
if (proxyInfo.Recording.HasValue)
31+
{
32+
_proxyState.IsRecording = proxyInfo.Recording.Value;
33+
}
34+
35+
return Ok(ProxyInfo.From(_proxyState));
36+
}
37+
38+
[HttpPost("raiseMockRequest")]
39+
public void RaiseMockRequest()
40+
{
41+
_proxyState.RaiseMockRequest();
42+
Response.StatusCode = 202;
43+
}
44+
45+
[HttpPost("stopProxy")]
46+
public void StopProxy()
47+
{
48+
Response.StatusCode = 202;
49+
_proxyState.StopProxy();
50+
}
51+
}

dev-proxy/ApiControllers/ProxyInfo.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
namespace Microsoft.DevProxy.ApiControllers;
5+
6+
public class ProxyInfo
7+
{
8+
public bool? Recording { get; set; }
9+
public string? ConfigFile { get; init; }
10+
11+
public static ProxyInfo From(IProxyState proxyState)
12+
{
13+
return new ProxyInfo
14+
{
15+
ConfigFile = proxyState.ProxyConfiguration.ConfigFile,
16+
Recording = proxyState.IsRecording
17+
};
18+
}
19+
}

dev-proxy/MSGraphDbCommandHandler.cs renamed to dev-proxy/CommandHandlers/MSGraphDbCommandHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using Microsoft.DevProxy.Abstractions;
66
using Microsoft.Extensions.Logging;
77

8-
namespace Microsoft.DevProxy;
8+
namespace Microsoft.DevProxy.CommandHandlers;
99

1010
public class MSGraphDbCommandHandler : ICommandHandler
1111
{

dev-proxy/OutdatedCommandHandler.cs renamed to dev-proxy/CommandHandlers/OutdatedCommandHandler.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
using Microsoft.Extensions.Logging;
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
23

3-
namespace Microsoft.DevProxy;
4+
using Microsoft.Extensions.Logging;
5+
6+
namespace Microsoft.DevProxy.CommandHandlers;
47

58
public static class OutdatedCommandHandler
69
{

dev-proxy/PresetGetCommandHandler.cs renamed to dev-proxy/CommandHandlers/PresetGetCommandHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using System.Net.Http.Headers;
77
using System.Text.Json;
88

9-
namespace Microsoft.DevProxy;
9+
namespace Microsoft.DevProxy.CommandHandlers;
1010

1111
class ProxyPresetInfo
1212
{

dev-proxy/ProxyCommandHandler.cs renamed to dev-proxy/CommandHandlers/ProxyCommandHandler.cs

Lines changed: 77 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
using Microsoft.Extensions.Configuration;
5-
using Microsoft.Extensions.Logging;
64
using Microsoft.DevProxy.Abstractions;
75
using System.CommandLine;
86
using System.CommandLine.Invocation;
97

10-
namespace Microsoft.DevProxy;
8+
namespace Microsoft.DevProxy.CommandHandlers;
119

1210
public class ProxyCommandHandler : ICommandHandler
1311
{
14-
private readonly PluginEvents _pluginEvents;
12+
private readonly IPluginEvents _pluginEvents;
1513
private readonly Option[] _options;
1614
private readonly ISet<UrlToWatch> _urlsToWatch;
1715
private readonly ILogger _logger;
1816

19-
public ProxyCommandHandler(PluginEvents pluginEvents,
17+
public static ProxyConfiguration Configuration { get => ConfigurationFactory.Value; }
18+
19+
public ProxyCommandHandler(IPluginEvents pluginEvents,
2020
Option[] options,
2121
ISet<UrlToWatch> urlsToWatch,
2222
ILogger logger)
@@ -33,6 +33,73 @@ public int Invoke(InvocationContext context)
3333
}
3434

3535
public async Task<int> InvokeAsync(InvocationContext context)
36+
{
37+
ParseOptions(context);
38+
_pluginEvents.RaiseOptionsLoaded(new OptionsLoadedArgs(context, _options));
39+
await CheckForNewVersion();
40+
41+
try
42+
{
43+
var builder = WebApplication.CreateBuilder();
44+
builder.Logging.AddFilter("Microsoft.Hosting.*", LogLevel.Error);
45+
builder.Logging.AddFilter("Microsoft.AspNetCore.*", LogLevel.Error);
46+
47+
builder.Services.AddSingleton<IProxyState, ProxyState>();
48+
builder.Services.AddSingleton<IProxyConfiguration, ProxyConfiguration>(sp => ConfigurationFactory.Value);
49+
builder.Services.AddSingleton(_pluginEvents);
50+
builder.Services.AddSingleton(_logger);
51+
builder.Services.AddSingleton(_urlsToWatch);
52+
builder.Services.AddHostedService<ProxyEngine>();
53+
54+
builder.Services.AddControllers();
55+
builder.Services.AddEndpointsApiExplorer();
56+
builder.Services.AddSwaggerGen();
57+
58+
builder.Services.Configure<RouteOptions>(options =>
59+
{
60+
options.LowercaseUrls = true;
61+
});
62+
63+
builder.WebHost.ConfigureKestrel(options =>
64+
{
65+
options.ListenLocalhost(ConfigurationFactory.Value.ApiPort);
66+
_logger.LogInformation("Dev Proxy API listening on http://localhost:{Port}...", ConfigurationFactory.Value.ApiPort);
67+
});
68+
69+
var app = builder.Build();
70+
71+
if (app.Environment.IsDevelopment())
72+
{
73+
app.UseSwagger();
74+
app.UseSwaggerUI();
75+
}
76+
77+
app.MapControllers();
78+
app.Run();
79+
80+
81+
return 0;
82+
}
83+
catch (Exception ex)
84+
{
85+
_logger.LogError(ex, "An error occurred while running Dev Proxy");
86+
var inner = ex.InnerException;
87+
88+
while (inner is not null)
89+
{
90+
_logger.LogError(inner, "============ Inner exception ============");
91+
inner = inner.InnerException;
92+
}
93+
#if DEBUG
94+
throw; // so debug tools go straight to the source of the exception when attached
95+
#else
96+
return 1;
97+
#endif
98+
}
99+
100+
}
101+
102+
private void ParseOptions(InvocationContext context)
36103
{
37104
var port = context.ParseResult.GetValueForOption<int?>(ProxyHost.PortOptionName, _options);
38105
if (port is not null)
@@ -79,11 +146,10 @@ public async Task<int> InvokeAsync(InvocationContext context)
79146
{
80147
Configuration.InstallCert = installCert.Value;
81148
}
149+
}
82150

83-
CancellationToken? cancellationToken = (CancellationToken?)context.BindingContext.GetService(typeof(CancellationToken?));
84-
85-
_pluginEvents.RaiseOptionsLoaded(new OptionsLoadedArgs(context, _options));
86-
151+
private async Task CheckForNewVersion()
152+
{
87153
var newReleaseInfo = await UpdateNotification.CheckForNewVersion(Configuration.NewVersionNotification);
88154
if (newReleaseInfo != null)
89155
{
@@ -93,39 +159,14 @@ public async Task<int> InvokeAsync(InvocationContext context)
93159
Environment.NewLine
94160
);
95161
}
96-
97-
try
98-
{
99-
await new ProxyEngine(Configuration, _urlsToWatch, _pluginEvents, _logger).Run(cancellationToken);
100-
return 0;
101-
}
102-
catch (Exception ex)
103-
{
104-
_logger.LogError(ex, "An error occurred while running Dev Proxy");
105-
var inner = ex.InnerException;
106-
107-
while (inner is not null)
108-
{
109-
_logger.LogError(inner, "============ Inner exception ============");
110-
inner = inner.InnerException;
111-
}
112-
#if DEBUG
113-
throw; // so debug tools go straight to the source of the exception when attached
114-
#else
115-
return 1;
116-
#endif
117-
}
118-
119162
}
120163

121-
public static ProxyConfiguration Configuration { get => ConfigurationFactory.Value; }
122-
123164
private static readonly Lazy<ProxyConfiguration> ConfigurationFactory = new(() =>
124165
{
125166
var builder = new ConfigurationBuilder();
126167
var configuration = builder
127-
.AddJsonFile(ProxyHost.ConfigFile, optional: true, reloadOnChange: true)
128-
.Build();
168+
.AddJsonFile(ProxyHost.ConfigFile, optional: true, reloadOnChange: true)
169+
.Build();
129170
var configObject = new ProxyConfiguration();
130171
configuration.Bind(configObject);
131172

dev-proxy/IProxyState.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.DevProxy.Abstractions;
5+
6+
namespace Microsoft.DevProxy;
7+
8+
public interface IProxyState
9+
{
10+
Dictionary<string, object> GlobalData { get; }
11+
bool IsRecording { get; set; }
12+
IProxyConfiguration ProxyConfiguration { get; }
13+
List<RequestLog> RequestLogs { get; }
14+
void RaiseMockRequest();
15+
void StartRecording();
16+
void StopProxy();
17+
Task StopRecording();
18+
}

dev-proxy/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
using Microsoft.DevProxy;
55
using Microsoft.DevProxy.Abstractions;
6+
using Microsoft.DevProxy.CommandHandlers;
67
using Microsoft.DevProxy.Logging;
7-
using Microsoft.Extensions.Logging;
88
using Microsoft.Extensions.Logging.Console;
99
using System.CommandLine;
1010

dev-proxy/ProxyConfiguration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System.Runtime.Serialization;
55
using System.Text.Json.Serialization;
66
using Microsoft.DevProxy.Abstractions;
7-
using Microsoft.Extensions.Logging;
87

98
namespace Microsoft.DevProxy;
109

@@ -38,4 +37,5 @@ public class ProxyConfiguration : IProxyConfiguration
3837
public ReleaseType NewVersionNotification { get; set; } = ReleaseType.Stable;
3938
public LanguageModelConfiguration? LanguageModel { get; set; }
4039
public MockRequestHeader[]? FilterByHeaders { get; set; }
40+
public int ApiPort { get; set; } = 8897;
4141
}

dev-proxy/ProxyContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (c) Microsoft Corporation.
2-
// Licensed under the MIT License.using Microsoft.Extensions.Configuration;
2+
// Licensed under the MIT License.
33

44
using System.Security.Cryptography.X509Certificates;
55
using Microsoft.DevProxy.Abstractions;

0 commit comments

Comments
 (0)