|
|
@@ -1,21 +1,22 @@ |
|
|
<% |
|
|
<% |
|
|
'======================================================================================================================= |
|
|
'======================================================================================================================= |
|
|
' Jurisdiction Number Validation |
|
|
|
|
|
|
|
|
' Jurisdiction Number Validation + Lookup |
|
|
'======================================================================================================================= |
|
|
'======================================================================================================================= |
|
|
' Validates a submitted jurisdiction number against the JCode field of the jurisdictions |
|
|
' Validates a submitted jurisdiction number against the JCode field of the jurisdictions |
|
|
' list served by JurisdictionApiUrl (see public/web.config). That list is essentially static |
|
|
|
|
|
' reference data (townships/municipalities), so it's cached in Application scope for |
|
|
|
|
|
' JurisdictionCacheMinutes (default 60) instead of being fetched on every /request-order |
|
|
|
|
|
' submission. If a refresh attempt fails, stale cached data is used rather than blocking |
|
|
|
|
|
' order requests; only when there is no cached data at all (e.g. immediately after an app |
|
|
|
|
|
' pool restart, with the API also unreachable) does validation fail open (allow) rather than |
|
|
|
|
|
' block every order request site-wide. |
|
|
|
|
|
|
|
|
' list served by JurisdictionApiUrl (see public/web.config), and looks up the matching |
|
|
|
|
|
' municipality Name (used to pre-fill the order form's Municipality field). That list is |
|
|
|
|
|
' essentially static reference data (townships/municipalities), so it's cached in |
|
|
|
|
|
' Application scope for JurisdictionCacheMinutes (default 60) instead of being fetched on |
|
|
|
|
|
' every /request-order submission. If a refresh attempt fails, stale cached data is used |
|
|
|
|
|
' rather than blocking order requests; only when there is no cached data at all (e.g. |
|
|
|
|
|
' immediately after an app pool restart, with the API also unreachable) does validation |
|
|
|
|
|
' fail open (allow) rather than block every order request site-wide. |
|
|
' |
|
|
' |
|
|
' The cache is stored as a single delimited STRING ("|code1|code2|...|"), not a |
|
|
|
|
|
' Scripting.Dictionary or array of objects - Scripting.Dictionary is an apartment-threaded |
|
|
|
|
|
' COM object, and IIS raises "ASP 0197: Disallowed object use" if you try to store one in |
|
|
|
|
|
' the Application intrinsic (which is shared across all requests/threads). A plain string is |
|
|
|
|
|
' just script data, so it's safe to cache this way. |
|
|
|
|
|
|
|
|
' The cache is stored as a single delimited STRING ("|code1<TAB>name1|code2<TAB>name2|...|"), |
|
|
|
|
|
' not a Scripting.Dictionary or array of objects - Scripting.Dictionary is an |
|
|
|
|
|
' apartment-threaded COM object, and IIS raises "ASP 0197: Disallowed object use" if you try |
|
|
|
|
|
' to store one in the Application intrinsic (which is shared across all requests/threads). A |
|
|
|
|
|
' plain string is just script data, so it's safe to cache this way. |
|
|
'======================================================================================================================= |
|
|
'======================================================================================================================= |
|
|
|
|
|
|
|
|
Function IsValidJurisdictionNumber(jurisdictionNumber) |
|
|
Function IsValidJurisdictionNumber(jurisdictionNumber) |
|
|
@@ -29,13 +30,36 @@ Function IsValidJurisdictionNumber(jurisdictionNumber) |
|
|
' down) - fail open rather than block every order request site-wide. |
|
|
' down) - fail open rather than block every order request site-wide. |
|
|
IsValidJurisdictionNumber = True |
|
|
IsValidJurisdictionNumber = True |
|
|
Else |
|
|
Else |
|
|
IsValidJurisdictionNumber = (InStr(codesText, "|" & jurisdictionNumber & "|") > 0) |
|
|
|
|
|
|
|
|
IsValidJurisdictionNumber = (InStr(codesText, "|" & jurisdictionNumber & Chr(9)) > 0) |
|
|
End If |
|
|
End If |
|
|
End Function |
|
|
End Function |
|
|
|
|
|
|
|
|
' Returns the cached "|code1|code2|...|" string, refreshing it from JurisdictionApiUrl when |
|
|
|
|
|
' missing or older than JurisdictionCacheMinutes. Falls back to the existing (stale) cached |
|
|
|
|
|
' string if a refresh attempt fails. |
|
|
|
|
|
|
|
|
' Returns the municipality Name matching a jurisdiction number, or "" if the cache is empty |
|
|
|
|
|
' or has no matching entry (callers should treat "" as "couldn't look this up" and fall back |
|
|
|
|
|
' to letting the user enter it manually, not as a hard error). |
|
|
|
|
|
Function GetJurisdictionName(jurisdictionNumber) |
|
|
|
|
|
Dim codesText, marker, startPos, nameStart, endPos |
|
|
|
|
|
|
|
|
|
|
|
GetJurisdictionName = "" |
|
|
|
|
|
|
|
|
|
|
|
codesText = GetJurisdictionCodesText() |
|
|
|
|
|
If Len(codesText) = 0 Then Exit Function |
|
|
|
|
|
|
|
|
|
|
|
jurisdictionNumber = Trim(jurisdictionNumber) |
|
|
|
|
|
marker = "|" & jurisdictionNumber & Chr(9) |
|
|
|
|
|
startPos = InStr(codesText, marker) |
|
|
|
|
|
If startPos = 0 Then Exit Function |
|
|
|
|
|
|
|
|
|
|
|
nameStart = startPos + Len(marker) |
|
|
|
|
|
endPos = InStr(nameStart, codesText, "|") |
|
|
|
|
|
If endPos = 0 Then Exit Function |
|
|
|
|
|
|
|
|
|
|
|
GetJurisdictionName = Mid(codesText, nameStart, endPos - nameStart) |
|
|
|
|
|
End Function |
|
|
|
|
|
|
|
|
|
|
|
' Returns the cached "|code1<TAB>name1|code2<TAB>name2|...|" string, refreshing it from |
|
|
|
|
|
' JurisdictionApiUrl when missing or older than JurisdictionCacheMinutes. Falls back to the |
|
|
|
|
|
' existing (stale) cached string if a refresh attempt fails. |
|
|
Private Function GetJurisdictionCodesText() |
|
|
Private Function GetJurisdictionCodesText() |
|
|
Dim cacheMinutes, cachedAt, isStale |
|
|
Dim cacheMinutes, cachedAt, isStale |
|
|
|
|
|
|
|
|
@@ -60,15 +84,18 @@ Private Function GetJurisdictionCodesText() |
|
|
GetJurisdictionCodesText = Application("JurisdictionCodesText") |
|
|
GetJurisdictionCodesText = Application("JurisdictionCodesText") |
|
|
End Function |
|
|
End Function |
|
|
|
|
|
|
|
|
' Fetches the jurisdictions list and extracts every JCode value. Returns a |
|
|
|
|
|
' "|code1|code2|...|" string, or "" on any failure (network, HTTP status, or no matches). |
|
|
|
|
|
|
|
|
' Fetches the jurisdictions list and extracts each JCode/Name pair. Returns a |
|
|
|
|
|
' "|code1<TAB>name1|code2<TAB>name2|...|" string, or "" on any failure (network, HTTP |
|
|
|
|
|
' status, or no matches). |
|
|
' |
|
|
' |
|
|
' Uses a targeted regex over the raw response text rather than this codebase's generic |
|
|
' Uses a targeted regex over the raw response text rather than this codebase's generic |
|
|
' aspJSON parser (core/lib.json.asp) - that parser walks the input character-by-character in |
|
|
' aspJSON parser (core/lib.json.asp) - that parser walks the input character-by-character in |
|
|
' plain VBScript, which measured at over 40 seconds for this API's ~450KB/1500-record |
|
|
' plain VBScript, which measured at over 40 seconds for this API's ~450KB/1500-record |
|
|
' response. RegExp.Execute is implemented natively and handles the same payload |
|
|
' response. RegExp.Execute is implemented natively and handles the same payload |
|
|
' near-instantly; since JCode is the only field this validator needs, a full generic parse |
|
|
|
|
|
' isn't necessary anyway. |
|
|
|
|
|
|
|
|
' near-instantly. The regex assumes JCode is immediately followed by Name in the source |
|
|
|
|
|
' JSON (verified true for all 1525 current records) - if the API ever reorders those fields |
|
|
|
|
|
' this will need revisiting, but a full generic parse still isn't necessary since only these |
|
|
|
|
|
' two fields are used. |
|
|
Private Function FetchJurisdictionCodesText() |
|
|
Private Function FetchJurisdictionCodesText() |
|
|
Dim apiUrl : apiUrl = GetAppSetting("JurisdictionApiUrl") |
|
|
Dim apiUrl : apiUrl = GetAppSetting("JurisdictionApiUrl") |
|
|
Dim result : result = "" |
|
|
Dim result : result = "" |
|
|
@@ -81,9 +108,9 @@ Private Function FetchJurisdictionCodesText() |
|
|
http.Send "" |
|
|
http.Send "" |
|
|
|
|
|
|
|
|
If Err.Number = 0 And http.Status = 200 Then |
|
|
If Err.Number = 0 And http.Status = 200 Then |
|
|
Dim re, matches, m, codes, code |
|
|
|
|
|
|
|
|
Dim re, matches, m, codes, code, name |
|
|
Set re = New RegExp |
|
|
Set re = New RegExp |
|
|
re.Pattern = """JCode""\s*:\s*""([^""]*)""" |
|
|
|
|
|
|
|
|
re.Pattern = """JCode""\s*:\s*""([^""]*)""\s*,\s*""Name""\s*:\s*""([^""]*)""" |
|
|
re.Global = True |
|
|
re.Global = True |
|
|
re.IgnoreCase = True |
|
|
re.IgnoreCase = True |
|
|
|
|
|
|
|
|
@@ -92,7 +119,8 @@ Private Function FetchJurisdictionCodesText() |
|
|
codes = "|" |
|
|
codes = "|" |
|
|
For Each m In matches |
|
|
For Each m In matches |
|
|
code = Trim(m.SubMatches(0)) |
|
|
code = Trim(m.SubMatches(0)) |
|
|
If Len(code) > 0 Then codes = codes & code & "|" |
|
|
|
|
|
|
|
|
name = Trim(m.SubMatches(1)) |
|
|
|
|
|
If Len(code) > 0 Then codes = codes & code & Chr(9) & name & "|" |
|
|
Next |
|
|
Next |
|
|
If Len(codes) > 1 Then result = codes |
|
|
If Len(codes) > 1 Then result = codes |
|
|
End If |
|
|
End If |
|
|
|