PersistenceMapperWEBAPIClient
Previously, we had the PersistenceMapperWCFClient that connects to a RemotePeristenceMapper (like the MDrivenServer, for example).
Now, we also have the PersistenceMapperWEBAPIClient. It does the same thing but does not use WCF; instead, it defaults to transport over HTTPS.
The main reason for this novelty is that Microsoft is moving away from WCF in .netStandard and ASP.Core.
Since we introduced the PersistenceMapperWEBAPIClient, we have also added a few new functions that we found useful:
- The ability to compare checksum between the client and server of the model content is important since a client who has the wrong model cannot be allowed to save objects to the server. Because we want to notify the user of this as soon as possible, we need a way to discover this fact early in the client-application -lifecycle.
- Another useful function is the "Closed for business" message. This is useful in environments that require some downtime in order for maintenance - like a new deployment.
Client Configure PMP to talk to MDrivenServer over WebApi
public MDrivenProject9PMP() : base() { this.InitializeComponent(); MDriven.WebApi.Client.PersistenceMapperWEBAPIClient pm = new MDriven.WebApi.Client.PersistenceMapperWEBAPIClient(); pm.Uri = "http://localhost:5003/api/A0_WebApi"; pm.ServerPassword = "123456"; pm.ServerUserName = "a"; this.PersistenceMapper = pm; }
Checksum
public static void CheckIfOkToStartWithChecksum(PersistenceMapperWEBAPIClient pmapperWebClient, int checksumForThisES, IEcoTypeSystem typesystem, IAsyncSupportService asy) { BackgroundWorker bw = new BackgroundWorker(); bw.DoWork += (sender, e) => { CheckInBAckgroundThread(pmapperWebClient, checksumForThisES, typesystem, asy); }; bw.RunWorkerAsync(); } private static void CheckInBAckgroundThread(PersistenceMapperWEBAPIClient pmapperWebClient, int checksumForThisES, IEcoTypeSystem typesystem, IAsyncSupportService asy) { int tries = 0; DateTime time = DateTime.Now; bool ok = false; while (!ok && tries < 3 && (DateTime.Now - time) < TimeSpan.FromMinutes(1)) { try { tries++; var res = pmapperWebClient.UsedHttpClient.GetStringAsync("CompareChecksumReturnDiffData?checksum=" + checksumForThisES.ToString()).Result; if (!string.IsNullOrEmpty(res.Replace('\"',' ').Trim())) { asy.DispatchTaskToMainThread(() => { HandleUserNotifications(res, typesystem); }); } ok = true; } catch (Exception ex) { System.Threading.Thread.Sleep(200); } } } private static void HandleUserNotifications(string serverchecksumdata, IEcoTypeSystem typesystem) { var text = "WARNING - THE MDrivenServer SERVER HAS A DIFFERENT MODEL THAN YOU!!!\r\n" + "\r\n" + "The safe thing to do is to evolve the server...\r\n"; string checksumdata = (typesystem as Eco.UmlRt.Impl.EcoTypeSystem).GetCheckSumData(); if (serverchecksumdata != null && checksumdata != null) { int chunks = serverchecksumdata.Length / 200; int x = 0; string diffs = ""; for (int i = 0; i < chunks; i++) { string s1 = serverchecksumdata.Substring(x * 200, 200); string s2 = checksumdata.Substring(x * 200, 200); if (s1 == s2) { } else { s1 = serverchecksumdata.Substring(Math.Max(0, (x * 200) - 50), 200 + 50 + 50); //Show a bit before and after the diff s2 = checksumdata.Substring(Math.Max(0, (x * 200) - 50), 200 + 50 + 50); diffs += x.ToString() + " SERVER:" + s1 + "\r\n"; diffs += x.ToString() + " CLIENT:" + s2 + "\r\n"; diffs += "\r\n"; break; } x++; } MessageBox.Show(text + diffs); Application.Current.Shutdown(); } }
Closed for Business
private static BackgroundWorker _bw; public static void UpdateScheduledClosing(PersistenceMapperWEBAPIClient pmapperWebClient, DateTime appStartTime) { if (_bw == null) { _bw = new BackgroundWorker(); _bw.DoWork += (sender, e) => { GetScheduledShutdown(pmapperWebClient, appStartTime); }; _bw.RunWorkerCompleted += (sender, e) => { _bw = null; }; _bw.RunWorkerAsync(); } } public static DateTime? ScheduledShutdown { set; get; } public static string ScheduledShutdownMessage { set; get; } private static void GetScheduledShutdown(PersistenceMapperWEBAPIClient pmapperWebClient, DateTime appStartTime) { try { var res = pmapperWebClient.UsedHttpClient.GetStringAsync("GetScheduledClosing").Result; if (!string.IsNullOrEmpty(res)) { var doc = XDocument.Parse(res.Replace('\"', ' ')); if (doc != null && doc.Root != null) { var time = doc.Root.Element(XName.Get("time")); var message = doc.Root.Element(XName.Get("message")); DateTime timeDT; if (DateTime.TryParse(time.Value, out timeDT)) { if (timeDT > appStartTime) { ScheduledShutdown = timeDT; ScheduledShutdownMessage = message.Value; } } } } } catch { // not the end of the world } }
For the GetScheduledClosing, we have a function in MDrivenServer to set this:
You can then have your application check and show this message:
private void CheckScheduledClosing(out bool avoidFurtherWork) { avoidFurtherWork = false; MDrivenServerCheckModelChecksum.UpdateScheduledClosing(_ecospace.MainDataAccessWEBAPIClient, _AppStartTime); if (MDrivenServerCheckModelChecksum.ScheduledShutdown.HasValue) { if (MDrivenServerCheckModelChecksum.ScheduledShutdown.Value < DateTime.UtcNow && MDrivenServerCheckModelChecksum.ScheduledShutdown.Value > _AppStartTime) { avoidFurtherWork = true; Shutdown(); return; } else { var diff = (MDrivenServerCheckModelChecksum.ScheduledShutdown.Value - DateTime.UtcNow); string info = Math.Round(diff.TotalMinutes, 2).ToString() + " minutes left"; DisplayAdminMessage("Scheduled Shutdown:" + MDrivenServerCheckModelChecksum.ScheduledShutdown.Value.ToLocalTime().ToLongTimeString() + " " + MDrivenServerCheckModelChecksum.ScheduledShutdownMessage + " " + info, false); return; } } }
This page was edited more than 6 months ago on 06/17/2024. What links here