<% '======================================================================================================================= ' Jurisdiction Number Validation + Lookup '======================================================================================================================= ' Validates a submitted jurisdiction number against the JCode field of the jurisdictions ' 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 ("|code1name1|code2name2|...|"), ' 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) Dim codesText codesText = GetJurisdictionCodesText() jurisdictionNumber = Trim(jurisdictionNumber) If Len(codesText) = 0 Then ' No jurisdiction list available at all (first request after startup, API also ' down) - fail open rather than block every order request site-wide. IsValidJurisdictionNumber = True Else IsValidJurisdictionNumber = (InStr(codesText, "|" & jurisdictionNumber & Chr(9)) > 0) End If End Function ' 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 "|code1name1|code2name2|...|" 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() Dim cacheMinutes, cachedAt, isStale cacheMinutes = GetAppSetting("JurisdictionCacheMinutes") If Not IsNumeric(cacheMinutes) Then cacheMinutes = 60 cachedAt = Application("JurisdictionCodesFetchedAt") isStale = IsEmpty(cachedAt) If Not isStale Then isStale = (DateDiff("n", cachedAt, Now()) >= CInt(cacheMinutes)) If isStale Then Dim fresh fresh = FetchJurisdictionCodesText() If Len(fresh) > 0 Then Application.Lock Application("JurisdictionCodesText") = fresh Application("JurisdictionCodesFetchedAt") = Now() Application.Unlock End If End If GetJurisdictionCodesText = Application("JurisdictionCodesText") End Function ' Fetches the jurisdictions list and extracts each JCode/Name pair. Returns a ' "|code1name1|code2name2|...|" 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 ' 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 ' response. RegExp.Execute is implemented natively and handles the same payload ' 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() Dim apiUrl : apiUrl = GetAppSetting("JurisdictionApiUrl") Dim result : result = "" On Error Resume Next Dim http : Set http = Server.CreateObject("Msxml2.ServerXMLHTTP") http.setTimeouts 5000, 5000, 5000, 5000 http.Open "GET", apiUrl, False http.Send "" If Err.Number = 0 And http.Status = 200 Then Dim re, matches, m, codes, code, name Set re = New RegExp re.Pattern = """JCode""\s*:\s*""([^""]*)""\s*,\s*""Name""\s*:\s*""([^""]*)""" re.Global = True re.IgnoreCase = True Set matches = re.Execute(http.responseText) If Err.Number = 0 And matches.Count > 0 Then codes = "|" For Each m In matches code = Trim(m.SubMatches(0)) name = Trim(m.SubMatches(1)) If Len(code) > 0 Then codes = codes & code & Chr(9) & name & "|" Next If Len(codes) > 1 Then result = codes End If End If Err.Clear On Error GoTo 0 FetchJurisdictionCodesText = result End Function %>