Imports System.Xml Imports System.Text Imports System.Net.Http Imports DigitalData.Modules.Logging Imports MultiTool.Shared.Documents Imports MultiTool.Shared.Templates.GeneralConfig Imports MultiTool.Shared.Winline.Entities Namespace Winline Public Class WebServiceData Inherits BaseClass Private ReadOnly Config As WebServiceConfig Private ReadOnly Serializer As Serializer Private ReadOnly AppDataPath As String Public Event WebServiceProgress As EventHandler(Of String) Public Sub New(pLogConfig As LogConfig, pWebserviceConfig As WebServiceConfig, pAppDataPath As String) MyBase.New(pLogConfig, pLogConfig.GetLogger()) Serializer = New Serializer(pLogConfig) Config = pWebserviceConfig AppDataPath = pAppDataPath End Sub Public Async Function TransferDocumentToWinline(pDocument As Document, pMandator As Mandator, Optional pIsTest As Boolean = False) As Task(Of Boolean) Dim oBytes As Byte() = GetBytesFromDocument(pDocument) Dim oWS = Config ' --- Get and create path for request/response files Dim oPath As String = GetBaseWebServicePath() If IO.Directory.Exists(oPath) = False Then IO.Directory.CreateDirectory(oPath) End If RaiseEvent WebServiceProgress(Me, "Einstellungen laden") ' --- Build all teh filenamez and pathz Dim oBaseFileName As String = GetBaseFilenameForRequest() Dim oFileName = GetXmlFilenameWithSuffix(oBaseFileName, "Request", "xml") ' Relative Path for Webservice Call Dim oImportRelativeFilePath = IO.Path.Combine(GetDateSubDirectoryPath(oWS.ImportRelativePath), oFileName) ' Absolute Path to copy Request file Dim oImportAbsolutePath = IO.Path.Combine(oWS.ImportBasePath, oWS.ImportRelativePath) Dim oImportAbsoluteFilePath = IO.Path.Combine(GetDateSubDirectoryPath(oImportAbsolutePath), oFileName) ' --- Serialize Data into XML string RaiseEvent WebServiceProgress(Me, "Dateien schreiben") Dim oOutputFilePath = IO.Path.Combine(GetBaseWebServicePath(), oFileName) IO.File.WriteAllBytes(oOutputFilePath, oBytes) ' --- Copy file to Winline Import Directory Try IO.File.Copy(oOutputFilePath, oImportAbsoluteFilePath, True) Catch ex As Exception Logger.Error(ex) Throw ex End Try ' --- Prepare URL and HTTP Client Dim oTemplateType = pDocument.TemplateType Dim oTemplateName = pDocument.TemplateName ' ActionCode: Should this be a test or not? ' 0 = Test call ' 1 = Real call Dim oActionCode = 1 If pIsTest = True Then oActionCode = 0 End If ' Byref: Should data be supplied as file or as string? ' 0 = As String ' 1 = As File (relative to Winline Server directory) Dim oByref = 1 Dim oURL As String = $"{oWS.BaseUrl}/ewlservice/import?User={oWS.Username}&Password={oWS.Password}&Company={pMandator.Id}&Type={oTemplateType}&Vorlage={oTemplateName}&ActionCode={oActionCode}&Byref={oByref}&Data={oImportRelativeFilePath}" Dim oClient As New HttpClient() Logger.Info("Creating HTTP Request to [{0}]", oWS.BaseUrl) RaiseEvent WebServiceProgress(Me, "Anfrage absenden") ' --- Bring the action! Try Dim oResponse As HttpResponseMessage = Await oClient.GetAsync(oURL) Await HandleResponse(oResponse, oPath, oBaseFileName) Return True Catch ex As Exception Logger.Error(ex) Throw ex Finally oClient.Dispose() End Try End Function Private Async Function HandleResponse(pResponse As HttpResponseMessage, pPath As String, pBaseFileNAme As String) As Task pResponse.EnsureSuccessStatusCode() Dim oResponseBody As String = Await pResponse.Content.ReadAsStringAsync() Dim oContentType = pResponse.Content.Headers.ContentType.MediaType Dim oSerializer = Serializer.GetSerializer(GetType(Templates.Entities.MESOWebServiceResult)) RaiseEvent WebServiceProgress(Me, "Antwort verarbeiten") Select Case oContentType Case "text/xml" WriteResponseFile(pPath, pBaseFileNAme, oResponseBody, "xml") Dim oBytes As Byte() = Encoding.UTF8.GetBytes(oResponseBody) Using oStream As New IO.MemoryStream(oBytes) Dim oResponseObject As Templates.Entities.MESOWebServiceResult = oSerializer.Deserialize(oStream) Dim oErrorStrings As New List(Of String) For Each oDetails As Templates.Entities.MESOWebServiceResultResultDetails In oResponseObject.ResultDetails If oDetails.Success = True Then Logger.Info("KeyValue: [{0}]", oDetails.KeyValue) Logger.Info("VoucherNumber: [{0}]", oDetails.VoucherNumber) Else Logger.Warn("ErrorCode: [{0}]", oDetails.ErrorCode) Logger.Warn("ErrorText: [{0}]", oDetails.ErrorText) oErrorStrings.Add($"[{oDetails.ErrorCode}] {oDetails.ErrorText}") End If Next If oResponseObject.OverallSuccess = False Then Dim oMessage = $"Request to Webservice was unsuccessful:{vbNewLine}{vbNewLine}{String.Join(vbNewLine, oErrorStrings.ToArray)}" Throw New ApplicationException(oMessage) End If End Using Case "text/html" WriteResponseFile(pPath, pBaseFileNAme, oResponseBody, "txt") Throw New ApplicationException(oResponseBody) Case Else Throw New ApplicationException(oResponseBody) End Select End Function Private Function WriteResponseFile(pPath As String, pBaseFileName As String, pResponseBody As String, pExtension As String) Try Dim oRequestFileName As String = GetXmlFilenameWithSuffix(pBaseFileName, "Response", pExtension) Dim oFilePath As String = IO.Path.Combine(pPath, oRequestFileName) IO.File.WriteAllText(oFilePath, pResponseBody) Return True Catch ex As Exception Logger.Error(ex) Return False End Try End Function Private Function GetBytesFromDocument(pDocument As Document) As Byte() ' TODO: should "Lief_Name" be included here? Dim oFilteredFields As New List(Of String) From { "Fakt_Name" } Using oStream As New IO.MemoryStream() Dim w = XmlWriter.Create(oStream) w.WriteStartDocument() w.WriteStartElement("MESOWebService") w.WriteAttributeString("Template", pDocument.TemplateName) w.WriteAttributeString("TemplateType", pDocument.TemplateType) w.WriteAttributeString("option", pDocument.Option) w.WriteAttributeString("printVoucher", pDocument.PrintVoucher) pDocument.Rows.Sort() For Each oRow In pDocument.Rows w.WriteStartElement(oRow.Name) For Each oField As KeyValuePair(Of String, DocumentRow.FieldValue) In oRow.Fields If oField.Value.Final = String.Empty Then Continue For End If If oFilteredFields.Contains(oField.Key) Then Continue For End If w.WriteStartElement(oField.Key) w.WriteValue(oField.Value.Final) w.WriteEndElement() ' Field Next w.WriteEndElement() ' Row Next w.WriteEndElement() ' MESOWebService w.WriteEndDocument() ' Document w.Close() Return oStream.ToArray() End Using End Function Private Function GetBaseWebServicePath() As String Return IO.Path.Combine(AppDataPath, "WebService") End Function Private Function GetBaseFilenameForRequest() As String Return $"{Now:yyyy-MM-dd_hh-mm-ffff}" End Function Private Function GetXmlFilenameWithSuffix(pBaseString As String, pSuffix As String, pExtension As String) Return $"{pBaseString}-{pSuffix}.{pExtension}" End Function Private Function GetDateSubDirectoryPath(pBasePath As String) Dim oDirectoryPath As String = Now.ToString("yyyy\\MM\\dd") Dim oFullPath As String = IO.Path.Combine(pBasePath, oDirectoryPath) If IO.Directory.Exists(oFullPath) = False Then Try IO.Directory.CreateDirectory(oFullPath) Return oFullPath Catch ex As Exception Logger.Error(ex) Return Nothing End Try Else Return oFullPath End If End Function End Class End Namespace