首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用异步时,对WebAPI的调用未正确返回

使用异步时,对WebAPI的调用未正确返回
EN

Stack Overflow用户
提问于 2020-05-15 02:46:48
回答 1查看 58关注 0票数 1

我创建了一个在客户机上运行的服务。此服务在服务器上的数据库中插入日志条目。通过在服务器上运行的API插入日志条目。下面是Service1类中的简化代码。该服务是基于计时器的,并在需要时重复运行。因此,它需要在需要时插入日志条目。即重复执行SendToServer()函数。我删除了计时器代码,因为它在这里不相关。

代码语言:javascript
运行
复制
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调用永远不会正确返回。

类似的代码在控制台应用程序中工作得很好。

EN

回答 1

Stack Overflow用户

发布于 2020-05-15 04:31:43

问题是您的Windows服务在执行以下行后关闭:

代码语言:javascript
运行
复制
RunAsync().GetAwaiter().GetResult();

OnStart()方法需要做一些事情来保持服务运行,否则它将在OnStart()返回时关闭。但是,您不能将像while (true)这样的永久循环放在OnStart()方法中,因为系统会将OnStart()作为代码的回调调用,并期望OnStart()及时返回。同样,启动Task或在ThreadPool上启动任何东西都不会起作用(如您所见),因为这些作为background线程运行,后台线程会在应用程序停止时自动停止。从链接:

线程可以是后台线程也可以是前台线程。后台线程与前台线程相同,只是后台线程不会阻止进程终止。一旦属于某个进程的所有前台线程都已终止,公共语言运行库就会结束该进程。任何剩余的后台线程都会停止,并且不会完成。

为了解决这个问题,您需要启动一个前台线程。这里有一个非常粗略的例子,应该可以解决当前的问题。你需要调整它来做你想让它做的事情。

代码语言:javascript
运行
复制
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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61805106

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档