我创建了一个在客户机上运行的服务。此服务在服务器上的数据库中插入日志条目。通过在服务器上运行的API插入日志条目。下面是Service1
类中的简化代码。该服务是基于计时器的,并在需要时重复运行。因此,它需要在需要时插入日志条目。即重复执行SendToServer()
函数。我删除了计时器代码,因为它在这里不相关。
public class Logs
{
public string param1 { get; set; }
public string param2 { get; set; }
}
static HttpClient client = new HttpClient();
System.Timers.Timer timer = new System.Timers.Timer(); //New Edit
protected override void OnStart(string[] args)
{
SendToServer();
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);//New Edit
timer.Interval = 60000; //New Edit
timer.Enabled = true; //NewEdit
}
private void OnElapsedTime(object source, ElapsedEventArgs e)//New Edit
{
SendToServer();
}
public void SendToServer()
{
RunAsync().GetAwaiter().GetResult();
}
static async Task RunAsync(EventLogEntry Log)
{
client.BaseAddress = new Uri("https://<IP>:<Port>/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Logs log = new Logs
{
param1 = "value1";
param2 = "value2";
};
var url = await CreateLogsAsync(log);
}
static async Task<Uri> CreateLogsAsync(Logs log)
{
ServicePointManager.ServerCertificateValidationCallback = delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
};
HttpResponseMessage response = await client.PostAsync("api/Logs", new StringContent(new JavaScriptSerializer().Serialize(log), Encoding.UTF8, "application/json"));
response.EnsureSuccessStatusCode();
return response.Headers.Location;
}
当我安装服务或启动客户端计算机时。第一次数据库插入工作正常。但是,第二次不会将数据插入到数据库中。当我重新启动系统时,它再次插入第一个日志。我感觉到ASync函数有问题,在插入数据后第一个API调用永远不会正确返回。
类似的代码在控制台应用程序中工作得很好。
发布于 2020-05-15 04:31:43
问题是您的Windows服务在执行以下行后关闭:
RunAsync().GetAwaiter().GetResult();
OnStart()
方法需要做一些事情来保持服务运行,否则它将在OnStart()
返回时关闭。但是,您不能将像while (true)
这样的永久循环放在OnStart()
方法中,因为系统会将OnStart()
作为代码的回调调用,并期望OnStart()
及时返回。同样,启动Task
或在ThreadPool
上启动任何东西都不会起作用(如您所见),因为这些作为background线程运行,后台线程会在应用程序停止时自动停止。从链接:
线程可以是后台线程也可以是前台线程。后台线程与前台线程相同,只是后台线程不会阻止进程终止。一旦属于某个进程的所有前台线程都已终止,公共语言运行库就会结束该进程。任何剩余的后台线程都会停止,并且不会完成。
为了解决这个问题,您需要启动一个前台线程。这里有一个非常粗略的例子,应该可以解决当前的问题。你需要调整它来做你想让它做的事情。
using System.Threading;
public sealed class MyService : ServiceBase
{
private Thread _thread;
private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
protected override void OnStart(string[] args)
{
// Create the thread object and tell it to execute the Run method
_thread = new Thread(Run);
// Name the thread so it is identifyable
_thread.Name = "MyService Thread";
// Set the thread to be a foreground thread (keeps the service running)
_thread.IsBackground = false;
// Start the thread
_thread.Start();
}
protected override void OnStop()
{
// Set the shutdown event to tell the foreground thread to exit
// the while loop and return out of the Run() method
_shutdownEvent.Set();
// Wait for the foreground thread to exit
_thread.Join();
}
private void Run()
{
// The while loop keeps the foreground thread active by executing
// over and over again until Stop() sets the shutdown event, which
// triggers the while loop to exit.
while (!_shutdownEvent.WaitOne(1000))
{
// Put your logic here.
RunAsync().GetAwaiter().GetResult();
}
}
}
请注意,Run()
方法中的while
循环将反复运行,直到设置了shutdown事件(请参见Stop()
方法)。WaitOne()
调用的参数以毫秒为单位。按照编码,WaitOne()
调用将阻塞1秒,然后再次执行您的代码。您需要对此进行调整,以便您的代码在您想要的时候运行。
HTH
https://stackoverflow.com/questions/61805106
复制相似问题