gauri's software engineering portfolio

CSV Generation Closest Date Algorithm Example Report Engine Standardizing Error Messages Text Message Notifications Download as Markdown

code sample 1

CSV Generation Methods
Click the following links to view the source code on GitHub.
CSV Generation
Report Model
HTTP Response

about this sample

This series of code chunks provides a full picture of the CSV Generation stack. The CSV Generation stack is used in several places throughout our application, from the Revenue Reports, to families viewing their students and invoices.

Since we interpreted the requirements as having to build a hands-off system, we chose to send the monthly reports as CSVs in an email to the administrator. Because of this, I chose to generate CSV reports on the backend to prevent duplicate code between report viewing and sending. This operates with the help of CsvHelper, a NuGet package that helps generate CSVs from models.

    public static byte[] GenerateCsv<T>(IList<T> itemsToWriteList, ClassMap map = null)
                {
                    using (var memoryStream = new MemoryStream())
                    {
                        TextWriter writer = new StreamWriter(memoryStream);
                        var csv = new CsvWriter(writer);
                        var records = itemsToWriteList;
            
                        if (map != null)
                        {
                            csv.Configuration.RegisterClassMap(map);
                        }
            
                        csv.WriteRecords(records);
                        writer.Flush();
            
                        return memoryStream.ToArray();
                    }
                }
                

csv generation

GenerateCsv is where the CSV actually gets generated in the form of a byte array to prepare for sending it as an HTTP response. The goal of this method was to make it as abstract as possible since several parts of the application use this feature. This method belongs in the utility project to allow for reuse in multiple components. it prefers interfaces over their implementations by using an IList, so that if we choose to use something like a LinkedList in the future, we are able to without much refactoring. It also allows for an IList of any type <T> to be generated into a CSV. Finally, it makes use of C#'s default parameters so that even developers not using a model with a ClassMap can use this method. Within the function, this code utilizes using statements to control resource usage. Additionally, writer.Flush() is called to prevent the CsvWriter from becoming overloaded.

public class TotalProfitReportItem
                {
                    public string StudentFirstName { get; set; }
                    public string StudentLastName { get; set; }
                    public string FeeType { get; set; }
                    public decimal Amount { get; set; }
                }
            
                public sealed class TotalProfitClassMap : ClassMap<TotalProfitReportItem>
                {
                    public TotalProfitClassMap()
                    {
                        Map(m => m.StudentFirstName).Name("First Name");
                        Map(m => m.StudentLastName).Name("Last Name");
                        Map(m => m.FeeType).Name("Fee Description");
                        Map(m => m.Amount).Name("Amount");
                    }
                }
                

report model

TotalProfitReportItem is an example of a model class that describes the columns of one of our revenue reports. TotalProfitReportItem demonstrates low coupling by separating itself from any of the other reports. By creating a model for each report type, it becomes easy to change what information is displayed in the report and create new reports. ClassMaps are a feature in the CsvHelper library that allow you to customize how information is displayed in the CSV. For this, I used the ClassMap to rename the columsn. Additionally, this class demonstrates high cohesion by defining the CSV ClassMaps in the same place as the model definition.

public class ResponseFactory
{
    public static HttpResponseMessage ConstructCsvResponse(byte[] csvContentBytes)
    {
        var result = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new ByteArrayContent(csvContentBytes)
        };
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        result.Content.Headers.ContentLength = csvContentBytes.Length;
        return result;
    }
}
                

http response

The final chunk in this code sample is the ConstructCsvResponse method. This method custom creates the header and response of the CSV byte array using UTF-8 and specifying the length of the response. It displays good software engineering principles by making the representation of the data consistent both in the back-end and the front-end.