❔ question about console app host.RunAsync();
In this example:
https://learn.microsoft.com/en-us/dotnet/core/extensions/logging-providers
using Microsoft.Extensions.Hosting;
using IHost host = Host.CreateDefaultBuilder(args).Build();
// Application code should start here.
await host.RunAsync();
I am wondering what is the point of host.RunAsync(); because I have tested without it and there is no difference.
Logging providers - .NET
Learn how the logging provider API is used in .NET applications.
108 Replies
I think that's a confusing code example because it omits where you actually add your service code.
A real worker service (which they claim to be using as an example) looks more like this:
Where the Worker class then has an implementation of a background service loop
And in that real world scenario, if you never call Run or RunAsync that service never actually starts running.
yea, for a background worker i know that but what about for a plain console app
like for exemple
using Microsoft.Extensions.Hosting;
using IHost host = Host.CreateDefaultBuilder(args).Build();
Console.WriteLine("Hello World")
await host.RunAsync();
For a plain console app you wouldn't normally use a host builder at all I think. Their example is supposed to be based on a worker service, not a plain console app.
i mean there are many reasons youd need a generic host in a console app
I'm just trying to understand how I would use dependancy injection for a simple console app
I guess I just configure the services and then aquire an instance
I don't think the .NET team really expected people to want to do that. At least they certainly didn't make it simple or obvious.
here this is just some nice syntax to help you not call GetAwaiter manually
hmm? this is literally what the generic host is for
ok that's possible
this is very standard stuff
literally this is what GenericHost is designed for
Well, the templates for console apps don't use such a thing at all.
I mean a console app could be very complex and one might want to use dependancy injection to make it more testable no?
no cuz they dont need to
.NET Generic Host - .NET
Learn about the .NET Generic Host, which is responsible for app startup and lifetime management.
first paragraph in docs
theres ton of reasons you might have a long running console app that needs a full host but it isnt necessarily a web thing
That still shows the worker service example not a simple way to do it in a console app.
They don't make it obvious how to do it in a simple console app that isn't some kind of service.
scroll down
its the same thing tho
like you just register the host deps, and run it
@PatrickG what do you mean youve tested without the RunAsync?
hmmm
actually i tested aquireing settings from appsettings.json without host.RuunAsync
i dont think i tested DI tho
but not sure
i might have once
elaborate on this
cuz its not making much sense
nothing happens until you run the host
well, it depends
but nothing like run happens until you run it
hold on
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddTransient<RandomClass>();
})
.Build();
//retrive instance of RandomClass
call some function from random class
i think this would work without host.RunAsync();
err how
like what do you mean "work"
that does nothing
how so
well lets say RandomClass.WriteSomeThing();
it would write something..
and the instance was created by the DI framework
well this is static
so its completely unrelated to DI
no not static
no it wouldnt
you never called it
and it was never created
if you do
absolutely nothing happens here
This conversation is proving my point that it's very non-obvious how to use things like dependency injection in a plain console program.
RandomClass rdm = provider.GetRequiredService<RandomClass >();
i mean its not the MOST obvious thing in the world, but if you have any idea about how a host works its not hard
ahh, so this is a VERY different thing
I agree, I have a template at the ready because I always forget.
@PatrickG so the problem here is that you arent actually... using the host at all
using IServiceScope serviceScope = services.CreateScope();
IServiceProvider provider = serviceScope.ServiceProvider;
RandomClass rdm = provider.GetRequiredService<RandomClass >();
yes thats all good, however thats completely unrelated conceptually to the Host
your just using the container directly
maybe a distinction between the host and DI will be nice, like is the host needed at all or just DI?
you dont need a host to do that
ok so that was my point
thats pretty much how u use DI in a bland console app
dont need host.RynAsync()
Host = While loop that runs and does stuff
Container = Grab bag of dependencies that allows you to resolve stuff easily
if you want to use DI in a console app you should probably just use the full host, you get alot more power
youd implement IHostedService as your entry point
implement where
anywhere you want, then you register it with ur host
oh yea
ive done that before
i did a worker
but it could run as a console app too
It's basically taking the worker template and then hacking it to not have a loop that runs forever.
a host runs until its stopped
unless ur talking about the di thing
Yes, which is another reason it feels like the wrong way to do a console app at first glance.
Most console apps don't have the "I will run until stopped" thing
At least a very large number of them don't
ok but lets say you are making a console app for a huge ETL process
you just code it without DI ?
i mean generally this kinda thing would need a scheduler or trigger etc
we ran our jobs with quartz
which we spun up in a Host
I would personally probably not use DI, but then again I mainly use DI because I am using other stuff (like writing an ASP.NET Core web service) that sort of forces you down that path.
I mean, I would use DI in the purest sense: passing in interfaces in constructors.
because the point of DI is to make more testable
you can easily write a test that replaces the whole database with just a dummy service
what are you scheduling this ETL with?
task manager
i mean
are you talking about DI here, or IoC?
task scheduler
Let me rephrase: I would probably use DI but not use a DI framework.
IoC and DI is the same no ?
nope
no
how aso
IoC is the thing that resolves DI dependencies
IoC is a pattern for orchestrating DI
DI is literally just "i wrote a constructor that takes a class as an argument
"interface", usually
usually
i thought DI ment, instead of instanciating a class mself, i let a framework do it
ya thats what i meant, ive been doing python DI lately so class is fine there
That's not what DI is. DI is a much simpler and basic concept.
im actually writing a powerpoint right now as we speak about how to do DI in Python correctly
Take your dependencies as input.
that is a much better description of IoC
oh ok
share it if you can, seems fun to read
anyway, no, there's nothing wrong with using IoC in a console app
the bigger the better, IMO
ya i can share what i have, most of my lectures at work are more discussion based then slide based so the slides are pretty small. But basically cuz my new team is all fastapi im just talking about the fastapi container
its like a babys first DI container lol
agreed
i default to it for everything, one pattern, easy to understand etc
i've never seen it done in python
DI: super useful and you should totally use it.
IoC: overrated mechanism that complicates everything
how do you resolve complex dependency graphs?
we have exactly this setup at work, actually, a console app that is called by Windows Task Scheduler for a bunch of background stuff. Different CLI arguments for different tasks. This app currently does NOT use IoC at the root, just cause of how old it is, but some of tbe newer tasks that have been added to it do, and eventually I'd like to see it all changed over
ok well now from what you explained, DI is just a simple coding practice that ive been doing forever
correct
$di
Dependency injection is really just a pretentious way to say 'taking an argument'
See: http://blog.ploeh.dk/2017/01/27/dependency-injection-is-passing-an-argument/
Dependency injection is passing an argument
Is dependency injection really just passing an argument? A brief review.
we have a tag
I just...pass interfaces around. When I need a class to inject into something...I new one up.
what happens when that class needs 4 other classes
and they need 10 other classes combined
stuff gets deep
factory methods?
maybe you can take a page from azure functions
The fast api version is basically the factory pattern with automatic calling at the reqeust entry point
it's entirely possible that console programs don't get that complex, in mtreit's scenarios
each class has a constructor that passes the required dependancies to the child class or something
It depends naturally, but I'm not afraid to just write startup code and wire things up myself. It's simple to read. There's no "black magic" where I have to track down where some class is even coming from.
I do like simplicity and I like to minimize coupling between types so I tend to try to have simple, non-complex dependency graphs.
@Henkypenky this should give you the gist
basically a more manual register
anyways
so basically I just need to do DI to get the benefits of easily testable code
dont need to use IoC
right
Yes
yes
but it depends on ur usecase etc if you use the container
well the container is just for if you are too lazy to replace all the instances of a class in your code
you replace it only at one place with IoC
but that doesn't take that long most of the time anyways
search and replace..
huh
no
thats not the benefit of IOC at all
im pretty sure its stated as one of the main benefits of it at least
in the microsoft docs
that doesnt make much sense lol
well yes it does
a rename is already a one click process
IOC doesnt change that
unless you meant change the underlying implementation
Dependency injection - .NET
Learn how to use dependency injection within your .NET apps. Discover how to registration services, define service lifetimes, and express dependencies in C#.
idk what im supposed to gain from that
The class creates and directly depends on the MessageWriter class. Hard-coded dependencies, such as in the previous example, are problematic and should be avoided for the following reasons:
To replace MessageWriter with a different implementation, the Worker class must be modified.
If MessageWriter has dependencies, they must also be configured by the Worker class. In a large project with multiple classes depending on MessageWriter, the configuration code becomes scattered across the app.
This implementation is difficult to unit test. The app should use a mock or stub MessageWriter class, which isn't possible with this approach.
ya basically interafaces
which isnt what you said really, or i just misunderstood it
anyways
so what would you say
is the main benefit of IoC
Not having to create a 100 instances of different classes to create an instance of something lol
so just lighten the code?
i mean ya lol
thats a pretty fucking big lightening
yea
makes sense
anyways time for me to go to bed
thx all
thanks for sharing!
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.