Skip to content

Commit 255a164

Browse files
committed
Fix up acrolinx score to 80+ for changed documents
1 parent 5a214e1 commit 255a164

File tree

2 files changed

+51
-52
lines changed

2 files changed

+51
-52
lines changed

docs/extensibility/how-to-consume-brokered-service.md

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ With all code in this document, activating C#'s [nullable reference types](/dotn
2121
## Retrieving an IServiceBroker
2222

2323
To acquire a brokered service, you must first have an instance of <xref:Microsoft.ServiceHub.Framework.IServiceBroker>.
24-
When your code is running in the context of MEF or a VS Package, you typically want the global service broker.
24+
When your code is running in the context of MEF (Managed Extensibility Framework) or a VSPackage, you typically want the global service broker.
2525

26-
Brokered services themselves should use the <xref:Microsoft.ServiceHub.Framework.IServiceBroker> that they are assigned when their [service factory](xref:Microsoft.VisualStudio.Shell.ServiceBroker.BrokeredServiceFactory) is invoked.
26+
Brokered services themselves should use the <xref:Microsoft.ServiceHub.Framework.IServiceBroker> that they're assigned when their [service factory](xref:Microsoft.VisualStudio.Shell.ServiceBroker.BrokeredServiceFactory) is invoked.
2727

2828
### The global service broker
2929

@@ -36,7 +36,7 @@ IBrokeredServiceContainer container = await AsyncServiceProvider.GlobalProvider.
3636
IServiceBroker serviceBroker = container.GetFullAccessServiceBroker();
3737
```
3838

39-
Starting with Visual Studio 2022, code running in a MEF activated extension may import the global service broker:
39+
Starting with Visual Studio 2022, code running in a MEF activated extension can import the global service broker:
4040

4141
```cs
4242
[Import(typeof(SVsFullAccessServiceBroker))]
@@ -51,8 +51,8 @@ We recommend that each client/class in your extension acquire its own service br
5151
This pattern also encourages secure coding patterns where a brokered service should *not* be using the global service broker.
5252

5353
> [!IMPORTANT]
54-
> Implementations of <xref:Microsoft.ServiceHub.Framework.IServiceBroker> do not typically implement <xref:System.IDisposable>, but these objects cannot be collected while <xref:Microsoft.ServiceHub.Framework.IServiceBroker.AvailabilityChanged> handlers exist.
55-
Be sure to balance add/remove of event handlers, especially when the code may discard the service broker during the lifetime of the process.
54+
> Implementations of <xref:Microsoft.ServiceHub.Framework.IServiceBroker> do not typically implement <xref:System.IDisposable>, but these objects can't be collected while <xref:Microsoft.ServiceHub.Framework.IServiceBroker.AvailabilityChanged> handlers exist.
55+
Be sure to balance add/remove of event handlers, especially when the code might discard the service broker during the lifetime of the process.
5656

5757
### Context specific service brokers
5858

@@ -80,28 +80,28 @@ using (myService as IDisposable)
8080
}
8181
```
8282

83-
As with all brokered service requests, the above code will activate a new instance of a brokered service.
84-
After using the service, the code above disposes of the proxy as execution exits the `using` block.
83+
As with all brokered service requests, the preceding code activates a new instance of a brokered service.
84+
After using the service, the preceding code disposes of the proxy as execution exits the `using` block.
8585

8686
> [!IMPORTANT]
87-
> Every proxy retrieved must be disposed of, *even if the service interface does not derive from <xref:System.IDisposable>*.
87+
> Every proxy retrieved must be disposed of, *even if the service interface doesn't derive from <xref:System.IDisposable>*.
8888
> Disposal is important because the proxy often has I/O resources backing it that prevent it from being garbage collected.
8989
> Disposal terminates the I/O, allowing the proxy to be garbage collected.
9090
> Use a conditional cast to <xref:System.IDisposable> for disposal and be prepared for the cast to fail to avoid an exception for `null` proxies or proxies that do not actually implement <xref:System.IDisposable>.
9191
9292
Be sure to install the latest [Microsoft.ServiceHub.Analyzers](https://www.nuget.org/packages/Microsoft.ServiceHub.Analyzers) NuGet package and keep the ISBxxxx analyzer rules enabled to help prevent such leaks.
9393

94-
Disposal of the proxy will result in disposal of the brokered service that was dedicated to that client.
94+
Disposal of the proxy results in disposal of the brokered service that was dedicated to that client.
9595

96-
If your code requires a brokered service and cannot complete its work when the service is not available, you may want to display an error dialog to the user if the code owns the user experience rather than throw an exception.
96+
If your code requires a brokered service and can't complete its work when the service isn't available, you might display an error dialog to the user if the code owns the user experience rather than throw an exception.
9797

9898
### Client RPC targets
9999

100-
Some brokered services accept or require a client RPC target for "callbacks".
100+
Some brokered services accept or require a client RPC (Remote Procedure Call) target for "callbacks."
101101
Such an option or requirement should be in the documentation of that particular brokered service.
102102
For Visual Studio brokered services this information should be included in the IntelliSense documentation on the descriptor.
103103

104-
In such case, a client may provide one using <xref:Microsoft.ServiceHub.Framework.ServiceActivationOptions.ClientRpcTarget?displayProperty=nameWithType> like this:
104+
In such case, a client can provide one using <xref:Microsoft.ServiceHub.Framework.ServiceActivationOptions.ClientRpcTarget?displayProperty=nameWithType> like this:
105105

106106
```csharp
107107
IMyService? myService = await broker.GetProxyAsync<IMyService>(
@@ -120,7 +120,7 @@ This proxy forwards calls and events each direction, with some important differe
120120

121121
### Observer pattern
122122

123-
If the service contract takes parameters of type <xref:System.IObserver%601>, you may learn more about how to construct such a type at [How to implement an observer](/dotnet/standard/events/how-to-implement-an-observer).
123+
If the service contract takes parameters of type <xref:System.IObserver%601>, you can learn more about how to construct such a type at [How to implement an observer](/dotnet/standard/events/how-to-implement-an-observer).
124124

125125
An <xref:System.Threading.Tasks.Dataflow.ActionBlock%601> can be adapted to implement <xref:System.IObserver%601> with the <xref:System.Threading.Tasks.Dataflow.DataflowBlock.AsObserver%2A> extension method.
126126
The [System.Reactive.Observer](/previous-versions/dotnet/reactive-extensions/hh229899(v=vs.103)) class from the Reactive framework is another alternative to implementing the interface yourself.
@@ -130,15 +130,15 @@ The [System.Reactive.Observer](/previous-versions/dotnet/reactive-extensions/hh2
130130
- Expect <xref:StreamJsonRpc.RemoteInvocationException> to be thrown for any exception thrown from the brokered service. The original exception can be found in the <xref:System.Exception.InnerException%2A>.
131131
This is natural behavior for a remotely hosted service because it is behavior from <xref:StreamJsonRpc.JsonRpc>.
132132
When the service is local, the local proxy wraps all exceptions in the same way so that the client code can have just one exception path that works for local and remote services.
133-
- Check the <xref:StreamJsonRpc.RemoteInvocationException.ErrorCode%2A> property if the service documentation suggests that specific codes will be set based on specific conditions that you can branch on.
133+
- Check the <xref:StreamJsonRpc.RemoteInvocationException.ErrorCode%2A> property if the service documentation suggests that specific codes are set based on specific conditions that you can branch on.
134134
- A broader set of errors is communicated by catching <xref:StreamJsonRpc.RemoteRpcException>, which is the base type for the <xref:StreamJsonRpc.RemoteInvocationException>.
135135
- Expect <xref:StreamJsonRpc.ConnectionLostException> to be thrown from any call when the connection to a remote service drops or the process hosting the service crashes.
136-
This is primarily of concern when the service may be acquired remotely.
136+
This is primarily of concern when the service can be acquired remotely.
137137

138138
## Caching of the proxy
139139

140140
There is some expense in the activation of a brokered service and associated proxy, particularly when the service comes from a remote process.
141-
When frequent use of a brokered service warrants caching of the proxy across many calls into a class, the proxy may be stored in a field on that class.
141+
When frequent use of a brokered service warrants caching of the proxy across many calls into a class, the proxy can be stored in a field on that class.
142142
The containing class should be disposable and dispose of the proxy inside its `Dispose` method.
143143
Consider this example:
144144

@@ -171,8 +171,8 @@ class MyExtension : IDisposable
171171
}
172172
```
173173

174-
The above code is roughly correct, but it does not account for race conditions between `Dispose` and `SayHiAsync`.
175-
The code also does not account for <xref:Microsoft.ServiceHub.Framework.IServiceBroker.AvailabilityChanged> events that should lead to disposal of the proxy previously acquired and the reacquisition of the proxy the next time it is required.
174+
The preceding code is roughly correct, but it doesn't account for race conditions between `Dispose` and `SayHiAsync`.
175+
The code also doesn't account for <xref:Microsoft.ServiceHub.Framework.IServiceBroker.AvailabilityChanged> events that should lead to disposal of the proxy previously acquired and the reacquisition of the proxy the next time it's required.
176176

177177
The <xref:Microsoft.ServiceHub.Framework.ServiceBrokerClient> class is designed to handle these race and invalidation conditions to help keep your own code simple.
178178
Consider this updated example that caches the proxy using this helper class:
@@ -204,7 +204,7 @@ class MyExtension : IDisposable
204204
}
205205
```
206206

207-
The above code is still responsible to dispose of the <xref:Microsoft.ServiceHub.Framework.ServiceBrokerClient> and each rental of a proxy.
207+
The preceding code is still responsible to dispose of the <xref:Microsoft.ServiceHub.Framework.ServiceBrokerClient> and each rental of a proxy.
208208
Race conditions between disposal and use of the proxy are handled by the <xref:Microsoft.ServiceHub.Framework.ServiceBrokerClient> object, which will dispose of each cached proxy at the time of its own disposal or when the last rental of that proxy has been released, whichever comes last.
209209

210210
### Important caveats regarding the `ServiceBrokerClient`
@@ -217,7 +217,7 @@ Consider using <xref:Microsoft.ServiceHub.Framework.IServiceBroker> directly in
217217
The proxy is already cached beyond the scope of one method by the <xref:Microsoft.ServiceHub.Framework.ServiceBrokerClient>.
218218
If you need greater control over the lifetime of the proxy, particularly around reacquisition due to an <xref:Microsoft.ServiceHub.Framework.IServiceBroker.AvailabilityChanged> event, use <xref:Microsoft.ServiceHub.Framework.IServiceBroker> directly instead and store the service proxy in a field.
219219

220-
- Create and store <xref:Microsoft.ServiceHub.Framework.ServiceBrokerClient> to a field rather than a local variable. If you create and use it as a local variable in a method, it is not adding any value over using <xref:Microsoft.ServiceHub.Framework.IServiceBroker> directly, but now you have to dispose of two objects (the client and the rental) instead of one (the service).
220+
- Create and store <xref:Microsoft.ServiceHub.Framework.ServiceBrokerClient> to a field rather than a local variable. If you create and use it as a local variable in a method, it's not adding any value over using <xref:Microsoft.ServiceHub.Framework.IServiceBroker> directly, but now you have to dispose of two objects (the client and the rental) instead of one (the service).
221221

222222
### Choosing between IServiceBroker and ServiceBrokerClient
223223

@@ -227,14 +227,13 @@ Category| <xref:Microsoft.ServiceHub.Framework.IServiceBroker> | <xref:Microsoft
227227
--|--|--
228228
User friendly|Yes|Yes
229229
Requires disposal|No|Yes
230-
Manages lifetime of proxy|No. Owner must dispose of proxy when done using it.|Yes, they are kept alive and reused as long as they are valid.
230+
Manages lifetime of proxy|No. Owner must dispose of proxy when done using it.|Yes, they're kept alive and reused as long as they're valid.
231231
Applicable for stateless services|Yes|Yes
232232
Applicable for stateful services|Yes|No
233233
Appropriate when event handlers are added to proxy|Yes|No
234234
Event to notify when old proxy is invalidated| <xref:Microsoft.ServiceHub.Framework.IServiceBroker.AvailabilityChanged> | <xref:Microsoft.ServiceHub.Framework.ServiceBrokerClient.Invalidated>
235235

236236
<xref:Microsoft.ServiceHub.Framework.ServiceBrokerClient> provides a convenient means for you to get fast and frequent reuse of a proxy, where you don't care if the underlying service is changed out from under you in between top-level operations.
237-
238237
But if you do care about those things and want to manage the lifetime of your proxies yourself, or you need event handlers (which implies you need to manage lifetime of the proxy), you should use <xref:Microsoft.ServiceHub.Framework.IServiceBroker>.
239238

240239
## Resilience to service disruptions
@@ -249,17 +248,17 @@ There are a few kinds of service disruptions that are possible with brokered ser
249248

250249
When a brokered service request can be satisfied by an available service but the service factory throws an unhandled exception, a <xref:Microsoft.ServiceHub.Framework.ServiceActivationFailedException> is thrown back to the client so they can understand and report the failure to the user.
251250

252-
When a brokered service request cannot be matched up with any available service, `null` is returned to the client.
251+
When a brokered service request can't be matched up with any available service, `null` is returned to the client.
253252
In such a case, <xref:Microsoft.ServiceHub.Framework.IServiceBroker.AvailabilityChanged> will be raised when and if that service becomes available later.
254253

255-
The service request may be declined not because the service isn't there, but because the version offered is lower than the version requested.
256-
Your fallback plan may include retrying the service request with lower versions that your client knows exist and is able to interact with.
254+
The service request might be declined not because the service isn't there, but because the version offered is lower than the version requested.
255+
Your fallback plan might include retrying the service request with lower versions that your client knows exist and is able to interact with.
257256

258257
If/when latency from all the failed version checks becomes noticeable, the client can request the VisualStudioServices.VS2019_4Services.RemoteBrokeredServiceManifest to get a complete idea of what services and versions are available from a remote source.
259258

260259
### <a name="DroppedConnections"></a> Handling dropped connections
261260

262-
A successfully acquired brokered service proxy may fail due to a dropped connection or a crash in the process that hosts it.
261+
A successfully acquired brokered service proxy might fail due to a dropped connection or a crash in the process that hosts it.
263262
After such a disruption, any call made on that proxy will result in <xref:StreamJsonRpc.ConnectionLostException> being thrown.
264263

265264
A brokered service client can proactively detect and react to such connection drops by handling the <xref:StreamJsonRpc.JsonRpc.Disconnected> event.
@@ -283,15 +282,15 @@ void JsonRpc_Disconnected(object? sender, JsonRpcDisconnectedEventArgs args)
283282

284283
### <a name="ServiceAvailabilityChanges"></a> Handling service availability changes
285284

286-
Brokered service clients may receive notifications of when they should requery for a brokered service they previously queried for by handling the <xref:Microsoft.ServiceHub.Framework.IServiceBroker.AvailabilityChanged> event.
287-
Handlers to this event should be added *before* requesting a brokered service to ensure an event raised soon after a service request is made is not lost due to a race condition.
285+
Brokered service clients can receive notifications of when they should requery for a brokered service they previously queried for by handling the <xref:Microsoft.ServiceHub.Framework.IServiceBroker.AvailabilityChanged> event.
286+
Handlers to this event should be added *before* requesting a brokered service to ensure an event raised soon after a service request is made isn't lost due to a race condition.
288287

289-
When a brokered service is requested only for the duration of one async method's execution, handling this event is not recommended.
288+
When a brokered service is requested only for the duration of one async method's execution, handling this event isn't recommended.
290289
The event is most relevant to clients that store their proxy for extended periods such that they would need to compensate for service changes and are in a position to refresh their proxy.
291290

292-
This event may be raised on any thread, possibly concurrently to code that is using a service that the event is describing.
291+
This event can be raised on any thread, possibly concurrently to code that is using a service that the event is describing.
293292

294-
Several state changes may lead to raising of this event, including:
293+
Several state changes can lead to raising of this event, including:
295294

296295
- A solution or folder being opened or closed.
297296
- A Live Share session starting.
@@ -302,13 +301,13 @@ An impacted brokered service only results in this event being raised to clients
302301
The event is raised at most once per service after each request for that service.
303302
For example if the client requests service **A** and service **B** experiences an availability change, no event will be raised to that client.
304303
Later, when service **A** experiences an availability change, the client will receive the event.
305-
If the client does not re-request service **A**, subsequent availability changes for **A** will not result in any further notifications to that client.
304+
If the client doesn't re-request service **A**, subsequent availability changes for **A** will not result in any further notifications to that client.
306305
Once the client requests **A** again, it becomes eligible to receive the next notification regarding that service.
307306

308307
The event is raised when a service becomes available, is no longer available, or experiences an implementation change that requires all prior service clients to requery for the service.
309308

310309
The <xref:Microsoft.ServiceHub.Framework.ServiceBrokerClient> handles availability change events regarding cached proxies automatically by disposing of the old proxies when any rentals have been returned and requesting a new instance of the service when and if its owner requests one.
311-
This class can substantially simplify your code when the service is stateless and does not require that your code attaches event handlers to the proxy.
310+
This class can substantially simplify your code when the service is stateless and doesn't require that your code attaches event handlers to the proxy.
312311

313312
## Retrieving a brokered service pipe
314313

@@ -318,7 +317,7 @@ A pipe to the brokered service may be obtained via the <xref:Microsoft.ServiceHu
318317
This method takes a <xref:Microsoft.ServiceHub.Framework.ServiceMoniker> instead of a <xref:Microsoft.ServiceHub.Framework.ServiceRpcDescriptor> because the RPC behaviors provided by a descriptor are not required.
319318
When you have a descriptor, you can obtain the moniker from it via the <xref:Microsoft.ServiceHub.Framework.ServiceRpcDescriptor.Moniker%2A?displayProperty=nameWithType> property.
320319

321-
While pipes are bound to I/O they are not eligible for garbage collection.
320+
While pipes are bound to I/O they're not eligible for garbage collection.
322321
Avoid memory leaks by always completing these pipes when they will no longer be used.
323322

324323
In the following snippet, a brokered service is activated and the client has a direct pipe to it.
@@ -372,7 +371,7 @@ Mock<IFileSystem> mockFileSystem = new Mock<IFileSystem>();
372371
sbc.Proffer(VisualStudioServices.VS2022.FileSystem, (ServiceMoniker moniker, ServiceActivationOptions options, IServiceBroker serviceBroker, CancellationToken cancellationToken) => new ValueTask<object?>(mockFileSystem.Object));
373372
```
374373

375-
The mocked brokered service container does not require a proffered service to be registered first as Visual Studio itself does.
374+
The mocked brokered service container doesn't require a proffered service to be registered first as Visual Studio itself does.
376375

377376
Your code under test can acquire the brokered service as normal, except that under the test it will get your mock instead of the real one it would get while running under Visual Studio:
378377

0 commit comments

Comments
 (0)