Skip to content

Commit 8caf0d7

Browse files
Fixes exception when running in process. Closes #949
1 parent 90283df commit 8caf0d7

File tree

3 files changed

+298
-291
lines changed

3 files changed

+298
-291
lines changed
Lines changed: 168 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -1,165 +1,168 @@
1-
// Copyright (c) Microsoft Corporation.
2-
// Licensed under the MIT License.
3-
4-
using Microsoft.DevProxy.Abstractions;
5-
using Microsoft.VisualStudio.Threading;
6-
using System.CommandLine;
7-
using System.CommandLine.Invocation;
8-
9-
namespace Microsoft.DevProxy.CommandHandlers;
10-
11-
public class ProxyCommandHandler(IPluginEvents pluginEvents,
12-
Option[] options,
13-
ISet<UrlToWatch> urlsToWatch,
14-
ILogger logger) : ICommandHandler
15-
{
16-
private readonly IPluginEvents _pluginEvents = pluginEvents ?? throw new ArgumentNullException(nameof(pluginEvents));
17-
private readonly Option[] _options = options ?? throw new ArgumentNullException(nameof(options));
18-
private readonly ISet<UrlToWatch> _urlsToWatch = urlsToWatch ?? throw new ArgumentNullException(nameof(urlsToWatch));
19-
private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger));
20-
21-
public static ProxyConfiguration Configuration { get => ConfigurationFactory.Value; }
22-
23-
public int Invoke(InvocationContext context)
24-
{
25-
var joinableTaskContext = new JoinableTaskContext();
26-
var joinableTaskFactory = new JoinableTaskFactory(joinableTaskContext);
27-
28-
return joinableTaskFactory.Run(async () => await InvokeAsync(context));
29-
}
30-
31-
public async Task<int> InvokeAsync(InvocationContext context)
32-
{
33-
ParseOptions(context);
34-
_pluginEvents.RaiseOptionsLoaded(new OptionsLoadedArgs(context, _options));
35-
await CheckForNewVersionAsync();
36-
37-
try
38-
{
39-
var builder = WebApplication.CreateBuilder();
40-
builder.Logging.AddFilter("Microsoft.Hosting.*", LogLevel.Error);
41-
builder.Logging.AddFilter("Microsoft.AspNetCore.*", LogLevel.Error);
42-
43-
builder.Services.AddSingleton<IProxyState, ProxyState>();
44-
builder.Services.AddSingleton<IProxyConfiguration, ProxyConfiguration>(sp => ConfigurationFactory.Value);
45-
builder.Services.AddSingleton(_pluginEvents);
46-
builder.Services.AddSingleton(_logger);
47-
builder.Services.AddSingleton(_urlsToWatch);
48-
builder.Services.AddHostedService<ProxyEngine>();
49-
50-
builder.Services.AddControllers();
51-
builder.Services.AddEndpointsApiExplorer();
52-
builder.Services.AddSwaggerGen();
53-
54-
builder.Services.Configure<RouteOptions>(options =>
55-
{
56-
options.LowercaseUrls = true;
57-
});
58-
59-
builder.WebHost.ConfigureKestrel(options =>
60-
{
61-
options.ListenLocalhost(ConfigurationFactory.Value.ApiPort);
62-
_logger.LogInformation("Dev Proxy API listening on http://localhost:{Port}...", ConfigurationFactory.Value.ApiPort);
63-
});
64-
65-
var app = builder.Build();
66-
app.UseSwagger();
67-
app.UseSwaggerUI();
68-
app.MapControllers();
69-
await app.RunAsync();
70-
71-
return 0;
72-
}
73-
catch (Exception ex)
74-
{
75-
_logger.LogError(ex, "An error occurred while running Dev Proxy");
76-
var inner = ex.InnerException;
77-
78-
while (inner is not null)
79-
{
80-
_logger.LogError(inner, "============ Inner exception ============");
81-
inner = inner.InnerException;
82-
}
83-
#if DEBUG
84-
throw; // so debug tools go straight to the source of the exception when attached
85-
#else
86-
return 1;
87-
#endif
88-
}
89-
90-
}
91-
92-
private void ParseOptions(InvocationContext context)
93-
{
94-
var port = context.ParseResult.GetValueForOption<int?>(ProxyHost.PortOptionName, _options);
95-
if (port is not null)
96-
{
97-
Configuration.Port = port.Value;
98-
}
99-
var ipAddress = context.ParseResult.GetValueForOption<string?>(ProxyHost.IpAddressOptionName, _options);
100-
if (ipAddress is not null)
101-
{
102-
Configuration.IPAddress = ipAddress;
103-
}
104-
var record = context.ParseResult.GetValueForOption<bool?>(ProxyHost.RecordOptionName, _options);
105-
if (record is not null)
106-
{
107-
Configuration.Record = record.Value;
108-
}
109-
var watchPids = context.ParseResult.GetValueForOption<IEnumerable<int>?>(ProxyHost.WatchPidsOptionName, _options);
110-
if (watchPids is not null)
111-
{
112-
Configuration.WatchPids = watchPids;
113-
}
114-
var watchProcessNames = context.ParseResult.GetValueForOption<IEnumerable<string>?>(ProxyHost.WatchProcessNamesOptionName, _options);
115-
if (watchProcessNames is not null)
116-
{
117-
Configuration.WatchProcessNames = watchProcessNames;
118-
}
119-
var rate = context.ParseResult.GetValueForOption<int?>(ProxyHost.RateOptionName, _options);
120-
if (rate is not null)
121-
{
122-
Configuration.Rate = rate.Value;
123-
}
124-
var noFirstRun = context.ParseResult.GetValueForOption<bool?>(ProxyHost.NoFirstRunOptionName, _options);
125-
if (noFirstRun is not null)
126-
{
127-
Configuration.NoFirstRun = noFirstRun.Value;
128-
}
129-
var asSystemProxy = context.ParseResult.GetValueForOption<bool?>(ProxyHost.AsSystemProxyOptionName, _options);
130-
if (asSystemProxy is not null)
131-
{
132-
Configuration.AsSystemProxy = asSystemProxy.Value;
133-
}
134-
var installCert = context.ParseResult.GetValueForOption<bool?>(ProxyHost.InstallCertOptionName, _options);
135-
if (installCert is not null)
136-
{
137-
Configuration.InstallCert = installCert.Value;
138-
}
139-
}
140-
141-
private async Task CheckForNewVersionAsync()
142-
{
143-
var newReleaseInfo = await UpdateNotification.CheckForNewVersionAsync(Configuration.NewVersionNotification);
144-
if (newReleaseInfo != null)
145-
{
146-
_logger.LogInformation(
147-
"New Dev Proxy version {version} is available.{newLine}See https://aka.ms/devproxy/upgrade for more information.",
148-
newReleaseInfo.Version,
149-
Environment.NewLine
150-
);
151-
}
152-
}
153-
154-
private static readonly Lazy<ProxyConfiguration> ConfigurationFactory = new(() =>
155-
{
156-
var builder = new ConfigurationBuilder();
157-
var configuration = builder
158-
.AddJsonFile(ProxyHost.ConfigFile, optional: true, reloadOnChange: true)
159-
.Build();
160-
var configObject = new ProxyConfiguration();
161-
configuration.Bind(configObject);
162-
163-
return configObject;
164-
});
165-
}
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.DevProxy.Abstractions;
5+
using Microsoft.VisualStudio.Threading;
6+
using System.CommandLine;
7+
using System.CommandLine.Invocation;
8+
9+
namespace Microsoft.DevProxy.CommandHandlers;
10+
11+
public class ProxyCommandHandler(IPluginEvents pluginEvents,
12+
Option[] options,
13+
ISet<UrlToWatch> urlsToWatch,
14+
ILogger logger) : ICommandHandler
15+
{
16+
private readonly IPluginEvents _pluginEvents = pluginEvents ?? throw new ArgumentNullException(nameof(pluginEvents));
17+
private readonly Option[] _options = options ?? throw new ArgumentNullException(nameof(options));
18+
private readonly ISet<UrlToWatch> _urlsToWatch = urlsToWatch ?? throw new ArgumentNullException(nameof(urlsToWatch));
19+
private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger));
20+
21+
public static ProxyConfiguration Configuration { get => ConfigurationFactory.Value; }
22+
23+
public int Invoke(InvocationContext context)
24+
{
25+
var joinableTaskContext = new JoinableTaskContext();
26+
var joinableTaskFactory = new JoinableTaskFactory(joinableTaskContext);
27+
28+
return joinableTaskFactory.Run(async () => await InvokeAsync(context));
29+
}
30+
31+
public async Task<int> InvokeAsync(InvocationContext context)
32+
{
33+
ParseOptions(context);
34+
_pluginEvents.RaiseOptionsLoaded(new OptionsLoadedArgs(context, _options));
35+
await CheckForNewVersionAsync();
36+
37+
try
38+
{
39+
var builder = WebApplication.CreateBuilder();
40+
builder.Logging.AddFilter("Microsoft.Hosting.*", LogLevel.Error);
41+
builder.Logging.AddFilter("Microsoft.AspNetCore.*", LogLevel.Error);
42+
43+
builder.Services.AddSingleton<IProxyState, ProxyState>();
44+
builder.Services.AddSingleton<IProxyConfiguration, ProxyConfiguration>(sp => ConfigurationFactory.Value);
45+
builder.Services.AddSingleton(_pluginEvents);
46+
builder.Services.AddSingleton(_logger);
47+
builder.Services.AddSingleton(_urlsToWatch);
48+
builder.Services.AddHostedService<ProxyEngine>();
49+
50+
builder.Services.AddControllers();
51+
builder.Services.AddEndpointsApiExplorer();
52+
builder.Services.AddSwaggerGen();
53+
54+
builder.Services.Configure<RouteOptions>(options =>
55+
{
56+
options.LowercaseUrls = true;
57+
});
58+
59+
builder.WebHost.ConfigureKestrel(options =>
60+
{
61+
options.ListenLocalhost(ConfigurationFactory.Value.ApiPort);
62+
_logger.LogInformation("Dev Proxy API listening on http://localhost:{Port}...", ConfigurationFactory.Value.ApiPort);
63+
});
64+
65+
var app = builder.Build();
66+
app.UseSwagger();
67+
app.UseSwaggerUI();
68+
app.MapControllers();
69+
await app.RunAsync();
70+
71+
return 0;
72+
}
73+
catch (TaskCanceledException)
74+
{
75+
throw;
76+
}
77+
catch (Exception ex)
78+
{
79+
_logger.LogError(ex, "An error occurred while running Dev Proxy");
80+
var inner = ex.InnerException;
81+
82+
while (inner is not null)
83+
{
84+
_logger.LogError(inner, "============ Inner exception ============");
85+
inner = inner.InnerException;
86+
}
87+
#if DEBUG
88+
throw; // so debug tools go straight to the source of the exception when attached
89+
#else
90+
return 1;
91+
#endif
92+
}
93+
}
94+
95+
private void ParseOptions(InvocationContext context)
96+
{
97+
var port = context.ParseResult.GetValueForOption<int?>(ProxyHost.PortOptionName, _options);
98+
if (port is not null)
99+
{
100+
Configuration.Port = port.Value;
101+
}
102+
var ipAddress = context.ParseResult.GetValueForOption<string?>(ProxyHost.IpAddressOptionName, _options);
103+
if (ipAddress is not null)
104+
{
105+
Configuration.IPAddress = ipAddress;
106+
}
107+
var record = context.ParseResult.GetValueForOption<bool?>(ProxyHost.RecordOptionName, _options);
108+
if (record is not null)
109+
{
110+
Configuration.Record = record.Value;
111+
}
112+
var watchPids = context.ParseResult.GetValueForOption<IEnumerable<int>?>(ProxyHost.WatchPidsOptionName, _options);
113+
if (watchPids is not null)
114+
{
115+
Configuration.WatchPids = watchPids;
116+
}
117+
var watchProcessNames = context.ParseResult.GetValueForOption<IEnumerable<string>?>(ProxyHost.WatchProcessNamesOptionName, _options);
118+
if (watchProcessNames is not null)
119+
{
120+
Configuration.WatchProcessNames = watchProcessNames;
121+
}
122+
var rate = context.ParseResult.GetValueForOption<int?>(ProxyHost.RateOptionName, _options);
123+
if (rate is not null)
124+
{
125+
Configuration.Rate = rate.Value;
126+
}
127+
var noFirstRun = context.ParseResult.GetValueForOption<bool?>(ProxyHost.NoFirstRunOptionName, _options);
128+
if (noFirstRun is not null)
129+
{
130+
Configuration.NoFirstRun = noFirstRun.Value;
131+
}
132+
var asSystemProxy = context.ParseResult.GetValueForOption<bool?>(ProxyHost.AsSystemProxyOptionName, _options);
133+
if (asSystemProxy is not null)
134+
{
135+
Configuration.AsSystemProxy = asSystemProxy.Value;
136+
}
137+
var installCert = context.ParseResult.GetValueForOption<bool?>(ProxyHost.InstallCertOptionName, _options);
138+
if (installCert is not null)
139+
{
140+
Configuration.InstallCert = installCert.Value;
141+
}
142+
}
143+
144+
private async Task CheckForNewVersionAsync()
145+
{
146+
var newReleaseInfo = await UpdateNotification.CheckForNewVersionAsync(Configuration.NewVersionNotification);
147+
if (newReleaseInfo != null)
148+
{
149+
_logger.LogInformation(
150+
"New Dev Proxy version {version} is available.{newLine}See https://aka.ms/devproxy/upgrade for more information.",
151+
newReleaseInfo.Version,
152+
Environment.NewLine
153+
);
154+
}
155+
}
156+
157+
private static readonly Lazy<ProxyConfiguration> ConfigurationFactory = new(() =>
158+
{
159+
var builder = new ConfigurationBuilder();
160+
var configuration = builder
161+
.AddJsonFile(ProxyHost.ConfigFile, optional: true, reloadOnChange: true)
162+
.Build();
163+
var configObject = new ProxyConfiguration();
164+
configuration.Bind(configObject);
165+
166+
return configObject;
167+
});
168+
}

0 commit comments

Comments
 (0)