public async Task RefreshLiveStates(bool fast) { try { var watch = new Stopwatch(); watch.Start(); var indexCodes = StaticData.Instruments .Where(x => x.Flow != (byte)FlowTypes.Ati && x.CompanyCode != Constants.CompanyCodes.IDXS) .Select(x => x.InsCode) .ToList(); if (fast) { indexCodes.RemoveFromIList(x => !Online.Data.ContainsKey(x)); } OnOperationStart?.Invoke(this, indexCodes.Count * 2 + 3); var liveSrv = StaticServiceFactory.Create <ILiveInstDataService>(); var today = DateTime.Now.Date; var savedData = await liveSrv.GetDefaultQuery() .Where(x => x.DEven >= today) .ToListAsync(); OnOperationStep?.Invoke(this, EventArgs.Empty); int i = 0; var readWebSiteBlock = new TransformBlock <long, LiveInstData>( async inxCode => { InstrumentLastInfo ins = null; try { ins = await Online.FindAsync(null, inxCode); } catch (Exception ex) { _logger.WarnFormat("Cannot find instrument by code {0}; operation skip from this error.", ex, inxCode); return(null); } if (ins == null) { _logger.WarnFormat("cannot find instrument with code {0}", inxCode); return(null); } else { _logger.InfoFormat("instance {0} live data fetched {1}% completed", inxCode, Math.Ceiling(i++ *1.0 / indexCodes.Count * 100)); } var r = new LiveInstData(); foreach (var field in r.GetFields().Where(x => x.Kind == FieldKinds.Primitive)) { var value = ins.GetPropertyValue(field.Name); r.SetValue(field.Name, Typing.ChangeType(value, field.PropertyType)); } OnOperationStep?.Invoke(this, EventArgs.Empty); return(r); }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 15 }); List <LiveInstData> newData = new List <LiveInstData>(); List <LiveInstData> dirtyData = new List <LiveInstData>(); var writeLiveInstData = new ActionBlock <LiveInstData>(r => { if (r == null) { return; } var savedInst = savedData.FirstOrDefault(x => x.InsCode == r.InsCode); if (savedInst != null) { savedInst.ResetChanges(); foreach (var field in r.GetFields().Where(x => x.Kind == FieldKinds.Primitive)) { var value = r.GetPropertyValue(field.Name); savedInst.SetValue(field.Name, Typing.ChangeType(value, field.PropertyType)); } if (savedInst.ChangeTracker.State == ObjectState.Modified) { dirtyData.Add(savedInst); } } else { r.DEven = today; newData.Add(r); } OnOperationStep?.Invoke(this, EventArgs.Empty); }); readWebSiteBlock.LinkTo(writeLiveInstData); foreach (var code in indexCodes) { readWebSiteBlock.Post(code); } readWebSiteBlock.Complete(); await readWebSiteBlock.Completion; var ov = ObjectRegistry.GetObject <IValidationProvider>(); newData.RemoveFromIList(x => !ov.Validate(x, Mode.OnInsert.ToString()).IsValid); if (newData.Count > 0) { await liveSrv.Repository.BulkInsertAsync(newData); } OnOperationStep?.Invoke(this, EventArgs.Empty); dirtyData.RemoveFromIList(x => !ov.Validate(x, Mode.OnUpdate.ToString()).IsValid); if (dirtyData.Count > 0) { await liveSrv.SaveEntitiesAsync(dirtyData.ToArray()); } OnOperationStep?.Invoke(this, EventArgs.Empty); newData.Clear(); newData.TrimExcess(); dirtyData.Clear(); dirtyData.TrimExcess(); watch.Stop(); _logger.InfoFormat("RefreshLiveStates take {0}ms", watch.ElapsedMilliseconds); OnOperationCompleted?.Invoke(this, EventArgs.Empty); } catch (Exception exception) { _logger.Error("RefreshLiveStates", exception); OnOperationBreak?.Invoke(this, exception); } }