Wątek przeniesiony 2018-10-08 10:05 z C# i .NET przez somekind.

Windows Service i post request w timerze

Odpowiedz Nowy wątek
2018-10-01 15:56
0

Hej,
było już coś takiego jednak do dziś nie znalazłem rozwiązania w necie. Uprościłem przykład do takiej postaci. Generalnie z poziomu usługi windowsowej chce puszczać POSTa do bramki sms co 1 min.

public partial class Service1 : ServiceBase
    {
        public static readonly string API_URL = "https://api1.serwersms.pl/zdalnie/";
        public Dictionary<string, string> _content;
        public string _path = @"D:\log_service.txt";

        private readonly IMessageService _messageService;
        private readonly IMessageRepository _messageRepository;
        private static HttpClient client = new HttpClient();
        private Timer timer;

        public Service1(IMessageService messageService, IMessageRepository messageRepository)
        {
            InitializeComponent();
            _messageService = messageService;
            _messageRepository = messageRepository;
        }

        protected override void OnStart(string[] args)
        {
            timer = new Timer(TimeSpan.FromMinutes(1).TotalMilliseconds);
            timer.AutoReset = true;
            timer.Enabled = true;
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Start();
        }

        private async void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            var _message = _messageRepository.GetByStatus(status.inQueue);

            {
                foreach (Message m in _message)
                {
                    _content = Services.Utils.SmsApiConfiguration.GetConfig();
                    _content.Add("wiadomosc", m.MessageBody);
                    _content.Add("numer", m.Phone);
                    _content.Add("akcja", "wyslij_sms");

                    var httpContent = new FormUrlEncodedContent(_content);

                    try
                    {
                        var response = await client.PostAsync(API_URL, httpContent);

                        if (response.IsSuccessStatusCode)
                        {
                            var responseContent = await response.Content.ReadAsStringAsync();
                            File.AppendAllText(_path, Environment.NewLine + " " + responseContent);
                        }
                    }
                    catch (Exception ex)
                    {
                        File.AppendAllText(_path, Environment.NewLine + " " + ex);
                    }
                }
            }
        }

        protected override void OnStop()
        {
            timer.Stop();
            timer = null;
        }
    }

Zupełnie nie potrafię poprawić tego tak aby zadziałało poprawnie tzn.
W kolejce są dwie wiadomości do wysłania i nigdy, dla przykładu nie wyrzucam ich z kolejki. I teraz:

  1. Uruchamiam serwis.
  2. 1szy Timer Tick -> wszystko się wysyła
  3. 2gi Timer Tick -> próba PostAsync() ( 1sza wiadomość ) dostaję

System.Net.WebException: Żądanie zostało przerwane: Nie można utworzyć bezpiecznego kanału SSL/TLS.

druga wiadomość leci bez problemu

i tak w kółko. Gdy w kolejce mam 10 wiadomości, za 1szym razem wszystko leci, kolejne "tiknięcia" 1sza wiadomość przerwanie, pozostałe 9 bez problemu.
Robię to na Win 10 i szczerze pomału mam dość i zaczynam myśleć o zrobieniu tego jak zwykłą apkę konsolową i zapakowaniu tego w zaplanowane zadania. Bo w ten sposób chodzi. Co tutaj może być nie tak?
Kombinuję teraz z Fiddlerem jeszcze.
Target framework: 4.6.1.
Dostawca bramki używa TLS1.2

edytowany 1x, ostatnio: john_doe, 2018-10-01 16:02

Pozostało 580 znaków

2018-10-02 15:37
0

Panowie @somekind i reszta "grubych" głów tutaj. Nie dyskutujcie tam o sealed tak dużo :)
Czy naprawdę nikt z Was nie potrafi, nie miał do czynienia z tym cudem?
Zapraszam tutaj.

Pozostało 580 znaków

2018-10-02 15:40
0

A czemu client jest static?


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."

Pozostało 580 znaków

2018-10-02 15:49
0

próbuję już wielu opcji. Czytałem wiele treści w temacie poprawnego używania clienta. Jednym z nich był static. Ale nie jest on problemem w istocie.
Zrezygnowałem z "using" bo chodziło jeszcze gorzej a to rekomendowany sposób z Microsoftu.

Czy ktoś z Was mógłby to zreprodukować u siebie na 10?

edytowany 1x, ostatnio: john_doe, 2018-10-02 15:50

Pozostało 580 znaków

2018-10-02 15:59
0

Próbowałeś ustawić client.DefaultRequestHeaders.ConnectionClose = true;?


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."

Pozostało 580 znaków

2018-10-02 16:06
0

tak próbowałem. Ustawiłem to w metodzie, którą uruchamia Timer. Efekt wówczas jest taki, że już w 1szym "tiku" 1sza wiadomość leci, druga ma ten exception znienawidzony już przeze mnie .....
Zresztą ustawiałem też to w metodzie onStart() ten sam efekt.

edytowany 1x, ostatnio: john_doe, 2018-10-02 16:09

Pozostało 580 znaków

2018-10-02 19:11
0

Może to głupia sugestia, ale gdzieś mi się obiło na forach o oczy, że timer.Enabled = true to to samo co timer.Start() z tym że ten drugi ustawia timer.Enabled = true. Może przez to, że masz jedno i drugie coś ci się zazębia, a błąd o tym nie sugeruje

edytowany 1x, ostatnio: AdamWox, 2018-10-02 19:12

Pozostało 580 znaków

2018-10-03 08:51
0

@AdamWox: masz rację jednak nie w tym tkwi problem.

Pozostało 580 znaków

2018-10-03 10:03
gosc_z_pytaniem
0
john_doe napisał(a):

Robię to na Win 10 i szczerze pomału mam dość i zaczynam myśleć o zrobieniu tego jak zwykłą apkę konsolową i zapakowaniu tego w zaplanowane zadania. Bo w ten sposób chodzi. Co tutaj może być nie tak?

W takim razie spróbuj wydzielić logikę a następnie wywołać kod w serwisie i aplikacji konsolowej:

public class ServiceManager
    {
        public static readonly string API_URL = "https://api1.serwersms.pl/zdalnie/";
        public Dictionary<string, string> _content;
        public string _path = @"D:\log_service.txt";

        private readonly IMessageService _messageService;
        private readonly IMessageRepository _messageRepository;
        private static HttpClient client = new HttpClient();

        public ServiceManager(IMessageService messageService, IMessageRepository messageRepository)
        {
            _messageService = messageService;
            _messageRepository = messageRepository;
        }

        public async Task Process()
        {
            var _message = _messageRepository.GetByStatus(status.inQueue);

            {
                foreach (Message m in _message)
                {
                    _content = Services.Utils.SmsApiConfiguration.GetConfig();
                    _content.Add("wiadomosc", m.MessageBody);
                    _content.Add("numer", m.Phone);
                    _content.Add("akcja", "wyslij_sms");

                    var httpContent = new FormUrlEncodedContent(_content);

                    try
                    {
                        var response = await client.PostAsync(API_URL, httpContent);

                        if (response.IsSuccessStatusCode)
                        {
                            var responseContent = await response.Content.ReadAsStringAsync();
                            File.AppendAllText(_path, Environment.NewLine + " " + responseContent);
                        }
                    }
                    catch (Exception ex)
                    {
                        File.AppendAllText(_path, Environment.NewLine + " " + ex);
                    }
                }
            }
        }
    }

Konsoloa:

static async Task MainAsync(string[] args)
        {
            ServiceManager sm = CreateServiceManager();
            await sm.Process();

            await Task.Delay(10000);

            await sm.Process();
        }

Serwis:

public partial class Service1 : ServiceBase
    {
        private Timer timer;

        ServiceManager serviceManager;

        public Service1(ServiceManager serviceManager)
        {
            InitializeComponent();
            this.serviceManager = serviceManager;
        }

        protected override void OnStart(string[] args)
        {
            timer = new Timer(TimeSpan.FromMinutes(1).TotalMilliseconds);
            timer.AutoReset = true;
            timer.Enabled = true;
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Start();
        }

        private async void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            await serviceManager.Process();
        }

        protected override void OnStop()
        {
            timer.Stop();
            timer = null;
        }
    }

Pozostało 580 znaków

2018-10-03 10:30
gosc_z_pytaniem
1

Używasz w timerze async await, więc timer nie czeka na zakończenie zadania w obsłudze zdarzenia dłużej niż przez Ciebie określona minuta we właściwości interval.
Może być tak, że pierwszy w ciągu pierwszej minuty nie zakończyła się obsługa wszystkich elementów w kolejce i ponowne wywołanie obsługi timera powoduje jakieś zakleszczenia.

Po każdorazowym uruchomieniu aplikacji konsolowej tworzony jest nowy Timer, nowy HttpClient, więc ma to prawo działać poprawnie.

Pozostało 580 znaków

2018-10-03 11:04
0

najlepsze jest to, że na Windows 7 działa. Nie wiem jak na 8.1 ale na 10 takie kłopoty

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0