1
\$\begingroup\$

I am making a small console app to get XML from an API and then save the data to a database. While this project was not created via test-driven-development, I have tried to make it such that tests can be written easily and properly. Additionally, the core portions of the application are in a separate library project, as I am also making other interfaces (web app, etc.) for working with the API and data.

Application

Imports JetBrains.Annotations

Public Class Application

    <UsedImplicitly>
    Public Shared Function Main(arguments As String()) As Integer
        Dim calendarImporter As ICalendarImporter

        If arguments.Length <> 2
            calendarImporter = New CalendarImporter(
                GetInput("Url: "),
                GetInput("Token: "))
        Else 
            calendarImporter = New CalendarImporter(arguments(0), arguments(1))
        End If

        Try
            calendarImporter.RunAsync().GetAwaiter()
            Return 0
        Catch exception As Exception
            HandleException(exception)
            Return 1
        End Try
    End Function

    Private Shared Function GetInput(prompt As String) As String
        Dim input As String = Nothing

        While String.IsNullOrWhiteSpace(input)
            System.Console.Write(prompt)
            input = System.Console.ReadLine()
        End While

        Return input
    End Function

    Private Shared Sub HandleException(exception As Exception)
        System.Console.WriteLine(exception.Message)
        Dim innerException = exception.InnerException

        While innerException IsNot Nothing
            System.Console.WriteLine()
            System.Console.WriteLine(innerException.Message)
            innerException = innerException.InnerException
        End While
    End Sub

End Class

ICalendarImporter

Public Interface ICalendarImporter

    Function RunAsync() As Task

End Interface

CalendarImporter

Imports Library.CalendarImporter.Db
Imports Library.CalendarImporter.Services
Imports Library.CalendarImporter.Services.Interfaces

Public Class CalendarImporter
    Implements ICalendarImporter
    Implements IDisposable

    Public Sub New(url As String, token As String)
        Me.Url = url
        Me.Token = token
    End Sub

    Private Property CalendarImporterService As ICalendarImporterService

    Private Property Db As CalendarImporterDbContext

    Private Property Url As String

    Private Property Token As String

    Public Async Function RunAsync() As Task Implements ICalendarImporter.RunAsync
        CalendarImporterService = New CalendarImporterService(url, token)
        Dim calendarImportResult = Await CalendarImporterService.ImportCalendarAsync()

        If calendarImportResult.CalendarImport Is Nothing
            Throw New Exception(
                Convert.ToInt32(calendarImportResult.StatusCode) & 
                " " & 
                calendarImportResult.StatusCode.ToString())
        End If

        Db.CalendarImports.Add(calendarImportResult.CalendarImport)
        Await Db.SaveChangesAsync()
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        Db?.Dispose()
    End Sub

End Class

That concludes the console app. The following items are from the library, and used by the console app and others.

ICalendarImporterService

Imports Library.CalendarImporter.Services.Models

Namespace Services.Interfaces
    Public Interface ICalendarImporterService

        Function ImportCalendarAsync() As Task(Of ImportCalendarResult)

    End Interface

End NameSpace

CalendarImporterService

Imports System.IO
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.Xml
Imports System.Xml.Serialization
Imports Library.CalendarImporter.Entities
Imports Library.CalendarImporter.Services.Interfaces
Imports Library.CalendarImporter.Services.Models

Namespace Services

    Public Class CalendarImporterService
        Implements ICalendarImporterService

        Public Sub New(url As String, token As String)
            Me.Url = url
            Me.Token = token
        End Sub

        Private ReadOnly Property Url As String

        Private ReadOnly Property Token As String

        Private Property CalendarImportXmlSerializer As XmlSerializer = 
            New XmlSerializer(GetType(CalendarImport))

        Public Async Function ImportCalendarAsync() As Task(Of ImportCalendarResult) _
            Implements ICalendarImporterService.ImportCalendarAsync

            Dim getXmlResult = Await GetXmlAsync()

            Dim result = New ImportCalendarResult With {
                .StatusCode = getXmlResult.StatusCode
                }

            If Not String.IsNullOrWhiteSpace(getXmlResult.Xml)
                result.CalendarImport = DeserializeXml(getXmlResult.Xml)
                result.CalendarImport.Xml = getXmlResult.Xml.Replace("UTF-8", "UTF-16")
                result.CalendarImport.Date = Date.Now
            End If

            Return result
        End Function

        Private Function DeserializeXml(xml As String) As CalendarImport
            Using stringReader = New StringReader(xml)
                Using xmlReader As XmlReader = XmlReader.Create(stringReader)
                    Return CalendarImportXmlSerializer.Deserialize(xmlReader)
                End Using
            End Using
        End Function

        Private Async Function GetXmlAsync() As Task(Of GetXmlResult)
            Using httpClient = New HttpClient
                httpClient.DefaultRequestHeaders.Authorization = 
                    New AuthenticationHeaderValue("Basic", Token)

                Dim response = Await httpClient.GetAsync(Url)

                Dim result = New GetXmlResult With {
                    .StatusCode = response.StatusCode
                    }

                If response.IsSuccessStatusCode
                    result.Xml = Await response.Content.ReadAsStringAsync()
                End If

                Return result
            End Using
        End Function

    End Class

End NameSpace

GetXmlResult

Imports System.Net

Namespace Services.Models

    Public Class GetXmlResult

        Public Property StatusCode As HttpStatusCode

        Public Property Xml As String

    End Class

End NameSpace

ImportCalendarResult

Imports System.Net
Imports Library.CalendarImporter.Entities

Namespace Services.Models

    Public Class ImportCalendarResult

        Public Property CalendarImport As CalendarImport

        Public Property StatusCode As HttpStatusCode

    End Class

End NameSpace

The Entities namespace that includes CalendarImport contains the POCO the XML and database map to. CalendarImport is the name of the root XML object. The namespaces have been edited to remove potentially identifying information about the client(s) involved with the project.

How would I improve this?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.