Home > Net >  CsvHelper not setting properties that have classpaths
CsvHelper not setting properties that have classpaths

Time:05-14

I am having a strange issue where CsvHelper does not change properties that use classpaths to save data eg set => Channel.Snippet.Title or set => Channel.Id.

using (StreamReader fileStream = new StreamReader(openFileDialog.FileName))
using (CsvReader reader = new CsvReader(fileStream, new CsvConfiguration(CultureInfo.InvariantCulture)
{
    DetectColumnCountChanges = false,
    HeaderValidated = (args) => // This is set because the CSV is only partial data
    {
        Console.WriteLine(args.ToString());
    },
    MissingFieldFound = null // This is set because the CSV is only partial data
}))
{
    foreach (FullChannel record in reader.GetRecords<FullChannel>()) // tried adding .ToList()
    {
        Settings.Default.Channels.Add(record); // record.Id and record.Title are both null
        Console.WriteLine($"Id: {record.Id} Title: {record.Title}"); // Logs: Id: Title: 
        record.Id = "foo"; // This works fine
        record.Title = "bar"; // This works fine too
        Console.WriteLine($"Id: {record.Id} Title: {record.Title}"); // Logs: Id: foo Title: bar 
    }
}

This always deserializes the correct amount. I've tried to create a new TestChannel, clean and rebuild. CsvHelper seems to be able to save if there is no classpath eg using private string title in Title (The commented out code).

using Google.Apis.YouTube.v3.Data;

public class FullChannel
{
    private string title;

    public FullChannel()
    {
        Channel.Snippet = new ChannelSnippet();
    }

    // Functionality 
    public DateTime LastUpdated { get; set; }

    public bool AllNotifications { get; set; }

    // Channel
    /// <summary>
    /// Warning: Nothing in this property gets saved
    /// </summary>
    [XmlIgnore]
    //public Channel Channel { get; set; } = new Channel();  // this is the original code
    public TestChannel Channel { get; set; } = new TestChannel(); // this doesn't work for Id or Title

    // For csv
    [Name("Channel Id")]
    public string Id { get => Channel.Id; set => Channel.Id = value; }

    [Name("Channel Url")]
    [XmlIgnore] // Generated value only
    public string Url { get => $"https://www.youtube.com/channel/{Channel.Id}"; set => _ = value; }

    [Name("Channel Title")]
    public string Title {
        //get => title;
        //set => title = value;
        get => Channel.Snippet.Title;
        set => Channel.Snippet.Title = value;
    }
}

public class TestChannel
{
    public ChannelSnippet Snippet { get; set; }

    public string Id { get; set; }
}

CodePudding user response:

I have a feeling that the way CsvHelper reconstitutes the class is not recognizing the classpaths. The only thing I can suggest is saving directly to Channel.Snippet.Title and Channel.Id.

void Main()
{
    using (var fileStream = new StringReader("Channel Id,Channel Url,Channel Title\n1,this.com,MyTitle"))
    using (CsvReader reader = new CsvReader(fileStream, new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        DetectColumnCountChanges = false,
        HeaderValidated = (args) => // This is set because the CSV is only partial data
        {
            Console.WriteLine(args.ToString());
        },
        MissingFieldFound = null // This is set because the CSV is only partial data
    }))
    {
        reader.Context.RegisterClassMap<FullChannelMap>();
        foreach (FullChannel record in reader.GetRecords<FullChannel>()) // tried adding .ToList()
        {
            Console.WriteLine($"Id: {record.Id} Title: {record.Title}"); // Logs: Id: Title: 
            record.Id = "foo"; // This works fine
            record.Title = "bar"; // This works fine too
            Console.WriteLine($"Id: {record.Id} Title: {record.Title}"); // Logs: Id: foo Title: bar 
        }
    }
}

public class FullChannelMap : ClassMap<FullChannel>
{
    public FullChannelMap()
    {
        Map(x => x.Channel.Id).Name("Channel Id");
        Map(x => x.Channel.Snippet.Title).Name("Channel Title");
        Map(x => x.Url).Name("Channel Url");
    }
}
  • Related