From a5cfbdfc96f506b5ddc66f81086fd99e353b3007 Mon Sep 17 00:00:00 2001 From: Rene Evertz Date: Wed, 30 Oct 2024 11:43:23 +0100 Subject: [PATCH] Gkv8 sendet an Kundenapp Bei Fehler wird es aufm App8 als ResultXML gespeichert --- BeWo/ServiceProxy/Generated.cs | 4 +- DakotaSender/DakotaSender.csproj | 2 +- DakotaSender/FileController.cs | 80 ++++++ DakotaSender/Program.cs | 227 +++++++----------- DakotaSender/ResultXml.cs | 30 --- DakotaUnitTest/fehler_example.xml | 2 +- Host/GkvAbrechnungServer.aspx.cs | 4 +- .../AccountingServiceImp.cs | 2 +- .../GkvAbrechnung/GkvClientResultRequestDC.cs | 10 +- .../GkvAbrechnung/GkvServerResultDC.cs | 2 +- .../GkvAbrechnung/GkvServerResultXml.cs | 33 ++- Shared/Exceptions/GkvException.cs | 18 +- 12 files changed, 224 insertions(+), 190 deletions(-) create mode 100644 DakotaSender/FileController.cs delete mode 100644 DakotaSender/ResultXml.cs diff --git a/BeWo/ServiceProxy/Generated.cs b/BeWo/ServiceProxy/Generated.cs index 011f39f6f..cb3f0c484 100644 --- a/BeWo/ServiceProxy/Generated.cs +++ b/BeWo/ServiceProxy/Generated.cs @@ -2098,7 +2098,7 @@ namespace BeWo.ServiceProxy [System.ServiceModel.ServiceKnownTypeAttribute(typeof(System.Collections.Generic.List))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(BS.Shared.InvoiceType))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(BS.Shared.GkvTransferResultType))] - [System.ServiceModel.ServiceKnownTypeAttribute(typeof(BS.Shared.GkvAbrechnungApp8RequestTypeDC))] + [System.ServiceModel.ServiceKnownTypeAttribute(typeof(BS.Shared.RequestType))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(BS.Shared.DataContracts.GkvAbrechnung.GkvAbrechnungDC))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(System.Collections.Generic.List))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(BS.Shared.DataContracts.GkvAbrechnung.GkvTransferProtokollDC))] @@ -6336,7 +6336,7 @@ namespace BeWo.ServiceProxy [System.ServiceModel.ServiceKnownTypeAttribute(typeof(System.Collections.Generic.List))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(BS.Shared.InvoiceType))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(BS.Shared.GkvTransferResultType))] - [System.ServiceModel.ServiceKnownTypeAttribute(typeof(BS.Shared.GkvAbrechnungApp8RequestTypeDC))] + [System.ServiceModel.ServiceKnownTypeAttribute(typeof(BS.Shared.RequestType))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(BS.Shared.DataContracts.GkvAbrechnung.GkvAbrechnungDC))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(System.Collections.Generic.List))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(BS.Shared.DataContracts.GkvAbrechnung.GkvTransferProtokollDC))] diff --git a/DakotaSender/DakotaSender.csproj b/DakotaSender/DakotaSender.csproj index 9fedb922f..67c1688ef 100644 --- a/DakotaSender/DakotaSender.csproj +++ b/DakotaSender/DakotaSender.csproj @@ -45,9 +45,9 @@ + - diff --git a/DakotaSender/FileController.cs b/DakotaSender/FileController.cs new file mode 100644 index 000000000..1a3692e0b --- /dev/null +++ b/DakotaSender/FileController.cs @@ -0,0 +1,80 @@ +using BS.Shared.DataContracts.GkvAbrechnung; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DakotaSender +{ + internal static class FileController + { + internal static void CopyFileToFailed(DakotaSystemFile file) + { + var failed_folder = Config.FailedFolder; + + CopyFileTo(file.SourceAuftragsdatei, failed_folder.FullName); + CopyFileTo(file.SourceNutzdatendatei, failed_folder.FullName); + } + internal static void CopyFileToDestination(DakotaSystemFile file) + { + var folder = Config.LoadDatenannahmestelleFolder(file.Datenannahmestelle); + + CopyFileTo(file.SourceAuftragsdatei, folder.FullName, file.TransfernameAuf); + CopyFileTo(file.SourceNutzdatendatei, folder.FullName, file.Transfername); + } + internal static void CopyFileTo(FileSystemInfo file, string destination_folder, string file_name = null) + { + if (file_name is null) + file_name = file.Name; + + CopyFile(file.FullName, Path.Combine(destination_folder, file_name)); + } + internal static void CopyFile(string source, string destination) + { + Program.Print($"Kopiere \"{source}\" nach \"{destination}\". "); + + File.Copy(source, destination); + + Program.PrintLine("Ok."); + } + + internal static void DeleteQueueFile(DakotaSystemFile file) + { + DeleteFile(file.SourceAuftragsdatei.FullName); + DeleteFile(file.SourceNutzdatendatei.FullName); + } + internal static void DeleteDakotaFile(DakotaSystemFile file) + { + var folder = Config.LoadDatenannahmestelleFolder(file.Datenannahmestelle).FullName; + + DeleteFile(Path.Combine(folder, file.TransfernameAuf)); + DeleteFile(Path.Combine(folder, file.Transfername)); + } + internal static void DeleteFile(string file) + { + Program.Print($"Lösche {file}. "); + + File.Delete(file); + + Program.PrintLine("Ok."); + } + + internal static void SaveAsXmlFileInResultFolder(GkvServerResultDC result, string tenant, long user) + { + Program.Print($"Speichere Protokoll Oid \'{result.ProtokollOid}\' als Xml. "); + + var xml = GkvServerResultXml.ToXml(result, user); + + var folder = Config.GetResultTenantFolder(tenant).FullName; + var path = Path.Combine(folder, $"P{result.ProtokollOid}.xml"); + + Program.Print($"Path: {path}. "); + + XmlFileConverter.Save(xml, path); + + Program.PrintLine("Ok."); + } + } +} diff --git a/DakotaSender/Program.cs b/DakotaSender/Program.cs index c47ad2bde..5fae2b272 100644 --- a/DakotaSender/Program.cs +++ b/DakotaSender/Program.cs @@ -1,5 +1,8 @@ using BS.Shared; +using BS.Shared.AppSender; +using BS.Shared.DataContracts; using BS.Shared.DataContracts.GkvAbrechnung; +using BS.Shared.Exceptions; using System; using System.Collections.Generic; using System.Configuration; @@ -19,7 +22,7 @@ namespace DakotaSender static bool time_in_line = false; static bool is_dakota_running = false; - static Dictionary> handleRequests; + static Dictionary> ten2user2req; static void Main(string[] args) { @@ -37,10 +40,12 @@ namespace DakotaSender CheckDakotaStatus(); HandleQueueFiles(); + + HandleResults(); } catch (Exception e) { - PrintLine(e.ToString()); + PrintException(e); if (is_dakota_running) { @@ -52,46 +57,46 @@ namespace DakotaSender PrintEnd(); } - static void PrintTitle() + internal static void PrintTitle() { PrintWithTime("\n", false); PrintLine("-------------------"); PrintLine("Dakota Sender Modul"); PrintLine("-------------------"); } - static void PrintEnd() + internal static void PrintEnd() { PrintLine("Ende"); PrintLine("-------------------"); } - - static void PrintLine() => PrintLine(null); - static void PrintLine(string line) + internal static void PrintLine() => PrintLine(null); + internal static void PrintLine(string line) { PrintWithTime(line + "\n", !time_in_line); time_in_line = false; } - static void Print(string line) + internal static void Print(string line) { PrintWithTime(line, !time_in_line); time_in_line = true; } - static void PrintWithTime(string line, bool showTime) + internal static void PrintWithTime(string line, bool showTime) { if (showTime) Console.Write($"[{DateTime.Now:dd.MM.yy HH:mm:ss.fff}] {line}"); else Console.Write(line); } - static void PrintFileInfo(DakotaSystemFile file) + internal static void PrintFileInfo(DakotaSystemFile file) { PrintLine($"Verarbeite Datei: {file.SourceNutzdatendatei.Name}"); PrintLine($"- Tenant: {file.Tenant}"); PrintLine($"- Protokoll Oid: {file.ProtokollOid}"); PrintLine($"- Datenannahmestelle: {file.Datenannahmestelle}"); } + internal static void PrintException(Exception e) => PrintLine(e.ToString()); static void CheckDakotaStatus() { @@ -188,7 +193,7 @@ namespace DakotaSender if (ten2dat2files is null) return; - handleRequests = new Dictionary>(); + ten2user2req = new Dictionary>(); PrintLine(); foreach (var kv in ten2dat2files) @@ -203,72 +208,47 @@ namespace DakotaSender PrintLine($"Bearbeite Datenannahmestelle {dat} für Tenant {ten}."); - HandleQueueFiles(ten, dat, files); + HandleQueueFiles(files); } } } - - static void HandleQueueFiles(string tenant, string datenstelle, List files) + static void HandleQueueFiles(List files) { - List successful = new List(); - DakotaSystemFile error = null; - List followUpError = new List(); + bool error = false; foreach (var file in files) { - if (error is object) + if (!error) { - PrintLine($"Folgefehler: {file.SourceNutzdatendatei.Name}"); + var msg = HandleQueueFile(file, out bool success); - followUpError.Add(file); - continue; - } + if (success) + { + PrintLine(msg); - var msg = HandleQueueFile(file, out bool success); + Add2Results(file, GkvTransferResultType.Success); + } + else + { + error = true; - if (success) - { - successful.Add(file); + PrintLine("Fehler gefunden. " + msg); - PrintLine(msg); + Add2Results(file, GkvTransferResultType.FailSoft, msg, "DS:Fehler"); + + FileController.CopyFileToFailed(file); + } } else { - error = file; + PrintLine($"Folgefehler: {file.SourceNutzdatendatei.Name}"); - PrintLine("Fehler gefunden. " + msg); - - CopyFileToFailed(file); + Add2Results(file, GkvTransferResultType.FailFollowUp, "Wird neu erstellt und übertragen.", "DS:Folgefehler"); } - DeleteQueueFile(file); + FileController.DeleteQueueFile(file); } - - if (successful is object && !successful.Any()) - successful = null; - - if (followUpError is object && !followUpError.Any()) - followUpError = null; - - var application_user_oids = GetApplicationUserOids(successful, error, followUpError); - - if (!handleRequests.ContainsKey(tenant)) - handleRequests.Add(tenant, new Dictionary()); - - var p_successful = successful?.Select(x => new Tuple(x.ProtokollOid, x.ApplicationUserOid)).ToList(); - var p_error = error is object? new Tuple(error.ProtokollOid, error.ApplicationUserOid) : null; - var p_followup = followUpError?.Select(x => new Tuple(x.ProtokollOid, x.ApplicationUserOid)).ToList(); - - handleRequests[tenant].Add(datenstelle, new GkvClientResultRequestDC() - { - GkvSecretKey = Config.GkvSecretKey, - Tenant = tenant, - Protokoll_User_Success_Oid = p_successful, - Protokoll_User_Fehler_Oid = p_error, - Protokoll_User_Folgefehler_Oid = p_followup - }); } - /// /// Bearbeitet eine File. Wenn dakota.exe während der Bearbeitung gestartet wird, wird das Dakota Verzeichnis gesäubert und die weitere Bearbeitung durch throw Exception unterbrochen. /// @@ -284,7 +264,7 @@ namespace DakotaSender if (!Config.IsDatenannahmestelleValid(file.Datenannahmestelle)) return $"Datenannahmestelle {file.Datenannahmestelle} unbekannt."; - CopyFileToDestination(file); + FileController.CopyFileToDestination(file); Print("Sende via Dakota. "); @@ -294,79 +274,76 @@ namespace DakotaSender if (is_dakota_running) { - DeleteDakotaFile(file); + FileController.DeleteDakotaFile(file); throw new Exception(); } return message; } - - static List GetApplicationUserOids(List successful, DakotaSystemFile error, List followUpError) + static void Add2Results(DakotaSystemFile file, GkvTransferResultType type, string nachricht = null, string title = null) { - var res = new List(); + var tenant = file.Tenant; + var user = file.ApplicationUserOid; - if (successful is object) - successful.ForEach(x => res.Add(x.ApplicationUserOid)); + if (!ten2user2req.ContainsKey(tenant)) + ten2user2req.Add(tenant, new Dictionary()); - if (error is object) - res.Add(error.ApplicationUserOid); + var user2req = ten2user2req[tenant]; - if (followUpError is object) - followUpError.ForEach(x => res.Add(x.ApplicationUserOid)); + if (!user2req.ContainsKey(user)) + user2req.Add(user, new GkvClientResultRequestDC()); - return res; + var req = user2req[user]; + + if (req.ResultDCs is null) + req.ResultDCs = new List(); + + var item = new GkvServerResultDC(); + + item.Datum = DateTime.Now; + item.Nachricht = nachricht; + item.ProtokollOid = file.ProtokollOid; + item.ResultType = type; + item.Titel = title; + + req.ResultDCs.Add(item); } - static void CopyFileToFailed(DakotaSystemFile file) + static void HandleResults() { - var failed_folder = Config.FailedFolder; + foreach (var tenant in ten2user2req.Keys) + { + foreach (var user in ten2user2req[tenant].Keys) + { + var req = ten2user2req[tenant][user]; - CopyFileTo(file.SourceAuftragsdatei, failed_folder.FullName); - CopyFileTo(file.SourceNutzdatendatei, failed_folder.FullName); + HandleResult(req, tenant, user); + } + } } - static void CopyFileToDestination(DakotaSystemFile file) + static void HandleResult(GkvClientResultRequestDC req, string tenant, long user) { - var folder = Config.LoadDatenannahmestelleFolder(file.Datenannahmestelle); + try + { + var res = GkvSender.SendKundenAppClientRequest(req, tenant); - CopyFileTo(file.SourceAuftragsdatei, folder.FullName, file.TransfernameAuf); - CopyFileTo(file.SourceNutzdatendatei, folder.FullName, file.Transfername); - } - static void CopyFileTo(FileSystemInfo file, string destination_folder, string file_name = null) - { - if (file_name is null) - file_name = file.Name; + if (res.Success) + return; + } + catch(GkvException e) + { + PrintException(e); + } + catch(Exception e) + { + PrintException(e); + } - CopyFile(file.FullName, Path.Combine(destination_folder, file_name)); - } - static void CopyFile(string source, string destination) - { - Print($"Kopiere \"{source}\" nach \"{destination}\". "); - - File.Copy(source, destination); - - PrintLine("Ok."); - } - - static void DeleteQueueFile(DakotaSystemFile file) - { - DeleteFile(file.SourceAuftragsdatei.FullName); - DeleteFile(file.SourceNutzdatendatei.FullName); - } - static void DeleteDakotaFile(DakotaSystemFile file) - { - var folder = Config.LoadDatenannahmestelleFolder(file.Datenannahmestelle).FullName; - - DeleteFile(Path.Combine(folder, file.TransfernameAuf)); - DeleteFile(Path.Combine(folder, file.Transfername)); - } - static void DeleteFile(string file) - { - Print($"Lösche {file}. "); - - File.Delete(file); - - PrintLine("Ok."); + foreach (var result in req.ResultDCs) + { + FileController.SaveAsXmlFileInResultFolder(result, tenant, user); + } } static int ExecuteDakota(string arg) @@ -388,31 +365,5 @@ namespace DakotaSender throw new Exception($"dakota30.exe - Timeout exceeded ({Config.ProcessWaitForExitMs} ms). "); } } - - // static void CreateResultSuccessXmlFile(DakotaSystemFile file) - // => CreateResultXmlFile(file, "Dakota Erfolg", "", GkvTransferResultType.Success); - // static void CreateResultFehlerXmlFile(DakotaSystemFile file, string error) - // => CreateResultXmlFile(file, "Dakota Fehler", error, GkvTransferResultType.FailSoft); - // static void CreateResultXmlFile(DakotaSystemFile file, string title, string nachricht, GkvTransferResultType result_type) - //{ - // Print($"Speichere {title} als Xml. "); - - // var result = new ResultXml(); - - // result.Datum = DateTime.Now; - // result.Titel = title; - // result.Nachricht = nachricht; - // result.Level = (int)result_type; - // result.Oid = file.ProtokollOid; - - // var folder = Config.GetResultTenantFolder(file.Tenant).FullName; - // var path = Path.Combine(folder, $"P{file.ProtokollOid}.xml"); - - // Print($"Path: {path}. "); - - // XmlFileConverter.Save(result, path); - - // PrintLine("Ok."); - // } } } diff --git a/DakotaSender/ResultXml.cs b/DakotaSender/ResultXml.cs deleted file mode 100644 index f6545f4c4..000000000 --- a/DakotaSender/ResultXml.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Linq; -using System.Xml.Serialization; - -namespace DakotaSender -{ - [Serializable()] - [XmlRoot("Result")] - public class ResultXml - { - [XmlAttribute("Oid")] - public long Oid { get; set; } - - [XmlElement("Titel")] - public string Titel { get; set; } - - [XmlElement("Datum")] - public DateTime? Datum { get; set; } - - [XmlElement("Nachricht")] - public string Nachricht { get; set; } - - [XmlElement("Level")] - public int Level { get; set; } - } -} diff --git a/DakotaUnitTest/fehler_example.xml b/DakotaUnitTest/fehler_example.xml index dc8a4bbe9..09176d907 100644 --- a/DakotaUnitTest/fehler_example.xml +++ b/DakotaUnitTest/fehler_example.xml @@ -1,5 +1,5 @@  - + 31 2024-06-01T09:00:00 TestNach diff --git a/Host/GkvAbrechnungServer.aspx.cs b/Host/GkvAbrechnungServer.aspx.cs index 6a95acb3b..bca713b3b 100644 --- a/Host/GkvAbrechnungServer.aspx.cs +++ b/Host/GkvAbrechnungServer.aspx.cs @@ -264,7 +264,7 @@ namespace Host { var xml_obj = GkvServerResultXml.GetResultXml(file.FullName); - if (xml_obj is GkvServerResultXml xml && oids.Contains(xml.Oid)) + if (xml_obj is GkvServerResultXml xml && oids.Contains(xml.ProtokollOid)) continue; file.Delete(); @@ -297,7 +297,7 @@ namespace Host if (xml is null) continue; - dict.Add(xml.Oid, GkvServerResultXml.ToDC(xml)); + dict.Add(xml.ProtokollOid, GkvServerResultXml.ToDC(xml)); } return dict; } diff --git a/Service/ServiceImplementations/AccountingServiceImp.cs b/Service/ServiceImplementations/AccountingServiceImp.cs index 3bd14b76a..ee5085eac 100644 --- a/Service/ServiceImplementations/AccountingServiceImp.cs +++ b/Service/ServiceImplementations/AccountingServiceImp.cs @@ -1182,7 +1182,7 @@ namespace BeWo.Service.ServiceImplementations var gkv_abrechnung_entity = DAOFactory.GenericDAO.LoadByID(gkv_abrechnung.GkvAbrechnungOid.Value); - var protokoll = gkv_abrechnung_entity.GkvTransferProtokolle.First(x => x.Oid == result.Oid); + var protokoll = gkv_abrechnung_entity.GkvTransferProtokolle.First(x => x.Oid == result.ProtokollOid); protokoll.ResultType = result.ResultType; protokoll.Fehlerdatum = result.Datum; diff --git a/Shared/DataContracts/GkvAbrechnung/GkvClientResultRequestDC.cs b/Shared/DataContracts/GkvAbrechnung/GkvClientResultRequestDC.cs index 3374103ac..c6cd77ff5 100644 --- a/Shared/DataContracts/GkvAbrechnung/GkvClientResultRequestDC.cs +++ b/Shared/DataContracts/GkvAbrechnung/GkvClientResultRequestDC.cs @@ -13,11 +13,11 @@ namespace BS.Shared.DataContracts.GkvAbrechnung : base(RequestType.GkvClientResult) { } [DataMember] public string GkvSecretKey { get; set; } + [DataMember] public long UserOid { get; set; } - [DataMember] public IList Application_User_Oids { get; set; } - - [DataMember] public IList Protokoll_Success_Oid { get; set; } - [DataMember] public long? Protokoll_Fehler_Oid { get; set; } - [DataMember] public IList Protokoll_Folgefehler_Oid { get; set; } + [DataMember] public IList ResultDCs { get; set; } + //[DataMember] public IList> Protokoll_User_Success_Oid { get; set; } + //[DataMember] public Tuple Protokoll_User_Fehler_Oid { get; set; } + //[DataMember] public IList> Protokoll_User_Folgefehler_Oid { get; set; } } } diff --git a/Shared/DataContracts/GkvAbrechnung/GkvServerResultDC.cs b/Shared/DataContracts/GkvAbrechnung/GkvServerResultDC.cs index f4e5aaaaa..b975d0fba 100644 --- a/Shared/DataContracts/GkvAbrechnung/GkvServerResultDC.cs +++ b/Shared/DataContracts/GkvAbrechnung/GkvServerResultDC.cs @@ -11,7 +11,7 @@ namespace BS.Shared.DataContracts.GkvAbrechnung [DataContract] public class GkvServerResultDC { - [DataMember] public long Oid { get; set; } + [DataMember] public long ProtokollOid { get; set; } [DataMember] public string Titel { get; set; } [DataMember] public DateTime? Datum { get; set; } [DataMember] public string Nachricht { get; set; } diff --git a/Shared/DataContracts/GkvAbrechnung/GkvServerResultXml.cs b/Shared/DataContracts/GkvAbrechnung/GkvServerResultXml.cs index 7fd2dfecf..646962bd1 100644 --- a/Shared/DataContracts/GkvAbrechnung/GkvServerResultXml.cs +++ b/Shared/DataContracts/GkvAbrechnung/GkvServerResultXml.cs @@ -13,8 +13,11 @@ namespace BS.Shared.DataContracts.GkvAbrechnung [XmlRoot("Result")] public class GkvServerResultXml { - [XmlAttribute("Oid")] - public long Oid { get; set; } + [XmlAttribute("ProtokollOid")] + public long ProtokollOid { get; set; } + + [XmlAttribute("UserOid")] + public long UserOid { get; set; } [XmlElement("Titel")] public string Titel { get; set; } @@ -50,17 +53,31 @@ namespace BS.Shared.DataContracts.GkvAbrechnung } } - public static GkvServerResultDC ToDC(GkvServerResultXml fehler) + public static GkvServerResultDC ToDC(GkvServerResultXml result) { var dc = new GkvServerResultDC(); - dc.Oid = fehler.Oid; - dc.Titel = fehler.Titel; - dc.Datum = fehler.Datum; - dc.Nachricht = fehler.Nachricht; - dc.ResultType = (GkvTransferResultType)fehler.Level; + dc.ProtokollOid = result.ProtokollOid; + dc.Titel = result.Titel; + dc.Datum = result.Datum; + dc.Nachricht = result.Nachricht; + dc.ResultType = (GkvTransferResultType)result.Level; return dc; } + + public static GkvServerResultXml ToXml(GkvServerResultDC dc, long useroid) + { + var xml = new GkvServerResultXml(); + + xml.ProtokollOid = dc.ProtokollOid; + xml.UserOid = useroid; + xml.Titel = dc.Titel; + xml.Datum = dc.Datum; + xml.Nachricht = dc.Nachricht; + xml.Level = (int)dc.ResultType; + + return xml; + } } } diff --git a/Shared/Exceptions/GkvException.cs b/Shared/Exceptions/GkvException.cs index 38ee54b30..c3bcbda97 100644 --- a/Shared/Exceptions/GkvException.cs +++ b/Shared/Exceptions/GkvException.cs @@ -25,5 +25,21 @@ namespace BS.Shared.Exceptions { } - } + + public override string ToString() + { + var sb = new StringBuilder(); + + if (!string.IsNullOrEmpty(Title)) + sb.Append(Title + " - "); + + if (!string.IsNullOrEmpty(Message)) + sb.Append(Message + " - "); + + if(sb.Length == 0) + sb.Append(base.ToString()); + + return sb.ToString(); + } + } }