public async Task <IList <IGstLookupResult> > LookupGstDataAsync(GstLookupInputType inputType, string input, bool validateInput = false) { if (validateInput) { GstInputValidator.ValidateInput(inputType, input); } GstWebScraper scraper; var pool = _pools[inputType]; while (pool.TryDequeue(out scraper) && scraper.ShouldDispose) { } if (scraper == null) { scraper = new GstWebScraper(); } try { return(await scraper.LookupGstDataAsync(inputType, input)); } finally { if (!scraper.ShouldDispose) { pool.Enqueue(scraper); } } }
public static CachedGstEntity CreateForError(GstLookupInputType inputType, string input, KnownCustomsGstErrorCode error) { return(new CachedGstEntity { PartitionKey = GetPartitionKey(inputType, input), RowKey = "000", KnownErrorCode = error.ToString() }); }
public async Task <IList <IGstLookupResult> > LookupGstDataAsync(GstLookupInputType inputType, string input, bool validateInput = false) { // Customs' server will return empty result if I send the same request two times in a row, // so I'm going to cache the most recent result and return that if the same requests were sent twice. var currentInput = Tuple.Create(inputType, input); if (currentInput.Equals(_previousInput)) { if (_previousResults.Count > 0) { var result = (GstLookupResult)_previousResults[0]; result.IsLiveData = false; } return(_previousResults); } if (validateInput) { GstInputValidator.ValidateInput(inputType, input); } if (_accessCount > 0) { throw new NotSupportedException(Resources.SingleLookupErrorMessage); } try { if (Interlocked.Increment(ref _accessCount) > 1) { throw new NotSupportedException(Resources.SingleLookupErrorMessage); } if (!_isInitialized) { await InitializeTokenAsync(); await LoadFrontPageAsync(); await BrowseToLookupPageAsync(); _isInitialized = true; } if (_inputType == null || _inputType != inputType) { await SelectLookupInputTypeAsync(inputType); } var results = await ExecuteLookupAsync(input); _previousInput = currentInput; _previousResults = results; return(results); } catch (WebException ex) { throw new CustomsGstException(ex.Message, innerException: ex); } finally { Interlocked.Decrement(ref _accessCount); } }
async Task SelectLookupInputTypeAsync(GstLookupInputType inputType) { var req = new RestRequest("_/Recalc"); switch (inputType) { case GstLookupInputType.GstNumber: req.AddParameter("d-3", "true"); req.AddParameter("d-5", ""); req.AddParameter("d-6", "false"); req.AddParameter("d-7", ""); req.AddParameter("d-8", "false"); req.AddParameter("d-9", ""); req.AddParameter("LASTFOCUSFIELD__", "d-3"); req.AddParameter("DOC_MODAL_ID__", 0); req.AddParameter("RECALC_SOURCE__", "d-3"); break; case GstLookupInputType.BusinessRegNumber: req.AddParameter("d-3", "false"); req.AddParameter("d-5", ""); req.AddParameter("d-6", "true"); req.AddParameter("d-7", ""); req.AddParameter("d-8", "false"); req.AddParameter("d-9", ""); req.AddParameter("LASTFOCUSFIELD__", "d-6"); req.AddParameter("DOC_MODAL_ID__", 0); req.AddParameter("RECALC_SOURCE__", "d-6"); break; case GstLookupInputType.BusinessName: req.AddParameter("d-3", "false"); req.AddParameter("d-5", ""); req.AddParameter("d-6", "false"); req.AddParameter("d-7", ""); req.AddParameter("d-8", "true"); req.AddParameter("d-9", ""); req.AddParameter("LASTFOCUSFIELD__", "d-8"); req.AddParameter("DOC_MODAL_ID__", 0); req.AddParameter("RECALC_SOURCE__", "d-8"); break; } req.AddParameter("RECALC_TRIGGER__", "CheckboxClick"); req.AddParameter("FAST_VERLAST__", _token); req.AddParameter("FAST_VERLAST_SOURCE__", _tokenSource); req.AddParameter("FAST_CLIENT_WHEN__", GetJavascriptTime()); req.AddParameter("FAST_CLIENT_WINDOW__", _windowId); req.AddParameter("FAST_CLIENT_AJAX_ID__", GetAjaxId()); var resp = await _client.ExecutePostTaskAsync(req); UpdateTokenForNextRequest(resp); _inputType = inputType; }
public static CachedGstEntity CreateForResult(GstLookupInputType inputType, string input, IGstLookupResult liveResult, int sequence) { if (!liveResult.IsLiveData) { throw new ArgumentException(Resources.WebApiCannotCacheStaleData, "liveResult"); } return(new CachedGstEntity { PartitionKey = GetPartitionKey(inputType, input), RowKey = sequence.ToString("000"), GstNumber = liveResult.GstNumber, LegalName = liveResult.LegalName, TradingName = liveResult.TradingName, CommenceDate = liveResult.CommenceDate, Status = liveResult.Status }); }
public static void ValidateInput(GstLookupInputType inputType, string input) { if (inputType == GstLookupInputType.GstNumber && !GstNumberRegex.IsMatch(input)) { throw new InvalidGstInputException(Resources.InvalidGstNumberValidationMessage); } if (inputType == GstLookupInputType.BusinessRegNumber && !BusinessRegNumberRegex.IsMatch(input)) { throw new InvalidGstInputException(Resources.InvalidBusinessRegNumberValidationMessage); } if (inputType == GstLookupInputType.BusinessName && input.Length <= 3) { throw new InvalidGstInputException(Resources.BusinessNameTooShortValidationMessage); } }
public static string GetPartitionKey(GstLookupInputType inputType, string input) { switch (inputType) { case GstLookupInputType.GstNumber: return(PartitionKeyPrefixForGstNumber + input); case GstLookupInputType.BusinessRegNumber: return(PartitionKeyPrefixForBusinessRegNumber + new string( input.Where(char.IsLetterOrDigit).Select(char.ToUpperInvariant).ToArray())); case GstLookupInputType.BusinessName: return(PartitionKeyPrefixForBusinessNameQuery + input.ToUpperInvariant().Replace(' ', '_')); default: throw new NotSupportedException(); } }
public async Task <IList <IGstLookupResult> > LookupGstDataAsync(GstLookupInputType inputType, string input, bool validateInput = false) { if (validateInput) { GstInputValidator.ValidateInput(inputType, input); } // Retrieve all entities of the given Partition Key. var partitionKey = CachedGstEntity.GetPartitionKey(inputType, input); var resultsQuery = Table.CreateQuery <CachedGstEntity>().Where(e => e.PartitionKey == partitionKey); var cachedResults = new List <IGstLookupResult>(); TableContinuationToken continuationToken = null; do { var segment = await resultsQuery.AsTableQuery().ExecuteSegmentedAsync(continuationToken); cachedResults.AddRange(segment.Results); continuationToken = segment.ContinuationToken; } while (continuationToken != null); // Return if there is any entity in the cache. if (cachedResults.Count > 0) { return(cachedResults); } // Lookup Customs' server and cache the results. IList <IGstLookupResult> lookupResults; try { lookupResults = await _dataSource.LookupGstDataAsync(inputType, input); } catch (CustomsGstException ex) { if (ex.KnownErrorCode == KnownCustomsGstErrorCode.Over100Results) { #pragma warning disable 4014 InsertAsync(CachedGstEntity.CreateForError( inputType, input, KnownCustomsGstErrorCode.Over100Results)); } #pragma warning restore 4014 throw; } if (lookupResults.Count == 0) { #pragma warning disable 4014 InsertAndScheduleDeleteAsync(CachedGstEntity.CreateForError( inputType, input, KnownCustomsGstErrorCode.NoResult), 6); return(lookupResults); #pragma warning restore 4014 } if (lookupResults[0].IsLiveData) { CachedGstEntity lastCachedResult = null; var batchOp = new TableBatchOperation(); for (var i = 0; i < lookupResults.Count; i++) { lastCachedResult = CachedGstEntity.CreateForResult(inputType, input, lookupResults[i], i); batchOp.InsertOrReplace(lastCachedResult); } #pragma warning disable 4014 Table.ExecuteBatchAsync(batchOp); #pragma warning restore 4014 if (inputType == GstLookupInputType.BusinessName) { Debug.Assert(lastCachedResult != null, "cacheResult shouldn't be null here"); #pragma warning disable 4014 ScheduleDeleteAsync(lastCachedResult, 6); #pragma warning restore 4014 } } return(lookupResults); }