20
20
using OpenQA . Selenium . Remote ;
21
21
using System ;
22
22
using System . Diagnostics ;
23
+ using System . Diagnostics . CodeAnalysis ;
23
24
using System . Globalization ;
24
25
using System . IO ;
25
26
using System . Net ;
26
27
using System . Net . Http ;
27
28
using System . Threading . Tasks ;
28
29
30
+ #nullable enable
31
+
29
32
namespace OpenQA . Selenium
30
33
{
31
34
/// <summary>
32
35
/// Exposes the service provided by a native WebDriver server executable.
33
36
/// </summary>
34
37
public abstract class DriverService : ICommandServer
35
38
{
36
- private string driverServicePath ;
37
- private string driverServiceExecutableName ;
38
- private string driverServiceHostName = "localhost" ;
39
- private int driverServicePort ;
40
- private bool silent ;
41
- private bool hideCommandPromptWindow ;
42
39
private bool isDisposed ;
43
- private Process driverServiceProcess ;
44
- private TimeSpan initializationTimeout = TimeSpan . FromSeconds ( 20 ) ;
40
+ private Process ? driverServiceProcess ;
45
41
46
42
/// <summary>
47
43
/// Initializes a new instance of the <see cref="DriverService"/> class.
@@ -55,29 +51,33 @@ public abstract class DriverService : ICommandServer
55
51
/// <exception cref="DriverServiceNotFoundException">
56
52
/// If the specified driver service executable does not exist in the specified directory.
57
53
/// </exception>
58
- protected DriverService ( string servicePath , int port , string driverServiceExecutableName )
54
+ protected DriverService ( string ? servicePath , int port , string ? driverServiceExecutableName )
59
55
{
60
- this . driverServicePath = servicePath ;
61
- this . driverServiceExecutableName = driverServiceExecutableName ;
62
- this . driverServicePort = port ;
56
+ this . DriverServicePath = servicePath ;
57
+ this . DriverServiceExecutableName = driverServiceExecutableName ;
58
+ this . Port = port ;
63
59
}
64
60
65
61
/// <summary>
66
62
/// Occurs when the driver process is starting.
67
63
/// </summary>
68
- public event EventHandler < DriverProcessStartingEventArgs > DriverProcessStarting ;
64
+ public event EventHandler < DriverProcessStartingEventArgs > ? DriverProcessStarting ;
69
65
70
66
/// <summary>
71
67
/// Occurs when the driver process has completely started.
72
68
/// </summary>
73
- public event EventHandler < DriverProcessStartedEventArgs > DriverProcessStarted ;
69
+ public event EventHandler < DriverProcessStartedEventArgs > ? DriverProcessStarted ;
74
70
75
71
/// <summary>
76
72
/// Gets the Uri of the service.
77
73
/// </summary>
78
74
public Uri ServiceUrl
79
75
{
80
- get { return new Uri ( string . Format ( CultureInfo . InvariantCulture , "http://{0}:{1}" , this . driverServiceHostName , this . driverServicePort ) ) ; }
76
+ get
77
+ {
78
+ string url = string . Format ( CultureInfo . InvariantCulture , "http://{0}:{1}" , this . HostName , this . Port ) ;
79
+ return new Uri ( url ) ;
80
+ }
81
81
}
82
82
83
83
/// <summary>
@@ -88,48 +88,30 @@ public Uri ServiceUrl
88
88
/// (non-local) machines. This property can be used as a workaround so
89
89
/// that an IP address (like "127.0.0.1" or "::1") can be used instead.
90
90
/// </remarks>
91
- public string HostName
92
- {
93
- get { return this . driverServiceHostName ; }
94
- set { this . driverServiceHostName = value ; }
95
- }
91
+ public string HostName { get ; set ; } = "localhost" ;
96
92
97
93
/// <summary>
98
94
/// Gets or sets the port of the service.
99
95
/// </summary>
100
- public int Port
101
- {
102
- get { return this . driverServicePort ; }
103
- set { this . driverServicePort = value ; }
104
- }
96
+ public int Port { get ; set ; }
105
97
106
98
/// <summary>
107
99
/// Gets or sets a value indicating whether the initial diagnostic information is suppressed
108
100
/// when starting the driver server executable. Defaults to <see langword="false"/>, meaning
109
101
/// diagnostic information should be shown by the driver server executable.
110
102
/// </summary>
111
- public bool SuppressInitialDiagnosticInformation
112
- {
113
- get { return this . silent ; }
114
- set { this . silent = value ; }
115
- }
103
+ public bool SuppressInitialDiagnosticInformation { get ; set ; }
116
104
117
105
/// <summary>
118
106
/// Gets a value indicating whether the service is running.
119
107
/// </summary>
120
- public bool IsRunning
121
- {
122
- get { return this . driverServiceProcess != null && ! this . driverServiceProcess . HasExited ; }
123
- }
108
+ [ MemberNotNullWhen ( true , nameof ( driverServiceProcess ) ) ]
109
+ public bool IsRunning => this . driverServiceProcess != null && ! this . driverServiceProcess . HasExited ;
124
110
125
111
/// <summary>
126
112
/// Gets or sets a value indicating whether the command prompt window of the service should be hidden.
127
113
/// </summary>
128
- public bool HideCommandPromptWindow
129
- {
130
- get { return this . hideCommandPromptWindow ; }
131
- set { this . hideCommandPromptWindow = value ; }
132
- }
114
+ public bool HideCommandPromptWindow { get ; set ; }
133
115
134
116
/// <summary>
135
117
/// Gets the process ID of the running driver service executable. Returns 0 if the process is not running.
@@ -159,54 +141,33 @@ public int ProcessId
159
141
/// <summary>
160
142
/// Gets or sets a value indicating the time to wait for an initial connection before timing out.
161
143
/// </summary>
162
- public TimeSpan InitializationTimeout
163
- {
164
- get { return this . initializationTimeout ; }
165
- set { this . initializationTimeout = value ; }
166
- }
144
+ public TimeSpan InitializationTimeout { get ; set ; } = TimeSpan . FromSeconds ( 20 ) ;
167
145
168
146
/// <summary>
169
147
/// Gets or sets the executable file name of the driver service.
170
148
/// </summary>
171
- public string DriverServiceExecutableName
172
- {
173
- get { return this . driverServiceExecutableName ; }
174
- set { this . driverServiceExecutableName = value ; }
175
- }
149
+ public string ? DriverServiceExecutableName { get ; set ; }
176
150
177
151
/// <summary>
178
152
/// Gets or sets the path of the driver service.
179
153
/// </summary>
180
- public string DriverServicePath
181
- {
182
- get { return this . driverServicePath ; }
183
- set { this . driverServicePath = value ; }
184
- }
154
+ public string ? DriverServicePath { get ; set ; }
185
155
186
156
/// <summary>
187
157
/// Gets the command-line arguments for the driver service.
188
158
/// </summary>
189
- protected virtual string CommandLineArguments
190
- {
191
- get { return string . Format ( CultureInfo . InvariantCulture , "--port={0}" , this . driverServicePort ) ; }
192
- }
159
+ protected virtual string CommandLineArguments => string . Format ( CultureInfo . InvariantCulture , "--port={0}" , this . Port ) ;
193
160
194
161
/// <summary>
195
162
/// Gets a value indicating the time to wait for the service to terminate before forcing it to terminate.
196
163
/// </summary>
197
- protected virtual TimeSpan TerminationTimeout
198
- {
199
- get { return TimeSpan . FromSeconds ( 10 ) ; }
200
- }
164
+ protected virtual TimeSpan TerminationTimeout => TimeSpan . FromSeconds ( 10 ) ;
201
165
202
166
/// <summary>
203
167
/// Gets a value indicating whether the service has a shutdown API that can be called to terminate
204
168
/// it gracefully before forcing a termination.
205
169
/// </summary>
206
- protected virtual bool HasShutdown
207
- {
208
- get { return true ; }
209
- }
170
+ protected virtual bool HasShutdown => true ;
210
171
211
172
/// <summary>
212
173
/// Gets a value indicating whether the service is responding to HTTP requests.
@@ -231,7 +192,7 @@ protected virtual bool IsInitialized
231
192
// that the HTTP status returned is a 200 status, and that the resposne has the correct
232
193
// Content-Type header. A more sophisticated check would parse the JSON response and
233
194
// validate its values. At the moment we do not do this more sophisticated check.
234
- isInitialized = response . StatusCode == HttpStatusCode . OK && response . Content . Headers . ContentType . MediaType . StartsWith ( "application/json" , StringComparison . OrdinalIgnoreCase ) ;
195
+ isInitialized = response . StatusCode == HttpStatusCode . OK && response . Content . Headers . ContentType is { MediaType : string mediaType } && mediaType . StartsWith ( "application/json" , StringComparison . OrdinalIgnoreCase ) ;
235
196
}
236
197
}
237
198
}
@@ -256,6 +217,7 @@ public void Dispose()
256
217
/// <summary>
257
218
/// Starts the DriverService if it is not already running.
258
219
/// </summary>
220
+ [ MemberNotNull ( nameof ( driverServiceProcess ) ) ]
259
221
public void Start ( )
260
222
{
261
223
if ( this . driverServiceProcess != null )
@@ -265,9 +227,14 @@ public void Start()
265
227
266
228
this . driverServiceProcess = new Process ( ) ;
267
229
268
- if ( this . driverServicePath != null )
230
+ if ( this . DriverServicePath != null )
269
231
{
270
- this . driverServiceProcess . StartInfo . FileName = Path . Combine ( this . driverServicePath , this . driverServiceExecutableName ) ;
232
+ if ( this . DriverServiceExecutableName is null )
233
+ {
234
+ throw new InvalidOperationException ( "If the driver service path is specified, the driver service executable name must be as well" ) ;
235
+ }
236
+
237
+ this . driverServiceProcess . StartInfo . FileName = Path . Combine ( this . DriverServicePath , this . DriverServiceExecutableName ) ;
271
238
}
272
239
else
273
240
{
@@ -276,7 +243,7 @@ public void Start()
276
243
277
244
this . driverServiceProcess . StartInfo . Arguments = this . CommandLineArguments ;
278
245
this . driverServiceProcess . StartInfo . UseShellExecute = false ;
279
- this . driverServiceProcess . StartInfo . CreateNoWindow = this . hideCommandPromptWindow ;
246
+ this . driverServiceProcess . StartInfo . CreateNoWindow = this . HideCommandPromptWindow ;
280
247
281
248
DriverProcessStartingEventArgs eventArgs = new DriverProcessStartingEventArgs ( this . driverServiceProcess . StartInfo ) ;
282
249
this . OnDriverProcessStarting ( eventArgs ) ;
@@ -288,8 +255,7 @@ public void Start()
288
255
289
256
if ( ! serviceAvailable )
290
257
{
291
- string msg = "Cannot start the driver service on " + this . ServiceUrl ;
292
- throw new WebDriverException ( msg ) ;
258
+ throw new WebDriverException ( $ "Cannot start the driver service on { this . ServiceUrl } ") ;
293
259
}
294
260
}
295
261
@@ -327,10 +293,7 @@ protected void OnDriverProcessStarting(DriverProcessStartingEventArgs eventArgs)
327
293
throw new ArgumentNullException ( nameof ( eventArgs ) , "eventArgs must not be null" ) ;
328
294
}
329
295
330
- if ( this . DriverProcessStarting != null )
331
- {
332
- this . DriverProcessStarting ( this , eventArgs ) ;
333
- }
296
+ this . DriverProcessStarting ? . Invoke ( this , eventArgs ) ;
334
297
}
335
298
336
299
/// <summary>
@@ -344,10 +307,7 @@ protected void OnDriverProcessStarted(DriverProcessStartedEventArgs eventArgs)
344
307
throw new ArgumentNullException ( nameof ( eventArgs ) , "eventArgs must not be null" ) ;
345
308
}
346
309
347
- if ( this . DriverProcessStarted != null )
348
- {
349
- this . DriverProcessStarted ( this , eventArgs ) ;
350
- }
310
+ this . DriverProcessStarted ? . Invoke ( this , eventArgs ) ;
351
311
}
352
312
353
313
/// <summary>
0 commit comments