I have a problem with my asp.net application.
My application is supposed to webscrape a site once every day.
I'm trying to fire of a method with a timer and this method I'm trying to process needs my dbcontext to save the new data.
My method works fine if i run my application and go to the page that calls this method on request, but when the timer tries to use it my dbcontext is disposed.
My question is.. How do i configure my asp.net application so i can reuse my dbcontext in the background and not dependent to a request from a web browser?
Here is some code:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<FundContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("FundContext")));
services.AddTransient<IFundDataService, FundDataService>();
services.AddMvc();
}
FundContext.cs
public class FundContext : DbContext, IFundContext
{
public FundContext(DbContextOptions<FundContext> options)
: base(options)
{
}
public DbSet<Fund> Funds { get; set; }
}
FundsModel.cshtml.cs
public class FundsModel : PageModel
{
private IFundDataService fundDataService;
public FundsModel(IFundDataService fundDataService)
{
this.fundDataService = fundDataService;
}
public void OnGet()
{
}
public List<Fund> TodaysFundList { get { return fundDataService.TodaysFundList; } }
public List<Fund> YesterdaysFundList { get { return fundDataService.YesterdaysFundList; } }
}
FundDataService.cs
public class FundDataService : Controller, IFundDataService
{
private FundContext fundContext;
private List<Fund> todaysFundList;
private List<Fund> yesterdaysFundList;
private static Timer timer;
public FundDataService(FundContext fundContext)
{
this.fundContext = fundContext;
GetFundFromWebAndSavetoDB();
PopulateFundLists();
InitializeTimer();
}
public List<Fund> TodaysFundList { get { return todaysFundList; } }
public List<Fund> YesterdaysFundList{ get { return yesterdaysFundList; } }
private void InitializeTimer()
{
DateTime timeNow = DateTime.Now;
DateTime scheduledTime = new DateTime(timeNow.Year, timeNow.Month, timeNow.Day, 00, 01, 00);
if(timeNow > scheduledTime)
{
scheduledTime = scheduledTime.AddDays(1);
}
double tickTime = 10000;/*(double)(scheduledTime - DateTime.Now).TotalMilliseconds;*/
timer = new Timer(tickTime);
timer.Elapsed += Timer_Elapsed;
timer.Start();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
timer.Stop();
GetFundFromWebAndSavetoDB();
PopulateFundLists();
InitializeTimer();
}
private void PopulateFundLists()
{
todaysFundList = new List<Fund>();
yesterdaysFundList = new List<Fund>();
foreach (var fund in fundContext.Funds)
{
if(fund.DateAddedToDB == DateTime.Now.Date)
{
todaysFundList.Add(new Fund
{
ID = fund.ID,
Name = fund.Name,
RateLastDay = fund.RateLastDay,
RateThisYear = fund.RateThisYear,
LastUpdate = fund.LastUpdate,
DateAddedToDB = fund.DateAddedToDB
});
}
if (fund.DateAddedToDB == DateTime.Now.Date.AddDays(-1))
{
yesterdaysFundList.Add(new Fund
{
ID = fund.ID,
Name = fund.Name,
RateLastDay = fund.RateLastDay,
RateThisYear = fund.RateThisYear,
LastUpdate = fund.LastUpdate,
DateAddedToDB = fund.DateAddedToDB
});
}
}
todaysFundList.Sort(delegate (Fund a, Fund b)
{
return b.RateThisYear.CompareTo(a.RateThisYear);
});
yesterdaysFundList.Sort(delegate (Fund a, Fund b)
{
return b.RateThisYear.CompareTo(a.RateThisYear);
});
}
private void GetFundFromWebAndSavetoDB()
{
var rawData = WebScrapingService.Instance.WebScrapeSiteAndReturnCollection(
"url"
, "//tbody/tr");
foreach (var fund in rawData)
{
decimal rateLastDay;
bool rateLastDayOK = decimal.TryParse(fund.ChildNodes[5].InnerText, out rateLastDay);
decimal rateThisYear;
bool rateThisYearOK = decimal.TryParse(fund.ChildNodes[11].InnerText, out rateThisYear);
var newFund = new Fund
{
Name = fund.ChildNodes[3].InnerText,
RateLastDay = rateLastDay,
RateThisYear = rateThisYear,
LastUpdate = Convert.ToDateTime(fund.ChildNodes[21].InnerText),
DateAddedToDB = DateTime.Now.Date
};
var NumberOfFundsAddedToday = (from x in fundContext.Funds where x.DateAddedToDB == DateTime.Now.Date select x).Count();
if(NumberOfFundsAddedToday < 5)
{
fundContext.Funds.Add(newFund);
fundContext.SaveChanges();
}
}
}
}
timer.AutoReset = false;to save yourself the hassle callingtimer.Stop();. It will fire theElapsedevent just once when set tofalse.