Web API线程化的最佳实践

时间:2018-10-11 11:49:53

标签: c# multithreading rest asp.net-web-api

我有一个仅带有单个GET控制器的简单Web API。 GET控制器读取XML数据并以JSON格式返回。

GET API应该每分钟都超过一次,但是如果没有GET请求超过1分钟,那么我需要开始备份数据(仅以XML格式。没什么花哨的)

我的GET Api

        //GET api/
        public IHttpActionResult Get()
        {            
            try
            {
                //Read XML
                XDocument xDoc = XDocument.Load(@"D:\myfile.xml");


                //Convert XML data into JSON string
                string jsonStr = JsonConvert.SerializeXNode(xDoc);
                JObject json = JObject.Parse(jsonStr);

                return Ok(json);
            }
            catch (Exception ex)
            {
                return NotFound();
            }                     
        }

示例XML:

<CurrentStatus>
    <Time Stamp= "20181011133631244">
        <price>12</price>
        <amount>100</amount>
    </Time>
</CurrentStatus>

XML格式的示例备份:

<CurrentStatus>
    <Time Stamp= "20181011133631244">
        <price>12</price>
        <amount>100</amount>
    </Time>
    <Time Stamp= "20181011133633354">
        <price>11</price>
        <amount>120</amount>
    </Time>
    <Time Stamp= "20181011133633204">
        <price>15</price>
        <amount>90</amount>
    </Time>
</CurrentStatus>

我的计划逻辑::我打算声明一个static变量_lastAccessedTimestamp,该变量将由一个单独的线程监视。如果currentTime - _lastAccessedTimestamp> 1 min,则开始备份数据。

问题:针对这种情况(或其他更好的选择)在Web API中实现线程的良好实践?

PS: Web服务将在本地IIS服务器上运行。

3 个答案:

答案 0 :(得分:2)

每次请求后,我都会设置/重置计时器1分钟。从另一个线程轮询的变量效率不高,还会引发其他问题。

更重要的是,您可以使用适当的作业处理lib(例如Hangfire-https://www.hangfire.io/),这样就可以安排作业(在1分钟后),并在每个请求之后重新安排作业,以防出现新的请求。

请注意,IIS可以随时停止您的进程,您可能需要调查一下。 http://docs.hangfire.io/en/latest/deployment-to-production/making-aspnet-app-always-running.html

对于实现,您可以使用中间件/过滤器,该中间件/过滤器会在每个请求结束时自动执行此操作。无需在控制器中添加它。在不重复代码的情况下添加多个控制器也更加容易。

答案 1 :(得分:0)

您可以使用诸如Hangfire之类的功能来触发任务,然后该任务可以由某些东西来处理。可能是控制台应用程序,另一个Web应用程序,Azure功能等等。关键是它在您的主Web应用程序外部。然后,您可以立即返回,而无需等待该事件完成。您还可以利用SignalR和网络工作者等工具将状态更新推送到客户端。

答案 2 :(得分:0)

我将使用arrayOfObjects.sort((a, b) => b.get('date').unix() - a.get('date').unix()); 进行此操作。在这里进一步阅读-> Time Class

请知道我的答案使用了依赖注入,但是可以很容易地重构为实例化普通类。

我将实施一个计时器服务,该服务在您的情况下使用1分钟的间隔进行配置。我将在下面共享我的计时器实现,它以单例形式在依赖项注入容器中注册,但应该为您提供一些帮助。

System.Timers.Timer

在应用程序启动时,您必须启动计时器,每分钟之后,它将开始进行数据备份。由于 public class TimerService : ITimerService { private readonly System.Timers.Timer _timer; private DateTime _startTime = DateTime.Now; private double _timerSettings; public TimerService() { _timer = new System.Timers.Timer { AutoReset = true, Interval = 60000, }; _timer.Elapsed += (sender, args) => { //Backup Data method here _startTime = DateTime.Now; }; } public double GetTimerInterval() { return _timer.Interval; } public void StopTimer() { if (_timer == null) { throw new ApplicationException("Timer not primed."); } _timer.Stop(); } public void StartTimer() { if (_timer == null) { throw new ApplicationException("Timer not primed."); } _startTime = DateTime.Now; _timer.Start(); } }

现在只需重置控制器中的计时器

AutoReset = true