private void ConnectionEstablished(object sender, ConnectionEstablishedEventArgs e) { log.Info("TpsService: Tps Connection is established."); peer = e.RemoteTcpPeer; log.Info($"TpsService: Connected to [{peer.IPEndPoint}]"); TpsConnectionEstablished?.Invoke(); }
private async Task OnPostpaySaleSuccess() { log.Info("CardTenderViewModel: Payment Approved.Generate and print receipt for postpay."); posManager.ActiveSale.Receipt = receiptGenerator.PostPayCard(posManager.ActiveSale); posManager.ActiveSale.PaymentStatus = PaymentApprovalStatus.PaymentApproved; await GoToPrintReceipt(); }
/// <summary> /// Handles the selection of a device by the user /// </summary> /// <param name="deviceViewModel">Device view model.</param> private async void HandleSelectedDevice() { _log.Info("Attempting to handle selected bluetooth device"); // Check bluetooth status and if not on, exit if (!_bluetoothService.IsOn) { _log.Info("Bluetooth is not on"); _userDialogs.Toast($"\tError: {_bluetoothService.StateText}"); return; } // Device is already connected if (IsConnected) { _log.Info("Device is already connected. Attempting to disconnect."); Task.Run(async() => await TryToDisconnectDevice()); _log.Debug("Disconnection task <TryToDisconnectDevice> has been spawned."); return; } // Device has not connected yet else { _log.Info("Connecting to device."); var slots = _deviceSlotService.GetAvailableSlots(); var buttons = new List <string>(); if (slots.Count > 0) { foreach (var slotIndex in slots) { try { string name = _deviceSlotService.SlotName[slotIndex]; buttons.Add(name); } catch (KeyNotFoundException) { _userDialogs.Alert("Invalid slot index value"); return; } } var result = await _userDialogs.ActionSheetAsync("Which device?", "Cancel", null, null, buttons.ToArray()); if (result == "Cancel") { return; } var selected = _deviceSlotService.SlotName.IndexOf(result); await Task.Run(async() => await TryToConnectDevice(selected)); return; } else { _userDialogs.Alert("Please disconnect from a device before attempt to connect to another one"); } } }
public JsValue PerformRequest(string url) { _log.Info($"Music provider ({_musicProvider.Manifest.Name}) is requesting a url: {url}"); return(AsyncHelper.RunSync(async() => { var content = await url.WithHeader("User-Agent", "SoundByte App") .HandleAuthExpireAsync(_authenticationService, _musicProvider); return content; })); }
public PCNetworkListenerViewModel(IMvxLogProvider logProvider, IMvxNavigationService navigationService) : base(logProvider, navigationService) { _log = logProvider.GetLogFor <PCNetworkListenerViewModel>(); _log.Info("PCNetworkListenerViewModel has been constructed {logProvider} {navigationService}", logProvider, navigationService); _parser = new ComboBoxSQLParseManager(logProvider); // Setup UI Commands RefreshNetMsgCommand = new MvxCommand(GetLogsFromManager); // Fetch Initial Data _stopwatch = new Stopwatch(); GetLogsFromManager(); // get singleton and create event handler IPcNetworkListener pcNetworkListener = Mvx.IoCProvider.Resolve <IPcNetworkListener>(); pcNetworkListener.MessageHit += PCNetworkManagerOnMessage; // set initial UI Fields int listeningPort = pcNetworkListener.GetAppSettingsDataUdpPort(); ListeningUDPPort = listeningPort.ToString(); TimeSinceLastStartup = GetDateFromTimeSpan(); RemoteControlTimeStamp = ""; }
private async Task LogOut(bool closeTill) { log.Debug("LogoutViewModel:Started Logout process."); var result = posManager.PosLogout(closeTill); if (!result) { log.Error("LogoutViewModel: Logout failed."); log.Info("LogoutViewModel: Show MessageBox to user and inform him to retry."); var response = messageBoxService.ShowMessageBox("ConnectionLoseWhileLogout", MessageBoxButtonType.OK); log.Debug("LogoutViewModel: Close the navigation."); await navigationService.Close(this); } else { log.Debug("LogoutViewModel: Successful logout."); if (App.IsFcsConnected) { log.Debug("LogoutViewModel: Fcs is connected. try to sign off."); await App.SignOffAsync(); } else { log.Error("LogoutViewModel: Fcs is not connected.Go to LoginViewModel."); await navigationService.Navigate <LoginViewModel>(); } } }
public string GetPassword() { string keyVaultName = Settings.Default.AzureKeyVaultName; string kvUri = $"https://{keyVaultName}.vault.azure.net"; Response <KeyVaultSecret> secret; try { SecretClient client = new(new Uri(kvUri), new DefaultAzureCredential()); secret = client.GetSecret(Settings.Default.AzureKeyVaultGitHubPassword); _log.Info("Got Azure secret!"); } catch (Exception e) { _log.ErrorException("Getting Azure secret failed", e); secret = null; } // async version- prob not a good idea //var secret = await client.GetSecretAsync(secretName); return(secret?.Value.Value); }
public MainViewModel(IMvxLogProvider logProvider, IMvxNavigationService navigationService) : base(logProvider, navigationService) { _log = logProvider.GetLogFor <MainViewModel>(); _log.Info("Main VM constrcuted"); //ShowChildCommand = new MvxAsyncCommand(async () => await NavigationService.Navigate<ChildViewModel>()); //ShowModalCommand = new MvxAsyncCommand(async () => await NavigationService.Navigate<ModalViewModel>()); //ShowModalNavCommand = // new MvxAsyncCommand(async () => await NavigationService.Navigate<ModalNavViewModel>()); //ShowTabsCommand = new MvxAsyncCommand(async () => await NavigationService.Navigate<TabsRootViewModel>()); //ShowSplitCommand = new MvxAsyncCommand(async () => await NavigationService.Navigate<SplitRootViewModel>()); //ShowOverrideAttributeCommand = new MvxAsyncCommand(async () => // await NavigationService.Navigate<OverrideAttributeViewModel>()); //ShowSheetCommand = new MvxAsyncCommand(async () => await NavigationService.Navigate<SheetViewModel>()); ShowWindowCommand = new MvxAsyncCommand(async() => await NavigationService.Navigate <WindowViewModel>()); //ShowMixedNavigationCommand = // new MvxAsyncCommand(async () => await NavigationService.Navigate<MixedNavFirstViewModel>()); ShowCustomBindingCommand = new MvxAsyncCommand(async() => await NavigationService.Navigate <CustomBindingViewModel>()); _counter = 3; }
protected void LogInfo(string message, [CallerMemberName] string caller = null) { using (LogContext.PushProperty("class", _typNme)) using (LogContext.PushProperty("method", caller)) { _log.Info(message); } }
public Boolean SetCurrentTheme(String name, Boolean applySetting) { try { // Find theme for name IMesTheme theme = Themes.FirstOrDefault(x => x.Name == name); if (theme == null) { return(false); } CurrentTheme = theme; // Setup asnc info Mvx.IoCProvider.Resolve <IMvxMainThreadAsyncDispatcher>() .ExecuteOnMainThreadAsync(() => { // Setup app style ResourceDictionary appTheme = Application.Current.Resources.MergedDictionaries.Count > 0 ? Application.Current.Resources.MergedDictionaries[0] : null; if (appTheme == null) { appTheme = new ResourceDictionary(); Application.Current.Resources.MergedDictionaries.Add(appTheme); } appTheme.BeginInit(); appTheme.MergedDictionaries.Clear(); foreach (Uri uri in theme.ApplicationResources) { ResourceDictionary newDict = new ResourceDictionary { Source = uri }; appTheme.MergedDictionaries.Add(newDict); } appTheme.EndInit(); }); _log.Info($"Theme set to {name}"); // publish event _messenger.Publish(new MesThemeChangeMessage(this, CurrentTheme.Name)); if (applySetting) { Properties.Settings.Default.ThemeName = CurrentTheme.Name; } return(true); } catch (Exception e) { _log.InfoException("Log Theme Setting", e); return(false); } }
private void ProposeNewPrice(double amount) { if (SelectedGrade == null) { log.Error("GradesViewModel: Selected Grade is null."); return; } SelectedGrade.NewPrice = amount; log.Info("GradesViewModel: Entry amount {0} for new price of {1}.", amount, SelectedGrade.CurrentData.Type); }
public PCControllerInfoViewModel(IMvxLogProvider logProvider, IMvxNavigationService navigationService) : base(logProvider, navigationService) { _log = logProvider.GetLogFor <PCControllerInfoViewModel>(); RefreshLogCommand = new MvxCommand(GetLogsFromManager); _parser = new ComboBoxSQLParseManager(logProvider); _log.Info("PCControllerViewModel has been constructed {logProvider} {navigationService}", logProvider, navigationService); GetAppInfo(); _stopwatch = new Stopwatch(); GetLogsFromManager(); }
public void GetLogsFromManager() { _stopwatch.Start(); SQLiteCRUD sql = new(ConnectionStringManager.GetConnectionString(ConnectionStringManager.DataBases.PCControllerDB)); ProcMonitorModel procData = new(); int numLogs = _parser.GetLogs(NumberOfNetMsgToFetch); _log.Info("Getting Data Logs from {sql} number: {numOfMsgs}", sql, numLogs); IList <NetworkMessageModel> rows = sql.GetSomeNetData(numLogs); NetGridRows = rows; _stopwatch.Stop(); string timeToFetchFromDb = $" DB query time: {_stopwatch.ElapsedMilliseconds} ms"; DataBaseQueryTime = timeToFetchFromDb; RaisePropertyChanged(() => NetGridRows); RaisePropertyChanged(() => DataBaseQueryTime); }
private async void ConfigurePaymentServer() { log.Debug("App: Configuring Tps.."); try { var tpsService = Mvx.IoCProvider.Resolve <ITpsService>(); tpsService.TpsConnectionClosed += async() => { IsTpsConnected = false; log.Info("App: Attempting to re-establish connection to TPS..."); await tpsService.ConnectAsync(); }; tpsService.TpsConnectionEstablished += () => IsTpsConnected = true; log.Info("App: Establishing Connection to TPS..."); await tpsService.ConnectAsync(); } catch (Exception ex) { log.ErrorException("App: ", ex); } }
private async void SubscribeToUpdates(object sender, SlotEventArgs args) { var slot = args.Slot; if (slot.Index != _slot.Index) { return; } var device = _slot.ConnectedDevice; if (device != null) { try { _batteryUpdateEventHandler = new EventHandler <CharacteristicUpdatedEventArgs>((s, a) => SetBatteryStatus(s, a)); device.BatteryCharacteristic.ValueUpdated += _batteryUpdateEventHandler; _infoUpdateEventHandler = new EventHandler <CharacteristicUpdatedEventArgs>((s, a) => SetSessionStatus(s, a)); device.InfoCharacteristic.ValueUpdated += _infoUpdateEventHandler; _log.Info("Sending Get Info Command."); var commandSuccessful = await SendCommand(CommandType.GetInfo); if (commandSuccessful) { _log.Info("Command successfully sent."); } //BatteryLevel = -1; //SessionStatus = -1; } catch (Exception) { _log.Error("Characteristic subscription for data logging could not be completed."); } } }
public GitHubManager(IMvxLogProvider logProvider) { _log = logProvider.GetLogFor <GitHubManager>(); _log.Info("GitHubManager has been constructed"); // setting private variables _monitoredAppPath = Settings.Default.MonitoredAppPath; _monitoredAppBackupPath = Settings.Default.MonitoredAppBackupPath; _monitoredAppTempPath = Settings.Default.MonitoredAppTempPath; _defaultRepo = Settings.Default.GitHubReleaseRepo; _gitHubUser = Settings.Default.GitHubAccountOwner; ProductHeaderValue productInformation = new ProductHeaderValue(GitHubIdentity); _log.Info("Calling AzureKeyManager for GitHubAuth(Password/Token)"); AzureKeyManager keyManager = new AzureKeyManager(logProvider); _githubPassword = keyManager.GetPassword(); if (_githubPassword != null) { if (!TryGetClient(productInformation, out GitHubClient client)) { return; } GetClient(productInformation, _gitHubUser, _githubPassword); GitHubClient = client; } else //TODO make sure this code is reachable { _githubPassword = PCController.Core.Properties.Settings.Default.AzureFallBackLocalSecret; _log.Info("using the fallback string {_githubPassword}", _githubPassword); } }
private void DonateInteraction(INInteraction interaction) { interaction.DonateInteraction( error => { if (error != null) { _logger.Error($"Interaction donation failed: {error}"); } else { _logger.Info("Successfully donated interaction."); } }); }
public AppDeployViewModel(IMvxLogProvider logProvider, IMvxNavigationService navigationService) : base(logProvider, navigationService) { _log = logProvider.GetLogFor <AppDeployViewModel>(); _log.Info("AppDeployViewModel has been constructed {logProvider} {navigationService}", logProvider, navigationService); _stopwatch = new Stopwatch(); // Setup UI Commands CheckForAppUpdateCommand = new MvxCommand(CheckAppUpdate); CheckAppVersionCommand = new MvxCommand(CheckAppVersion); SaveSettingsCommand = new MvxCommand(SaveCDSettings); CheckSettingsCommand = new MvxCommand(CheckCDConnectionSettings); // set initial UI Fields // Fetch Initial Data }
private void SetAmount() { if (this.CurrentAmountInString != null && this.CurrentAmountInString.Length > 0) { log.Info("PrepayViewModel: Customer Entry amount {0} for fueling.", Amount); if (this.CurrentAmountInString[this.CurrentAmountInString.Length - 1] == '.') { this.CurrentAmountInString += "0"; } Amount = Convert.ToDouble(this.CurrentAmountInString); log.Debug("PrepayViewModel: Navigate to PaymentProcessing page."); } else { log.Error("PrepayViewModel: CurrentAmount is null or empty."); } }
/// <summary> /// Initializes a new instance of the <see cref="T:UHMS.Core.Services.BluetoothService"/> class. /// </summary> /// <param name="sensorDataService">Handler for incoming sensor data.</param> /// <param name="adapter">Adapter used to manage the peripheral bluetooth connections.</param> /// <param name="bluetooth">Interface to the central bluetooth device.</param> /// <param name="userDialogs">Dialogs to manage user-oriented output to the UI.</param> /// <param name="log">Logger primarily for debugging and record purposes.</param> public BluetoothService(ISensorDataService sensorDataService, IDataLoggingService dataLoggingService, IDeviceSlotService deviceSlotService, IAdapter adapter, IBluetoothLE bluetooth, IUserDialogs userDialogs, IMvxLog log) { // Services _sensorDataService = sensorDataService; _dataLoggingService = dataLoggingService; _deviceSlotService = deviceSlotService; _adapter = adapter; _bluetooth = bluetooth; _userDialogs = userDialogs; _log = log; _log.Info("Initializing Bluetooth Service."); // Event tracker for subscribed characteristics. _characteristicEventAggregator = new ConcurrentDictionary <ICharacteristic, EventHandler <CharacteristicUpdatedEventArgs> >(); OutputData = new List <int>(); SubscribedCharacteristicsList = new List <DataType>(); }
public HomeViewModel(IMvxLogProvider logProvider, IMvxNavigationService navigationService) : base(logProvider, navigationService) { _log = logProvider.GetLogFor <HomeViewModel>(); _log.Info("HomeViewModel has been constructed {logProvider} {navigationService}", logProvider, navigationService); _stopwatch = new Stopwatch(); // Setup UI Commands RefreshLogCommand = new MvxCommand(GetLogsFromManager); StartAutoLogRefreshCommand = new MvxCommand(StartLogLoop); StopAutoLogRefreshCommand = new MvxCommand(StopLogLoop); OpenScriptsFolderCommand = new MvxCommand(OpenFolder); // set initial UI Fields LogRefreshInterval = Settings.Default.AutoRefreshLogInterval; AutoLogRefreshTrueButtonStatus = false; AutoLogRefreshFalseButtonStatus = true; RaisePropertyChanged(() => AutoLogRefreshTrueButtonStatus); RaisePropertyChanged(() => AutoLogRefreshFalseButtonStatus); // Fetch Initial Data StartLogLoop(); }
public void AddUdpFrame(string frame) { try { string message = frame; _log.Info("Going to send a message over the UDP driver {message}", message); if (message.Contains("!0D!0A")) { message = message.Replace("!0D!0A", "\r\n"); byte[] inputBytes = Encoding.ASCII.GetBytes(message); // new byte array and feed it the input string _asyncUdpLink.SendMessage(inputBytes); _log.Info("Message contained <crlf>, replaced the hex with ASCII to be sent properly {message}", message); } else if (message.Contains("!0D")) { message = message.Replace("!0D", "\r"); byte[] inputBytes = Encoding.ASCII.GetBytes(message); // new byte array and feed it the input string _asyncUdpLink.SendMessage(inputBytes); _log.Info("Message contained <cr>, replaced the hex with ASCII to be sent properly {message}", message); } else if (message.Contains("!0A")) { message = message.Replace("!0A", "\n"); byte[] inputBytes = Encoding.ASCII.GetBytes(message); // new byte array and feed it the input string _asyncUdpLink.SendMessage(inputBytes); _log.Info("Message contained <lf>, replaced the hex with ASCII to be sent properly {message}", message); } else { byte[] inputBytes = Encoding.ASCII.GetBytes(message); // new byte array and feed it the input string _asyncUdpLink.SendMessage(inputBytes); _log.Info("Message did not contain any ending characters {message}", message); } } catch (Exception e) { _log.ErrorException("Parsing the FrameToSend has failed {e}", e); } WriteUDPDataToDataBase(frame, true); }
public async Task <bool> ConnectDevice(SensorDevice sensorDevice, CancellationTokenSource tokenSource, int slotIndex = -1) { _isBusy = true; // Cannot connect to an already connected device or devices that is neither master or slave. if (sensorDevice.IsConnected || sensorDevice.Type == DeviceType.None) { return(false); } _log.Info("Connecting to a device."); if (_deviceSlotService.AllSlotsAreFull) { _userDialogs.Alert(new AlertConfig { Message = $"The device list is full. Please disconnect a device before attempting to connect another one." }); _isBusy = false; return(false); } DeviceSlot emptySlot; if (slotIndex > -1) { emptySlot = _deviceSlotService.DeviceSlots[slotIndex]; } else { emptySlot = _deviceSlotService.GetEmptySlot(sensorDevice.Type); } if (emptySlot == null) { _userDialogs.Alert(new AlertConfig { Message = $"Cannot connect to more devices of this type." }); _isBusy = false; return(false); } _log.Debug($"Connecting to {sensorDevice.Type}"); // Attempt to connect to device. int timeout = 4000; // 4 second timeout var task = _adapter.ConnectToDeviceAsync(device: sensorDevice.Device, cancellationToken: tokenSource.Token); try { if (await Task.WhenAny(task, Task.Delay(timeout)) != task) { tokenSource.Cancel(); _userDialogs.Alert(new AlertConfig { Message = $"Connection to {sensorDevice.Name} timed out." }); _isBusy = false; return(false); } } catch (DeviceConnectionException) { _userDialogs.Alert(new AlertConfig { Message = $"Could not connect to {sensorDevice.Name}." }); _isBusy = false; return(false); } // Clear the Last active output data types list. _sensorDataService.RecentOutputAdditions.Clear(); try { // TODO: Add file service for sensor data logging. sensorDevice.Characteristics = await GetAvailableCharacteristics(sensorDevice); _log.Debug($"New {sensorDevice.Type} Device Address: " + sensorDevice.Id); if (sensorDevice.Characteristics.Count == 0) { _userDialogs.Alert(new AlertConfig { Message = $"Error: No valid characteristics were detected for {sensorDevice.Name}. Disconnecting from the device." }); await DisconnectDevice(sensorDevice); _isBusy = false; return(false); } // Subscribe to data characteristics foreach (var characteristic in sensorDevice.Characteristics) { if (characteristic.Uuid == CMD_CHARACTERISTIC) { sensorDevice.CommandCharacteristic = characteristic; } else if (characteristic.Uuid == DATA_CHARACTERISTIC) { sensorDevice.DownloadDataCharacteristic = characteristic; await sensorDevice.DownloadDataCharacteristic.StartUpdatesAsync(); } else if (characteristic.Uuid == INFO_CHARACTERISTIC) { sensorDevice.InfoCharacteristic = characteristic; await sensorDevice.InfoCharacteristic.StartUpdatesAsync(); } else if (characteristic.Uuid == BATTERY_UUID) { sensorDevice.BatteryCharacteristic = characteristic; byte[] battery_pkg = await sensorDevice.BatteryCharacteristic.ReadAsync(); _deviceSlotService.UpdateBatteryStatus(emptySlot.Index, battery_pkg[0]); await sensorDevice.BatteryCharacteristic.StartUpdatesAsync(); } else if (characteristic.CanUpdate) { var datatype = _dataTypeForCharacteristicUUID[characteristic.Uuid]; DataType tempDataType = datatype; // Necessary temp conversion due to DataType clash in different chest and limb devices. if (datatype == DataType.temp) { if (sensorDevice.Type == DeviceType.Chest) { tempDataType = DataType.chest_temp; } else if (sensorDevice.Type == DeviceType.Limb) { tempDataType = DataType.foot_temp; } } if (!_dataTypeToOutputType.ContainsKey(tempDataType)) { continue; } foreach (var outputType in _dataTypeToOutputType[tempDataType]) { var outputTuple = Tuple.Create(emptySlot.Index, outputType); int outputID = outputTuple.GetHashCode(); OutputData.Add(outputID); emptySlot.OutputDataIDs.Add(outputID); _sensorDataService.AddToDataBuffer(outputID); SubscribedCharacteristicsList.Add(outputType); _sensorDataService.RecentOutputAdditions.Add(outputTuple); } var func = new EventHandler <CharacteristicUpdatedEventArgs>((sender, args) => CharacteristicOnValueUpdated(sender, args, sensorDevice)); _characteristicEventAggregator.TryAdd(characteristic, func); // Cleanup previous event handler. characteristic.ValueUpdated -= func; // Attach event handler to characteristic value update. characteristic.ValueUpdated += func; // Start Getting Sensor Data. await characteristic.StartUpdatesAsync(); } } _deviceSlotService.AddDeviceToSlot(emptySlot.Index, sensorDevice); } catch (Exception e) { _log.Debug(e.Message); } _isBusy = false; return(true); }
/// <summary> /// Event handler for when a device connects to the central bluetooth device. /// </summary> /// <param name="sender">Event sender.</param> /// <param name="e">Event args.</param> private async void OnDeviceConnectedAsync(object sender, DeviceEventArgs e) { while (_bluetoothService.IsBusy) { _log.Debug($"On Device Connected Async wait"); await Task.Delay(200); } // Check if the view refresher is alredy running. if (_renderGraphTask != null && (_renderGraphTask.IsCompleted == false || _renderGraphTask.Status == TaskStatus.Running || _renderGraphTask.Status == TaskStatus.WaitingToRun || _renderGraphTask.Status == TaskStatus.WaitingForActivation)) { _log.Info("Graph refresh task is already running. "); _log.Debug($"Active Graphs: {string.Join(" ", _currentActiveGraphs)}"); _log.Info("Resetting graph indicators to 0"); // Reset types in the same group for each of the output types from a recent device connection. foreach (var outputTuple in _sensorDataService.RecentOutputAdditions) { var outputID = outputTuple.GetHashCode(); int syncGroupIndex = -1; for (int i = 0; i < _dataSyncGroups.Count; i++) { var syncGroup = _dataSyncGroups[i]; if (syncGroup.Contains(outputID)) { foreach (var type in syncGroup) { if (_currentActiveGraphs.Contains(type)) { _graphs[type].ResetRefreshCursor(); _graphs[type].ClearGraph(); } } syncGroupIndex = i; break; } } GraphOutput newOutput = new GraphOutput(outputTuple.Item1, syncGroupIndex, outputTuple.Item2, outputTuple.Item2.ToString()); if (!limitDataTypes.Contains(outputTuple.Item2)) { DataOutputs.Add(outputTuple.GetHashCode(), newOutput); } } } else { foreach (var outputTuple in _sensorDataService.RecentOutputAdditions) { var outputID = outputTuple.GetHashCode(); int syncGroupIndex = -1; for (int i = 0; i < _dataSyncGroups.Count; i++) { var syncGroup = _dataSyncGroups[i]; if (syncGroup.Contains(outputID)) { syncGroupIndex = i; break; } } GraphOutput newOutput = new GraphOutput(outputTuple.Item1, syncGroupIndex, outputTuple.Item2, outputTuple.Item2.ToString()); if (!limitDataTypes.Contains(outputTuple.Item2)) { DataOutputs.Add(outputTuple.GetHashCode(), newOutput); } } _log.Info("Starting graph refresh task."); StartMonitor(); } CheckIfASessionIsRunning(); }
public BaseViewModel(IMvxLogProvider logProvider, IMvxNavigationService navigationService) : base(logProvider, navigationService) { _log = logProvider.GetLogFor <BaseViewModel>(); _log.Info("Base VM constructed"); }