Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit f7acb70

Browse files
committed
Fix crasher
1 parent 592a1cb commit f7acb70

File tree

4 files changed

+41
-18
lines changed

4 files changed

+41
-18
lines changed

src/GitHub.App/Controllers/UIController.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ public IObservable<bool> ListenToCompletionState()
152152

153153
void End(bool success)
154154
{
155-
uiProvider.RemoveService(typeof(IConnection));
155+
uiProvider.RemoveService(typeof(IConnection), this);
156156
completion?.OnNext(success);
157157
completion?.OnCompleted();
158158
transition.OnCompleted();
@@ -228,7 +228,7 @@ public void Start([AllowNull] IConnection connection)
228228
if (connection != null)
229229
{
230230
if (currentFlow != UIControllerFlow.Authentication)
231-
uiProvider.AddService(connection);
231+
uiProvider.AddService(this, connection);
232232
else // sanity check: it makes zero sense to pass a connection in when calling the auth flow
233233
Debug.Assert(false, "Calling the auth flow with a connection makes no sense!");
234234

@@ -263,15 +263,15 @@ public void Start([AllowNull] IConnection connection)
263263
if (currentFlow != UIControllerFlow.Authentication)
264264
{
265265
if (loggedin) // register the first available connection so the viewmodel can use it
266-
uiProvider.AddService(c);
266+
uiProvider.AddService(this, c);
267267
else
268268
{
269269
// a connection will be added to the list when auth is done, register it so the next
270270
// viewmodel can use it
271271
connectionAdded = (s, e) =>
272272
{
273273
if (e.Action == NotifyCollectionChangedAction.Add)
274-
uiProvider.AddService(typeof(IConnection), e.NewItems[0]);
274+
uiProvider.AddService(typeof(IConnection), this, e.NewItems[0]);
275275
};
276276
connectionManager.Connections.CollectionChanged += connectionAdded;
277277
}

src/GitHub.Exports/Services/IUIProvider.cs

+9-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,15 @@ public interface IUIProvider : IServiceProvider
1818
object TryGetService(string typename);
1919
T TryGetService<T>() where T : class;
2020

21-
void AddService(Type t, object instance);
22-
void AddService<T>(T instance);
23-
void RemoveService(Type t);
21+
void AddService(Type t, object owner, object instance);
22+
void AddService<T>(object owner, T instance);
23+
/// <summary>
24+
/// Removes a service from the catalog
25+
/// </summary>
26+
/// <param name="t">The type we want to remove</param>
27+
/// <param name="owner">The owner, which either has to match what was passed to AddService,
28+
/// or if it's null, the service will be removed without checking for ownership</param>
29+
void RemoveService(Type t, object owner);
2430

2531
IObservable<UserControl> SetupUI(UIControllerFlow controllerFlow, IConnection connection);
2632
void RunUI();

src/GitHub.VisualStudio/Services/UIProvider.cs

+27-10
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,17 @@ namespace GitHub.VisualStudio
2626
[PartCreationPolicy(CreationPolicy.Shared)]
2727
public class UIProvider : IUIProvider, IDisposable
2828
{
29+
class OwnedComposablePart
30+
{
31+
public object Owner { get; set; }
32+
public ComposablePart Part { get; set; }
33+
}
34+
2935
static readonly Logger log = LogManager.GetCurrentClassLogger();
3036
CompositeDisposable disposables = new CompositeDisposable();
3137
readonly IServiceProvider serviceProvider;
3238
CompositionContainer tempContainer;
33-
readonly Dictionary<string, ComposablePart> tempParts;
39+
readonly Dictionary<string, OwnedComposablePart> tempParts;
3440
ExportLifetimeContext<IUIController> currentUIFlow;
3541
readonly Version currentVersion;
3642
bool initializingLogging = false;
@@ -72,7 +78,7 @@ public UIProvider([Import(typeof(SVsServiceProvider))] IServiceProvider serviceP
7278
{
7379
SourceProvider = ExportProvider
7480
}));
75-
tempParts = new Dictionary<string, ComposablePart>();
81+
tempParts = new Dictionary<string, OwnedComposablePart>();
7682
}
7783

7884
[return: AllowNull]
@@ -152,12 +158,12 @@ public Ret GetService<T, Ret>() where Ret : class
152158
return GetService<T>() as Ret;
153159
}
154160

155-
public void AddService<T>(T instance)
161+
public void AddService<T>(object owner, T instance)
156162
{
157-
AddService(typeof(T), instance);
163+
AddService(typeof(T), owner, instance);
158164
}
159165

160-
public void AddService(Type t, object instance)
166+
public void AddService(Type t, object owner, object instance)
161167
{
162168
if (!Initialized)
163169
{
@@ -168,13 +174,23 @@ public void AddService(Type t, object instance)
168174
var batch = new CompositionBatch();
169175
string contract = AttributedModelServices.GetContractName(t);
170176
Debug.Assert(!string.IsNullOrEmpty(contract), "Every type must have a contract name");
177+
178+
// we want to remove stale instances of a service, if they exist, regardless of who put them there
179+
RemoveService(t, null);
180+
171181
var part = batch.AddExportedValue(contract, instance);
172182
Debug.Assert(part != null, "Adding an exported value must return a non-null part");
173-
tempParts.Add(contract, part);
183+
tempParts.Add(contract, new OwnedComposablePart { Owner = owner, Part = part });
174184
tempContainer.Compose(batch);
175185
}
176186

177-
public void RemoveService(Type t)
187+
/// <summary>
188+
/// Removes a service from the catalog
189+
/// </summary>
190+
/// <param name="t">The type we want to remove</param>
191+
/// <param name="owner">The owner, which either has to match what was passed to AddService,
192+
/// or if it's null, the service will be removed without checking for ownership</param>
193+
public void RemoveService(Type t, [AllowNull] object owner)
178194
{
179195
if (!Initialized)
180196
{
@@ -185,13 +201,14 @@ public void RemoveService(Type t)
185201
string contract = AttributedModelServices.GetContractName(t);
186202
Debug.Assert(!string.IsNullOrEmpty(contract), "Every type must have a contract name");
187203

188-
ComposablePart part;
189-
204+
OwnedComposablePart part;
190205
if (tempParts.TryGetValue(contract, out part))
191206
{
207+
if (owner != null && part.Owner != owner)
208+
return;
192209
tempParts.Remove(contract);
193210
var batch = new CompositionBatch();
194-
batch.RemovePart(part);
211+
batch.RemovePart(part.Part);
195212
tempContainer.Compose(batch);
196213
}
197214
}

src/UnitTests/GitHub.App/Controllers/UIControllerTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public void CloneDialogLoggedInWithoutConnection()
124124
{
125125
Assert.Equal(1, list.Count);
126126
Assert.IsAssignableFrom<IViewFor<IRepositoryCloneViewModel>>(list[0]);
127-
((IUIProvider)provider).Received().AddService(connection);
127+
((IUIProvider)provider).Received().AddService(uiController, connection);
128128
});
129129
uiController.Start(null);
130130
}

0 commit comments

Comments
 (0)