【问题标题】:Best practice for threading in a Web APIWeb API 中的线程最佳实践
【发布时间】:2019-03-16 11:51:43
【问题描述】:

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

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

我的 GET 接口

        //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 Service 将在 localhost IIS 服务器上运行。

【问题讨论】:

  • 你将如何主持这个?在 Windows 服务中?
  • @nvoigt:抱歉,我忘了提供该信息。在我的问题中更新。

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


【解决方案1】:

我会使用System.Timers.Timer 来执行此操作。在此处进一步阅读 -> Time Class

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

我将实施一个计时器服务,在您的情况下使用 1 分钟的时间间隔进行配置。我将在下面分享我的计时器实现,它在依赖注入容器中注册为单例,但应该给你一些工作。

 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.

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

    [Route("api/[controller]/[action]")]
public class XmlController : Controller
{
    private readonly ITimerService _timerService;

    public XmlController(ITimerService timerService)
    {
        //Injected in
        _timerService = timerService;
    }

    [HttpGet]
    public IActionResult ProccessXML(object someXMLObject)
    {
        _timerService.StopTimer();
        SomeMethodWithXml(someXMLObject)
        //Reset Timer
        _timerService.StartTimer();
        return Ok();
    }


}

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

    • 要使用Hangfire,我是否还需要安装一些服务器(Hangfire 服务器)。抱歉,我对此了解不多。
    • 不,您不需要安装服务器。查看快速入门指南:docs.hangfire.io/en/latest/quick-start.html Hangfire 对于您的情况可能有点矫枉过正......
    【解决方案3】:

    您可以使用 Hangfire 之类的工具来启动任务,然后该任务可以由某物来处理。这可能是一个控制台应用程序、另一个 Web 应用程序、一个 Azure 函数,等等。关键是它在您的主 Web 应用程序之外。然后,您可以立即返回,而无需等待那件事,无论它是什么,完成。您还可以利用 SignalR 和 Web Worker 等工具将状态更新推送到客户端。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多