My WPF Application instance implements a custom interface, but second DLL doesn't see the interface

I have an application written in WPF where one of the assemblies needs an System.Net.Http.HttpClient instance. The MSDN documentation says to have only one instance for your entire application. But I was using the client an assembly, here called MyDLL that wasn't the application's assembly. So I put in my application class a reference to a custom interface, IHttpClientOwner that's declared in an assembly that both projects can reference. (Otherwise, I'd get a circular reference.) I thought I'd find when the class inside MyDLL checks System.Windows.Application.Current, it would find IHttpClientOwner was implemented. But no. It isn't. What's going on?
87 Replies
JakenVeina
JakenVeina14mo ago
The MSDN documentation says to have only one instance for your entire application
That's a very naive understanding of the underlying problem. Give this a read. https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
Use IHttpClientFactory to implement resilient HTTP requests - .NET
Learn how to use IHttpClientFactory, available since .NET Core 2.1, for creating HttpClient instances, making it easy for you to use it in your applications.
JakenVeina
JakenVeina14mo ago
I thought I'd find when the class inside MyDLL checks System.Windows.Application.Current
does your you System.Windows.Application subclass implement this interface? is this code getting called when your WPF app is the entry point?
Will Pittenger
Will PittengerOP14mo ago
Yes it does. Well, the App class implements the interface. But no constructor is called.
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
Will Pittenger
Will PittengerOP14mo ago
Don't have a repository online
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
Will Pittenger
Will PittengerOP14mo ago
Well, I don't see how the IHttpClientFactory helps. First, I need a link to an interface. But where do I get that. Your page doesn't describe that. Then if I'm asking the factory to make new clients all the time, how is that different from just creating a HttpClient yourself?
JakenVeina
JakenVeina14mo ago
is this code getting called when your WPF app is the entry point?
Will Pittenger
Will PittengerOP14mo ago
No. I said that. It's the only app.
JakenVeina
JakenVeina14mo ago
what app?
Will Pittenger
Will PittengerOP14mo ago
In my project.
JakenVeina
JakenVeina14mo ago
which one?
Will Pittenger
Will PittengerOP14mo ago
What do you mean which one?
JakenVeina
JakenVeina14mo ago
you said you have two apps, yes? plus a third shared library
Will Pittenger
Will PittengerOP14mo ago
No. I have two proejcts. One is a DLL.
JakenVeina
JakenVeina14mo ago
which are what? they're all DLLs
Will Pittenger
Will PittengerOP14mo ago
The DLL isn't an application.
JakenVeina
JakenVeina14mo ago
so, what is it?
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
JakenVeina
JakenVeina14mo ago
???
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
Will Pittenger
Will PittengerOP14mo ago
Now I'm lost.
JakenVeina
JakenVeina14mo ago
me too
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
JakenVeina
JakenVeina14mo ago
what two projects do you have
MODiX
MODiX14mo ago
Will Pittenger
The DLL isn't an application.
React with ❌ to remove this embed.
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
Will Pittenger
Will PittengerOP14mo ago
C#
public partial class App : System.Windows.Application, Platform.HttpClientOwner.IHttpClientOwner
{
private static readonly System.Net.Http.HttpClient client = new();

public System.Net.Http.HttpClient HttpClient => client;
}
C#
public partial class App : System.Windows.Application, Platform.HttpClientOwner.IHttpClientOwner
{
private static readonly System.Net.Http.HttpClient client = new();

public System.Net.Http.HttpClient HttpClient => client;
}
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
Will Pittenger
Will PittengerOP14mo ago
I don't have a repository.
JakenVeina
JakenVeina14mo ago
personally, I have 0 interest in pouring over an entire repository of code, and I do not want to encourage that as a legit way to get help define the problem and answer some basic straightforward relevant questions
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
JakenVeina
JakenVeina14mo ago
I think it probably is
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
JakenVeina
JakenVeina14mo ago
I think he doesn't understand what an entry point is
Will Pittenger
Will PittengerOP14mo ago
C#
static Class()
{
if(System.Windows.Application.Current is not Platform.HttpClientOwner.IHttpClientOwner)
throw new System.InvalidProgramException("NetworkMgr can only be used by applications that implement " +
"BestChat.Platform.HttpClientOwner.IHttpClientOwner.");
.
.
.
}
C#
static Class()
{
if(System.Windows.Application.Current is not Platform.HttpClientOwner.IHttpClientOwner)
throw new System.InvalidProgramException("NetworkMgr can only be used by applications that implement " +
"BestChat.Platform.HttpClientOwner.IHttpClientOwner.");
.
.
.
}
JakenVeina
JakenVeina14mo ago
okay so, when does that run? what loads that?
Will Pittenger
Will PittengerOP14mo ago
I know what the entry point project means. I've been doing Windows since 1995.
JakenVeina
JakenVeina14mo ago
great so, what are the two projects you have one is a WPF application what is the other one? how do they relate?
Will Pittenger
Will PittengerOP14mo ago
Class is loaded indirectly by events in the main window.
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
JakenVeina
JakenVeina14mo ago
here's what I know....
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
Will Pittenger
Will PittengerOP14mo ago
Nope.
JakenVeina
JakenVeina14mo ago
public partial class EntryPoint
: Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);

var x = Application.Current == this;
}
}
public partial class EntryPoint
: Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);

var x = Application.Current == this;
}
}
debugger shows x is true what's probably happening is that the static constructor of Class is getting called before the application has actually been instantiated and bootstrapped because static constructors are invoked when the type is loaded into memory, not when it's actually used the reason that linking to IHttpClientFactory is helpful is because it plays directly with IoC systems which is what you probably want here instead of using some strange static context to pass around the shared HttpClient instance
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
Will Pittenger
Will PittengerOP14mo ago
I'm explicitly starting the app. I added a OnStartup override. That's not called.
JakenVeina
JakenVeina14mo ago
if your Class instance needs an HttpClient object to use, you should pass it in when you construct it
Will Pittenger
Will PittengerOP14mo ago
It constructs itself. Only one instance allowed.
JakenVeina
JakenVeina14mo ago
which is what an IoC system is for so example
Will Pittenger
Will PittengerOP14mo ago
It's loading JSON from the Internet so I can define its contents. How is that relevant?
JakenVeina
JakenVeina14mo ago
public class MyService
{
public MyService(HttpClient httpClient)
=> _httpClient;

public void DoSomeStuff();

private readonly HttpClient _httpClient;
}
public class MyService
{
public MyService(HttpClient httpClient)
=> _httpClient;

public void DoSomeStuff();

private readonly HttpClient _httpClient;
}
public class MyWindow
: Window
{
public MyWindow(MyService service)
=> _service = service;

private void OnButtonClick(object sender, ClickEventHandler e)
=> _service.DoSomeStuff();

private readonly MyService _service;
}
public class MyWindow
: Window
{
public MyWindow(MyService service)
=> _service = service;

private void OnButtonClick(object sender, ClickEventHandler e)
=> _service.DoSomeStuff();

private readonly MyService _service;
}
protected override OnStartup(StartupEventArgs e)
{
_serviceProvider = new ServiceCollection()
.AddHttpClientFactory()
.AddSingleton<MyService>()
.AddTransient<Window>()
.BuildServiceProvider();

_window = _serviceProvider.GetRequiredService<Window>();

_window.Show();
}
protected override OnStartup(StartupEventArgs e)
{
_serviceProvider = new ServiceCollection()
.AddHttpClientFactory()
.AddSingleton<MyService>()
.AddTransient<Window>()
.BuildServiceProvider();

_window = _serviceProvider.GetRequiredService<Window>();

_window.Show();
}
Will Pittenger
Will PittengerOP14mo ago
Why isn't my App's OnStartup being called? Or any of its constructors?
JakenVeina
JakenVeina14mo ago
_serviceProvider is an IoC container: Inversion of Control we have a lot of different services and classes and whatnot responsible for different things that should have different lifetimes we hand over management of all of that to one container that container ALSO handles dependency management so, when I say GetRequiredService<Window>()
Will Pittenger
Will PittengerOP14mo ago
As I said, OnStartup isn't being called. What good does all this do if it isn't being called? Yet that's the project I'm trying to start. The main window even appears.
JakenVeina
JakenVeina14mo ago
because Window is registered as Transient it creates a brand new one for me, every time and Window requires MyService so, the container supplies one and since MyService is registered as Singleton it only ever creates one, and shares it to everyone that asks
Will Pittenger
Will PittengerOP14mo ago
So explain how all that helps if OnStartup isn't called?
JakenVeina
JakenVeina14mo ago
then the HttpClientFactory system supplies HttpClients to everyone in the most appropriate way and it does not, in fact, only supply one instance, across the entire app it does a much more efficient job it allows you to, say, configure a different HttpClient for each different server you want to call to since they might have different HTTP settings you want to use the underlying resource that is ACTUALLY important to maintain as singleton, or close to it, is maintained internally why do you think OnStartup() isn't being called?
Will Pittenger
Will PittengerOP14mo ago
I put a breakpoint in it. I also told you the constructors weren't called.
JakenVeina
JakenVeina14mo ago
a breakpoint only hits if you give it the opportunity to hit is your app crashing inside the static Class constructor? where you throw an exception?
Will Pittenger
Will PittengerOP14mo ago
There's nothing in that constructor that runs until after I open a window and click a menu item. So no.
JakenVeina
JakenVeina14mo ago
so, OnStartup() isn't being called, but your window is opening?
Will Pittenger
Will PittengerOP14mo ago
It would crash there, but that doesn't prevent OnStartup from running. Correct.
JakenVeina
JakenVeina14mo ago
where does your window get created?
Will Pittenger
Will PittengerOP14mo ago
By app.xaml.
JakenVeina
JakenVeina14mo ago
StartupUri?
Will Pittenger
Will PittengerOP14mo ago
Yes.
JakenVeina
JakenVeina14mo ago
show your App codebehind
Will Pittenger
Will PittengerOP14mo ago
I did ages ago.
JakenVeina
JakenVeina14mo ago
there's no OnStartup() override in it, so.... no, you didn't
Will Pittenger
Will PittengerOP14mo ago
That was added just now.
JakenVeina
JakenVeina14mo ago
which is why I asked to see it again
Will Pittenger
Will PittengerOP14mo ago
namespace BestChat.GUI
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : System.Windows.Application, Platform.HttpClientOwner.IHttpClientOwner
{
private static System.Net.Http.HttpClient client = new();

public System.Net.Http.HttpClient HttpClient => client;

protected override void OnStartup(System.Windows.StartupEventArgs e)
{
base.OnStartup(e);

client = new System.Net.Http.HttpClient();
}
}
}
namespace BestChat.GUI
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : System.Windows.Application, Platform.HttpClientOwner.IHttpClientOwner
{
private static System.Net.Http.HttpClient client = new();

public System.Net.Http.HttpClient HttpClient => client;

protected override void OnStartup(System.Windows.StartupEventArgs e)
{
base.OnStartup(e);

client = new System.Net.Http.HttpClient();
}
}
}
JakenVeina
JakenVeina14mo ago
use "cs" BTW for the language identifier, not "C#"
Will Pittenger
Will PittengerOP14mo ago
Ah. It worked while editing. 9_9
JakenVeina
JakenVeina14mo ago
¯\_(ツ)_/¯
Will Pittenger
Will PittengerOP14mo ago
You probably want this too:
<Application
x:Class="Best_Chat.GUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Best_Chat.GUI"
xmlns:ctrls="clr-namespace:BestChat.GUI.Ctrls;assembly=BestChat.GUI.Ctrls"
StartupUri="MainWnd.xaml">
<Application
x:Class="Best_Chat.GUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Best_Chat.GUI"
xmlns:ctrls="clr-namespace:BestChat.GUI.Ctrls;assembly=BestChat.GUI.Ctrls"
StartupUri="MainWnd.xaml">
JakenVeina
JakenVeina14mo ago
is it Best_Chat or BestChat?
Will Pittenger
Will PittengerOP14mo ago
Oh. That was it. Something simple and I missed it. Thanks guys. Sorry for the confusion.
nohopestage
nohopestage14mo ago
You're instantiating a new client twice here
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
Will Pittenger
Will PittengerOP14mo ago
That was testing code. It's gone.
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
nohopestage
nohopestage14mo ago
So what's the other project? Is it a class library?
Unknown User
Unknown User14mo ago
Message Not Public
Sign In & Join Server To View
nohopestage
nohopestage14mo ago
Yeah I'm just curious
Accord
Accord14mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server