locked
Creating an background API RRS feed

  • Question

  • User1872902656 posted

    I need to create a function that runs as a background service. I need this function to make an api call every 30 seconds to opentdb.com ..and save those questions, options and correct answers to the database.

    I am making the project with .NET framework MVC. I did some research and all leads to [System.Timers.Timer and System.Threading.Timer.] and it I understood that  TIA putting a timer in API is not smart so I also looked for hangfire. However I have no idea how to implement this

    TIA

    Sunday, September 13, 2020 5:56 PM

Answers

  • User1686398519 posted

    Hi Lestat90, 

    According to your needs, I wrote an example of using hangfire, you can refer to it.

    1. You need to install Hangfire, and then configure Hangfire.
      • In the example given, Hangfire is configured in the Startup.cs file.
      • If you don't have a Startup.cs file, you can right-click the project and select New Item, and then search for OWIN Startup Class to create a Startup.cs file.
    2. You can use RecurringJobManager to operate recurring jobs.
    3. The example uses the EF framework and a custom Api is written for testing. You can modify it according to your needs.

    More details, you could refer to below code:

    Startup.cs

        public class Startup
        {
            private IEnumerable<IDisposable> GetHangfireServers()
            {
                GlobalConfiguration.Configuration
                    .SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
                    .UseSimpleAssemblyNameTypeSerializer()
                    .UseRecommendedSerializerSettings()
                    .UseSqlServerStorage("DailyWebAPIMVCDemoContext", new SqlServerStorageOptions
                    {
                        CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
                        SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
                        QueuePollInterval = TimeSpan.Zero,
                        UseRecommendedIsolationLevel = true,
                        DisableGlobalLocks = true
                    });
    
                yield return new BackgroundJobServer();
            }
            public void Configuration(IAppBuilder app)
            {
                app.UseHangfireAspNet(GetHangfireServers);
                app.UseHangfireDashboard();
            }
        }

    DailyWebAPIMVCDemoContext

        public class DailyWebAPIMVCDemoContext : DbContext
        {
            public DailyWebAPIMVCDemoContext()
                : base("name=DailyWebAPIMVCDemoContext")
            {
            }
            public virtual DbSet<Question> Questions { get; set; }
            public virtual DbSet<Answer> Answers { get; set; }
        }

    Model

        public class Question
        {
            [Key]
            public int QuestionId { get; set; }
            public string QuestionName { get; set; }
            public string CreateTime { get; set; }
            public ICollection<Answer> answers { get; set; }
        }
        public class Answer
        {
            [Key]
            public int AnswerId { get; set; }
            public string AnswerName { get; set; }
            public string AnswerOption { get; set; }
            public bool IsTrueAnswer { get; set; }
            public string CreateTime { get; set; }
            public int QuestionId { get; set; }
            [ForeignKey("QuestionId")]
            public Question question { get; set; }
        }

    QuestionController

        public class QuestionController : ApiController
        {
            public Question Get()
            {
                Question question = new Question { 
                    QuestionName = "test", 
                    answers = new List<Answer> { 
                        new Answer { AnswerName="answer1",AnswerOption="hello1",IsTrueAnswer=true},
                        new Answer { AnswerName="answer2",AnswerOption="hello2",IsTrueAnswer=false},
                        new Answer { AnswerName="answer3",AnswerOption="hello3",IsTrueAnswer=false},
                        new Answer { AnswerName="answer4",AnswerOption="hello4",IsTrueAnswer=false}
                    } 
                };
                return question;
            }
         }

    HomeController 

        public class HomeController : Controller
        {
            public DailyWebAPIMVCDemoContext db = new DailyWebAPIMVCDemoContext();
            public ActionResult Index()
            {
                QuestionJob();
                return View();
            }
            public static async Task GetQuestionAsync()
            {
                using (var client = new HttpClient())
                {
                    var response = await client.GetAsync("https://localhost:44302/api/Question");
                    var question = new Question();
                    if (response.IsSuccessStatusCode)
                    {
                        question = await response.Content.ReadAsAsync<Question>();
                    }
                    if (question != null)
                    {
                        question.CreateTime = DateTime.Now.ToString();
                        using (var db = new DailyWebAPIMVCDemoContext())
                        {
                            db.Questions.Add(question);
                            if (question.answers != null)
                            {
                                question.answers.ToList().ForEach(a => { a.CreateTime = question.CreateTime; db.Answers.Add(a); });
                            }
                            db.SaveChanges();
                        }
                    }
                }
            }
            public static void QuestionJob()
            {
                var manager = new RecurringJobManager();
                manager.AddOrUpdate("1", Job.FromExpression(() => GetQuestionAsync()), "*/30 * * * * ?", TimeZoneInfo.Local);
            }
        }

    Here is the result.

    Best Regards,

    YihuiSun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, September 14, 2020 6:58 AM

All replies

  • User1686398519 posted

    Hi Lestat90, 

    According to your needs, I wrote an example of using hangfire, you can refer to it.

    1. You need to install Hangfire, and then configure Hangfire.
      • In the example given, Hangfire is configured in the Startup.cs file.
      • If you don't have a Startup.cs file, you can right-click the project and select New Item, and then search for OWIN Startup Class to create a Startup.cs file.
    2. You can use RecurringJobManager to operate recurring jobs.
    3. The example uses the EF framework and a custom Api is written for testing. You can modify it according to your needs.

    More details, you could refer to below code:

    Startup.cs

        public class Startup
        {
            private IEnumerable<IDisposable> GetHangfireServers()
            {
                GlobalConfiguration.Configuration
                    .SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
                    .UseSimpleAssemblyNameTypeSerializer()
                    .UseRecommendedSerializerSettings()
                    .UseSqlServerStorage("DailyWebAPIMVCDemoContext", new SqlServerStorageOptions
                    {
                        CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
                        SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
                        QueuePollInterval = TimeSpan.Zero,
                        UseRecommendedIsolationLevel = true,
                        DisableGlobalLocks = true
                    });
    
                yield return new BackgroundJobServer();
            }
            public void Configuration(IAppBuilder app)
            {
                app.UseHangfireAspNet(GetHangfireServers);
                app.UseHangfireDashboard();
            }
        }

    DailyWebAPIMVCDemoContext

        public class DailyWebAPIMVCDemoContext : DbContext
        {
            public DailyWebAPIMVCDemoContext()
                : base("name=DailyWebAPIMVCDemoContext")
            {
            }
            public virtual DbSet<Question> Questions { get; set; }
            public virtual DbSet<Answer> Answers { get; set; }
        }

    Model

        public class Question
        {
            [Key]
            public int QuestionId { get; set; }
            public string QuestionName { get; set; }
            public string CreateTime { get; set; }
            public ICollection<Answer> answers { get; set; }
        }
        public class Answer
        {
            [Key]
            public int AnswerId { get; set; }
            public string AnswerName { get; set; }
            public string AnswerOption { get; set; }
            public bool IsTrueAnswer { get; set; }
            public string CreateTime { get; set; }
            public int QuestionId { get; set; }
            [ForeignKey("QuestionId")]
            public Question question { get; set; }
        }

    QuestionController

        public class QuestionController : ApiController
        {
            public Question Get()
            {
                Question question = new Question { 
                    QuestionName = "test", 
                    answers = new List<Answer> { 
                        new Answer { AnswerName="answer1",AnswerOption="hello1",IsTrueAnswer=true},
                        new Answer { AnswerName="answer2",AnswerOption="hello2",IsTrueAnswer=false},
                        new Answer { AnswerName="answer3",AnswerOption="hello3",IsTrueAnswer=false},
                        new Answer { AnswerName="answer4",AnswerOption="hello4",IsTrueAnswer=false}
                    } 
                };
                return question;
            }
         }

    HomeController 

        public class HomeController : Controller
        {
            public DailyWebAPIMVCDemoContext db = new DailyWebAPIMVCDemoContext();
            public ActionResult Index()
            {
                QuestionJob();
                return View();
            }
            public static async Task GetQuestionAsync()
            {
                using (var client = new HttpClient())
                {
                    var response = await client.GetAsync("https://localhost:44302/api/Question");
                    var question = new Question();
                    if (response.IsSuccessStatusCode)
                    {
                        question = await response.Content.ReadAsAsync<Question>();
                    }
                    if (question != null)
                    {
                        question.CreateTime = DateTime.Now.ToString();
                        using (var db = new DailyWebAPIMVCDemoContext())
                        {
                            db.Questions.Add(question);
                            if (question.answers != null)
                            {
                                question.answers.ToList().ForEach(a => { a.CreateTime = question.CreateTime; db.Answers.Add(a); });
                            }
                            db.SaveChanges();
                        }
                    }
                }
            }
            public static void QuestionJob()
            {
                var manager = new RecurringJobManager();
                manager.AddOrUpdate("1", Job.FromExpression(() => GetQuestionAsync()), "*/30 * * * * ?", TimeZoneInfo.Local);
            }
        }

    Here is the result.

    Best Regards,

    YihuiSun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, September 14, 2020 6:58 AM
  • User1872902656 posted

    This all looks confusing but I will try to modify to save the json data in mysql evey 30 sec. thanks a lot man

    Tuesday, September 15, 2020 1:32 PM
  • User1872902656 posted

    Hi Lestat90, 

    According to your needs, I wrote an example of using hangfire, you can refer to it.

    1. You need to install Hangfire, and then configure Hangfire.
      • In the example given, Hangfire is configured in the Startup.cs file.
      • If you don't have a Startup.cs file, you can right-click the project and select New Item, and then search for OWIN Startup Class to create a Startup.cs file.
    2. You can use RecurringJobManager to operate recurring jobs.
    3. The example uses the EF framework and a custom Api is written for testing. You can modify it according to your needs.

    More details, you could refer to below code:

    I did it but it throws this when i try to log in:

    System.ArgumentException: 'Keyword not supported: 'data source'.'

    after I changed the connection string in web.config , because prior to this error it was throwing : Keyword not supported: 'data source'. exception

    Wednesday, September 16, 2020 7:50 PM