Skip to content

Commit 82b3e3b

Browse files
committed
Fixed HttpClient Injection which was slightly broken with a hard reference
1 parent 83cacb4 commit 82b3e3b

File tree

7 files changed

+80
-30
lines changed

7 files changed

+80
-30
lines changed

src/BlazorWorker.Demo/Client/Pages/CoreExample.razor

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@
9494
var result = double.Parse(message.Substring($"{CoreMathsService.ResultMessage}:".Length).Trim());
9595
output += $"{rn}{LogDate()} EstimatePI({piIterations}) = {result}";
9696
StateHasChanged();
97-
StateHasChanged();
9897
}
9998
}
10099

src/BlazorWorker.Demo/Client/Pages/Http.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
sw.Start();
5454
backgroundService = await worker.CreateBackgroundServiceAsync<WebCallerService>(
5555
options => options
56-
.UseConventionalServiceAssembly()
56+
.AddConventionalAssemblyOfService()
5757
.AddHttpClient()
5858
);
5959

src/BlazorWorker.ServiceFactory/WorkerBackgroundServiceExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public static async Task<IWorkerBackgroundService<T>> CreateBackgroundServiceAsy
2222
var proxy = new WorkerBackgroundServiceProxy<T>(webWorkerProxy, new WebWorkerOptions());
2323
if (workerInitOptions == null)
2424
{
25-
workerInitOptions = new WorkerInitOptions().AddConventionalDependencyFor<T>();
25+
workerInitOptions = new WorkerInitOptions().AddAssemblyOf<T>();
2626
}
2727

2828
await proxy.InitAsync(workerInitOptions);

src/BlazorWorker.ServiceFactory/WorkerBackgroundServiceProxy.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,9 @@ public async Task InitAsync(WorkerInitOptions workerInitOptions = null)
9898
{
9999
initWorkerTask = new TaskCompletionSource<bool>();
100100

101-
if (workerInitOptions.ConventionalServiceAssembly)
101+
if (workerInitOptions.UseConventionalServiceAssembly)
102102
{
103-
workerInitOptions.AddConventionalDependencyFor<T>();
103+
workerInitOptions.AddAssemblyOf<T>();
104104
}
105105

106106
await this.worker.InitAsync(new WorkerInitOptions() {

src/BlazorWorker.WorkerCore/BlazorWorker.WorkerCore.xml

Lines changed: 15 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/BlazorWorker.WorkerCore/InitOptions.cs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public WorkerInitOptions()
4040
/// <summary>
4141
/// If set to true, deducts the name of the assembly containing the service using the service type assembly name + dll extension as file name, and adds it as a dependency.
4242
/// </summary>
43-
public bool ConventionalServiceAssembly { get; set; }
43+
public bool UseConventionalServiceAssembly { get; set; }
4444

4545
public WorkerInitOptions MergeWith(WorkerInitOptions initOptions)
4646
{
@@ -52,7 +52,7 @@ public WorkerInitOptions MergeWith(WorkerInitOptions initOptions)
5252
.Concat(initOptions.DependentAssemblyFilenames)
5353
.Distinct()
5454
.ToArray(),
55-
ConventionalServiceAssembly = initOptions.ConventionalServiceAssembly,
55+
UseConventionalServiceAssembly = initOptions.UseConventionalServiceAssembly,
5656
MessageEndPoint = initOptions.MessageEndPoint ?? this.MessageEndPoint,
5757
InitEndPoint = initOptions.InitEndPoint ?? this.InitEndPoint,
5858
};
@@ -64,40 +64,51 @@ public WorkerInitOptions MergeWith(WorkerInitOptions initOptions)
6464
/// </summary>
6565
public static class WorkerInitOptionsExtensions
6666
{
67+
6768
/// <summary>
68-
/// Deducts the name of the assembly containing the service using the the service type assembly name + dll extension as file name, and adds it as a dependency.
69+
/// Adds the specified assembly filesnames as dependencies
6970
/// </summary>
7071
/// <param name="source"></param>
72+
/// <param name="dependentAssemblyFilenames"></param>
7173
/// <returns></returns>
72-
public static WorkerInitOptions UseConventionalServiceAssembly(this WorkerInitOptions source)
74+
public static WorkerInitOptions AddAssemblies(this WorkerInitOptions source, params string[] dependentAssemblyFilenames)
7375
{
74-
source.ConventionalServiceAssembly = true;
76+
source.DependentAssemblyFilenames =
77+
source.DependentAssemblyFilenames.Concat(dependentAssemblyFilenames).ToArray();
7578
return source;
7679
}
7780

7881
/// <summary>
79-
/// Deducts the name of the assembly containing the specified type using the assembly name with dll extension as file name, and adds it as a dependency.
82+
/// Deducts the name of the assembly containing the service using the the service type assembly name with dll extension as file name, and adds it as a dependency.
8083
/// </summary>
8184
/// <param name="source"></param>
8285
/// <returns></returns>
83-
public static WorkerInitOptions AddConventionalDependencyFor<T>(this WorkerInitOptions source)
86+
public static WorkerInitOptions AddConventionalAssemblyOfService(this WorkerInitOptions source)
8487
{
85-
source.DependentAssemblyFilenames =
86-
source.DependentAssemblyFilenames.Concat(new[] {$"{typeof(T).Assembly.GetName().Name}.dll" }).ToArray();
88+
source.UseConventionalServiceAssembly = true;
89+
return source;
90+
}
91+
92+
/// <summary>
93+
/// Deducts the name of the assembly containing the specified <typeparamref name="T"/> using the assembly name with dll extension as file name, and adds it as a dependency.
94+
/// </summary>
95+
/// <param name="source"></param>
96+
/// <returns></returns>
97+
public static WorkerInitOptions AddAssemblyOf<T>(this WorkerInitOptions source)
98+
{
99+
source.AddAssemblies($"{typeof(T).Assembly.GetName().Name}.dll");
87100
return source;
88101
}
89102

90103
/// <summary>
91-
/// Registers the neccessary dependencies for instanciating <see cref="System.Net.Http.HttpClient"/> in the background service.
104+
/// Registers the neccessary dependencies for injecting or instanciating <see cref="System.Net.Http.HttpClient"/> in the background service.
92105
/// </summary>
93106
/// <param name="source"></param>
94107
/// <returns></returns>
108+
/// <remarks>When this method has been called, <see cref="System.Net.Http.HttpClient"/> can be used inside the service either by instanciating it or by injection into the constructor.</remarks>
95109
public static WorkerInitOptions AddHttpClient(this WorkerInitOptions source)
96110
{
97-
source.DependentAssemblyFilenames =
98-
source.DependentAssemblyFilenames.Concat(new[] {
99-
"System.Net.Http.dll",
100-
"System.Net.Http.WebAssemblyHttpHandler.dll" }).ToArray();
111+
source.AddAssemblies("System.Net.Http.dll", "System.Net.Http.WebAssemblyHttpHandler.dll");
101112
return source;
102113
}
103114
}

src/BlazorWorker.WorkerCore/SimpleInstanceService/SimpleInstanceService.cs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,24 @@ public class SimpleInstanceService
1212

1313
public static readonly SimpleInstanceService Instance = new SimpleInstanceService();
1414
public readonly Dictionary<long, InstanceWrapper> instances = new Dictionary<long, InstanceWrapper>();
15-
15+
1616
public static readonly string MessagePrefix = $"{typeof(SimpleInstanceService).FullName}::";
1717
public static readonly string InitServiceResultMessagePrefix = $"{nameof(InitServiceResult)}::";
1818
public static readonly string InitInstanceMessagePrefix = $"{nameof(InitInstance)}::";
1919
public static readonly string InitInstanceResultMessagePrefix = $"{nameof(InitInstanceResult)}::";
2020
public static readonly string DiposeMessagePrefix = $"{nameof(DisposeInstance)}::";
2121
public static readonly string DiposeResultMessagePrefix = $"{nameof(DisposeResult)}::";
2222

23+
private static Type _typeOfHttpClient;
24+
private const string HttpClientFullName = "System.Net.Http.HttpClient, System.Net.Http";
25+
26+
// The type of HttpClient is lazy loaded as the image might not exist
27+
private static Type TypeOfHttpClient() =>
28+
_typeOfHttpClient ??= Type.GetType(HttpClientFullName, true);
29+
30+
private static object HttpClientFactory() =>
31+
Activator.CreateInstance(TypeOfHttpClient());
32+
2333
static SimpleInstanceService()
2434
{
2535
AppDomain.CurrentDomain.AssemblyResolve += LogFailedAssemblyResolve;
@@ -133,19 +143,37 @@ public DisposeResult DisposeInstance(DisposeInstanceRequest request)
133143
}
134144
}
135145

136-
private class ServiceCollection: Dictionary<Type, Func<object>>
146+
private class ServiceCollection : Dictionary<string, Func<object>>
137147
{
148+
138149
public void Add<T>(Func<T> factory)
139150
{
140-
this.Add(typeof(T), () => factory());
151+
this.Add(GetQualifiedNameWithoutVersion(typeof(T)), () => factory());
152+
}
153+
154+
internal bool ContainsKey(Type parameterType)
155+
{
156+
Console.WriteLine($"ContainsKey {GetQualifiedNameWithoutVersion(parameterType)}?");
157+
Console.WriteLine($"Keys: {string.Join(';', this.Keys)}");
158+
return this.ContainsKey(GetQualifiedNameWithoutVersion(parameterType));
159+
}
160+
161+
internal Func<object> GetFactory(Type parameterType)
162+
{
163+
return this[GetQualifiedNameWithoutVersion(parameterType)];
164+
}
165+
166+
private string GetQualifiedNameWithoutVersion(Type forType)
167+
{
168+
return $"{forType.FullName}, {forType.Assembly.GetName().Name}";
141169
}
142170
}
143171

144172
private static InitInstanceResult InitInstance(long callId, string typeName, string assemblyName, Func<IWorkerMessageService> workerMessageServiceFactory)
145173
{
146174
var services = new ServiceCollection
147175
{
148-
() => new HttpClient(),
176+
{ HttpClientFullName, HttpClientFactory },
149177
workerMessageServiceFactory
150178
};
151179

@@ -158,6 +186,7 @@ private static InitInstanceResult InitInstance(long callId, string typeName, str
158186
foreach (var constructor in constructors)
159187
{
160188
var parameters = constructor.GetParameters();
189+
// Will favour the contructor with the highest count of supported arguments
161190
if (lastMatchArgCount < parameters.Length)
162191
{
163192
if (parameters.All(parameter => services.ContainsKey(parameter.ParameterType)))
@@ -174,7 +203,7 @@ private static InitInstanceResult InitInstance(long callId, string typeName, str
174203
}
175204

176205
// Create instances for each constructor argument matching a supported service.
177-
var serviceInstances = constructorInfo.GetParameters().Select(parameter => services[parameter.ParameterType].Invoke()).ToArray();
206+
var serviceInstances = constructorInfo.GetParameters().Select(parameter => services.GetFactory(parameter.ParameterType).Invoke()).ToArray();
178207

179208
var instance = constructorInfo.Invoke(serviceInstances);
180209

@@ -198,10 +227,12 @@ private static InitInstanceResult InitInstance(long callId, string typeName, str
198227
}
199228
}
200229

230+
201231
private static Assembly LogFailedAssemblyResolve(object sender, ResolveEventArgs args)
202232
{
203233
Console.Error.WriteLine($"{typeof(SimpleInstanceService).FullName}: '{args.RequestingAssembly}' is requesting missing assembly '{args.Name}')");
204234

235+
//return null;
205236
// Nobody really cares about this exception for now, it can't be caught.
206237
throw new InvalidOperationException($"{typeof(SimpleInstanceService).FullName}: '{args.RequestingAssembly}' is requesting missing assembly '{args.Name}')");
207238
}

0 commit comments

Comments
 (0)