CsvHelper with class
Here's an F# script that uses CsvHelper and runs as expected:
#r "nuget: CsvHelper, 30.0.1"
open System.IO
open System.Net.Http
open CsvHelper
type WALCLRecord() =
member val DATE = "" with get, set
member val WALCL = "" with get, set
let uri = sprintf "https://fred.stlouisfed.org/graph/fredgraph.csv?id=%s&cosd=%s" "WALCL" "2023-01-01"
let str = (new HttpClient()).GetStringAsync(uri).Result
use string_reader = new StringReader(str)
use csv_reader = new CsvReader(string_reader, System.Globalization.CultureInfo.InvariantCulture)
let records = csv_reader.GetRecords<WALCLRecord>()
let arr = records |> Array.ofSeq
for elt in arr do
printfn "%10s %15s" elt.DATE elt.WALCL
exit 0
The output:
2023-01-04 8507429.0
2023-01-11 8508587.0
2023-01-18 8489039.0
2023-01-25 8470557.0
2023-02-01 8433610.0
2023-02-08 8435369.0
2023-02-15 8384767.0
2023-02-22 8382190.0
2023-03-01 8339684.0
2023-03-08 8342283.0
2023-03-15 8639300.0
2023-03-22 8733787.0
2023-03-29 8705942.0
2023-04-05 8632384.0
2023-04-12 8614797.0
2023-04-19 8593263.0
2023-04-26 8562768.0
2023-05-03 8503994.0
2023-05-10 8503017.0
2023-05-17 8456760.0
2023-05-24 8436255.0
Note that it's using a class with properties to hold the data for each row:
type WALCLRecord() =
member val DATE = "" with get, set
member val WALCL = "" with get, set
CsvHelper with F# record
If I use an F# record instead:
type WALCLRecord = {
DATE : string
WALCL : float
}
it results in the following error:
CsvHelper.HeaderValidationException: Header with name 'dATE'[0] was not found.
Header with name 'wALCL'[0] was not found.
Headers: 'DATE', 'WALCL'
Headers: 'DATE', 'WALCL'
If you are expecting some headers to be missing and want to ignore this validation, set the configuration HeaderValidated to null. You can also change the functionality to do something else, like logging the issue.
IReader state:
ColumnCount: 0
CurrentIndex: -1
HeaderRecord:
["DATE","WALCL"]
IParser state:
ByteCount: 0
CharCount: 11
Row: 1
RawRow: 1
Count: 2
RawRecord:
DATE,WALCL
at CsvHelper.Configuration.ConfigurationFunctions.HeaderValidated(HeaderValidatedArgs args)
at CsvHelper.CsvReader.ValidateHeader(Type type)
at CsvHelper.CsvReader.ValidateHeader[T]()
at CsvHelper.CsvReader.GetRecords[T]()+MoveNext()
at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable`1 source) in D:\a\_work\1\s\src\FSharp.Core\seq.fs:line 1037
at <StartupCode$FSI_0183>.$FSI_0183.main@() in c:\Users\dharm\Dropbox\Documents\net-liquidity.fsx\walcl-csvhelper.fsx:line 98
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
Stopped due to error
Question
Is there a way to use the record type with CsvHelper?
Notes
In this question, it seems like they're successfully using F# records with CsvHelper.
Similar in this issue.
NameAttribute
If I use NameAttribute
to explicitly specify the field name:
type WALCLRecord = {
[<CsvHelper.Configuration.Attributes.NameAttribute("DATE")>]
date : string
[<CsvHelper.Configuration.Attributes.NameAttribute("WALCL")>]
walcl : float
}
the following is displayed:
CsvHelper.HeaderValidationException: Header with name 'date'[0] was not found.
Header with name 'walcl'[0] was not found.
Headers: 'DATE', 'WALCL'
Headers: 'DATE', 'WALCL'