Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Wieso stoppt Windows Dienst nach erster Ausführung?
CoderboyPB
myCSharp.de - Member



Dabei seit:
Beiträge: 291
Herkunft: Paderborn

Themenstarter:

Wieso stoppt Windows Dienst nach erster Ausführung?

beantworten | zitieren | melden

Hallo,
die statische Funktion Run() der Klasse Bot wird nur einmal ausgeführt, dann stoppt der Dienst automatisch.
Was mache ich falsch?


public class Program
    {
        public static void Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Warning)
                .Enrich.FromLogContext()
                .WriteTo.File(@"C:\SosaBot\LogFile.txt")
                .CreateLogger();

            try
            {
                Log.Information("Starting up the Service");
                CreateHostBuilder(args).Build().Run();
                return;
            }
            catch (Exception ex)
            {
                Log.Fatal(ex, "-ther was a problem, starting the service");
                return;
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            return Host.CreateDefaultBuilder(args)
                .UseWindowsService()
                .ConfigureServices((hostContext, services) =>
                {
                services.AddHostedService<Worker>();
                })
                .UseSerilog();
        }
    }


public class Worker : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                await Bot.Run();
                await Task.Delay(1000 * 60 * 3, stoppingToken);
            }
        }
    }


public static class Bot
    {
        public static async Task Run()
        {
            Log.Information("Starting Bot");

            var userClient = new TwitterClient(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET);

            (await userClient.Search.SearchTweetsAsync("Sportsfreund Sosa"))
                .ToList()
                .ForEach(async tweet =>
                {
                    Log.Information($"retweeting: {tweet.FullText}");
                    await userClient.Tweets.PublishRetweetAsync(tweet.Id);
                });

            Log.Information("Stopping Bot");
        }
    }

PS: Die Zugangsdaten sind da, habe sie aber hier heraus genommen.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15618
Herkunft: BW

beantworten | zitieren | melden

Den einzigen Fehler, den ich so sehe ist, dass Dein Logging kein Sinn macht.
- Du registierst nen statischen Logger
- Du registrierst nochmal Serilog


Normalerweise registriert man Serilog so:


        public static int Main(string[] args)
            => RunHostBuilder<Startup>(args);

        public static int RunHostBuilder<TStartup>(string[] args) where TStartup : class
        {
            try
            {
                using IHost host = CreateHostBuilder<TStartup>(args).Build();
                host.Run();

                return 0;
            }
            catch (Exception ex)
            {
                // Log.Logger will likely be internal type "Serilog.Core.Pipeline.SilentLogger"
                // This will log into Console, when app fails on startup
                if (Log.Logger == null || Log.Logger.GetType().Name == "SilentLogger")
                {
                    Log.Logger = new LoggerConfiguration()
                        .MinimumLevel.Debug()
                        .WriteTo.Console()
                        .CreateLogger();
                }

                Log.Fatal(ex, "Host terminated unexpectedly");

                return 1; /* 0 = ok, 1 = general error */
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }

        public static IHostBuilder CreateHostBuilder<TStartup>(string[] args)
            where TStartup : class
            => Host.CreateDefaultBuilder(args)
                .UseSerilog()
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<TStartup>()
                        .CaptureStartupErrors(true);
                });


Oder eben noch

                .UseSerilog((hostingContext, loggerConfiguration) =>
                {
                    loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration);
                })
Wenn Du Serilog über die appsettings.json verwalten willst.

Ansonsten solltest Du ja über Debugging herausfinden, warum der "Worker" (jetzt weiß ich auch, wieso Du im anderen Thread von Worker sprichst; dass Du damit nen BackgroundService meinst haste nicht verraten) sich und damit den Windows Service beendest.
Dazu musst Du nur die Start / Stop etc Methoden entsprechend implementieren und kannst dann rein steppen.

Damit relativiert sich übrigens auch meine Antwort im Azure Thread.
Du musst bei Fragen unbedingt den potentiellen Helfern mitteilen, von was Du sprichst.....

Lösung siehe hier.
private Nachricht | Beiträge des Benutzers
CoderboyPB
myCSharp.de - Member



Dabei seit:
Beiträge: 291
Herkunft: Paderborn

Themenstarter:

beantworten | zitieren | melden

1. zu dem Service:

Die Twitter Libary hatte ne Exception geworfen, die aber dummerweise nicht protokolliert wurde ...
Hab das Ganze entdeckt, als ich das noch mal als Standalone Applikation habe laufen lassen.

Die Exception wurde ausgelöst, dadurch, dass Retweets geretweeted wurden.
Fange die Exception jetzt ab und verlasse dann die Schleife direkt. Vorher habe ich die Tweets natürich chronologisch geordnet:


public static async Task Run()
        {
            var userClient = new TwitterClient(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET);

            var tweets = (await userClient.Search.SearchTweetsAsync("Sportsfreund Sosa"))
                 .OrderByDescending(tweet => tweet.CreatedAt)
                 .ToList();

            foreach (var tweet in tweets)
            {
                try
                {
                    await userClient.Tweets.PublishRetweetAsync(tweet.Id);
                    Log.Information($"Retweeted: {{ {tweet.FullText} }}");
                }
                catch (TwitterException)
                {
                    return;
                }
            }
        }

aber das funktioniert jetzt :-)

Was mich halt ärgert ist, dass die Exception nicht geloggt wurde, hätte mir einiges an Arbeit erspart ...

Zum Thema Serilog:
Das habe ich von einem Youtube Video von Tim Corey, ich selber kenne mich mit Serilog nicht aus, aber es scheint sehr mächtig zu sein, so dass ich es mir mal anschauen werde.
private Nachricht | Beiträge des Benutzers
CoderboyPB
myCSharp.de - Member



Dabei seit:
Beiträge: 291
Herkunft: Paderborn

Themenstarter:

beantworten | zitieren | melden

Nachtrag:
Der statische Logger I ST Serilog, mit UseSerilog wird dann das Programm angewiesen, Serilog zu nutzen.
So in etwa hat Tim Corey es in seinem Video erklärt.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15618
Herkunft: BW

beantworten | zitieren | melden

Zitat von CoderboyPB
Der statische Logger I ST Serilog, mit UseSerilog wird dann das Programm angewiesen, Serilog zu nutzen.

Nein, UseSerilog ist ein Shortcut für die Service Konfiguration und injiziert dabei die Factory.
Einfach mal in den Quellcode schauen.
Zitat von CoderboyPB
Die Twitter Libary hatte ne Exception geworfen, die aber dummerweise nicht protokolliert wurde ...
Setz den Logger korrekt, dann wird sie protokolliert.
Aber wenn Du meinst, dass meine Aussage falsch ist, dann lass es eben so - musst Du wissen :-)
private Nachricht | Beiträge des Benutzers
ClaraSoft
myCSharp.de - Member



Dabei seit:
Beiträge: 17

beantworten | zitieren | melden

Ich nutze Dependency Injection um meinen Logger zu bekommen. Dafür nutze ich das Interface ILogger<T>, was eigentlich sogar der standard Weg ist bzw sein sollte. Den kann ich sogar mit NLog konfigurieren. Ob der auch mit Serilog konfigurierbar ist weiß ich nicht.


private readonly ILogger<MqttSubcriptionWorker> logger;

public MqttSubcriptionWorker(ILogger<MqttSubcriptionWorker> logger)
{
    this.logger = logger;
}
private Nachricht | Beiträge des Benutzers
CoderboyPB
myCSharp.de - Member



Dabei seit:
Beiträge: 291
Herkunft: Paderborn

Themenstarter:

beantworten | zitieren | melden

Das ist auch der mir bekannte Weg.
Aber wie gesagt, hier zählte einfach nur das Ergebnis.

Wen es interessiert hier das Video. Ab ca. min 20:15https://www.youtube.com/watch?v=PzrTiz_NRKA
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15618
Herkunft: BW

beantworten | zitieren | melden

Zitat von ClaraSoft
Ob der auch mit Serilog konfigurierbar ist weiß ich nicht.

Serilog ist ein Sink-Provider, der auch das ILogger-Interface verwendet.
Durch das UseSerilog wird die Factory ausgetauscht, sodass das Logging-Interface selbst das gleiche bleibt aber die Verarbeitungs-Pipeline auf Serilog verändert wird.
Dadurch bleibt aus Entwicker-sicht alles identisch: nur das Ziel wird getauscht.

Die Factory hat aber nichts mit Logger.Log zutun.
private Nachricht | Beiträge des Benutzers