Xamarin ContentObserver - c#

trying to get a content observer to work in Xamarin Android.
It's not currently being executed when an event happens.
I tried converting from a java example and fixed it up for c#
I know there is not code to implement the event mod yet, trying to see it get caught first then will add the code.
This is the observer:
using System;
using Android.Database;
using Android.OS;
using Android.Content;
namespace FileTest
{
public class MyObserver : ContentObserver
{
private readonly Android.Net.Uri _uri;
public MyObserver(Android.Net.Uri uri): base(null)
{
_uri = uri;
}
public override void OnChange(bool selfChange) {
this.OnChange (selfChange, null);
Console.WriteLine ("change that I caught " );
}
// public override void OnChange(bool selfChange, Uri uri) {
//
// Console.WriteLine ("change that I caught " );
//
//}
}
}
this is the call:
ContentObserver observer = new MyObserver(Android.Net.Uri.Parse("content://com.Test/databases/Data.db"));
// TODO Auto-generated method stub
var a = Android.Net.Uri.Parse ("content://com.Test/databases/Data.db");
ContentResolver.RegisterContentObserver(a, false, observer);

Related

Xamarin Form HTTPClient Call crashing

I have a project where I am using System.Net.Http.HttpClient. I am trying to centralize all calls to my Web APIs so that I have common error handing etc. I created the following class in my project.
using ModernHttpClient;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace WebAPIHelper
{
class WebAPICaller
{
public async Task<string> CallWebService(string ps_URI)
{
HttpClient lobj_HTTPClient = null;
HttpResponseMessage lobj_HTTPResponse = null;
string ls_Response = "";
//We assume the internet is available.
try
{
//Get the Days of the Week
lobj_HTTPClient = new HttpClient(new NativeMessageHandler());
lobj_HTTPClient.BaseAddress = new Uri(App.APIPrefix);
lobj_HTTPClient.DefaultRequestHeaders.Accept.Clear();
lobj_HTTPClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
lobj_HTTPResponse = await lobj_HTTPClient.GetAsync(ps_URI);
if (!lobj_HTTPResponse.IsSuccessStatusCode)
{
Debug.WriteLine(lobj_HTTPResponse.ReasonPhrase);
}
else
{
ls_Response = await lobj_HTTPResponse.Content.ReadAsStringAsync();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
finally
{
if (lobj_HTTPClient != null)
lobj_HTTPClient.Dispose();
if (lobj_HTTPResponse != null)
{
lobj_HTTPResponse.Dispose();
}
}
return ls_Response;
}
}
}
I call the function from an instance object I created in my ViewModel class for languages as follows:
using ModernHttpClient;
using Newtonsoft.Json;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace WebAPIHelper
{
public class VM_Languages : INotifyPropertyChanged
{
/// <summary>
/// A collection for CGSLanguage objects.
/// </summary>
public ObservableCollection<GBSLanguage_ForList> Items_ForList { get; private set; }
const string ic_LanguagesAPIUrl = #"/languages/true";
/// <summary>
/// Constructor for the Languages view model.
/// </summary>
public VM_Languages()
{
this.Items_ForList = new ObservableCollection<GBSLanguage_ForList>();
}
/// <summary>
/// Indicates of the view model data has been loaded
/// </summary>
public bool IsDataLoaded
{
get;
private set;
}
/// <summary>
/// Creates and adds a the countries to the collection.
/// </summary>
public async Task LoadData()
{
HttpClient lobj_HTTPClient = null;
HttpResponseMessage lobj_HTTPResponse = null;
string ls_Response = "";
try
{
IsDataLoaded = false;
string ls_WorkLanguageURI = ic_LanguagesAPIUrl;
//Get the Days of the Week
lobj_HTTPClient = new HttpClient(new NativeMessageHandler());
lobj_HTTPClient.BaseAddress = new Uri(App.APIPrefix);
lobj_HTTPClient.DefaultRequestHeaders.Accept.Clear();
lobj_HTTPClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
**//This call will not work
//WebAPICaller lobj_APICaller = new WebAPICaller();
//ls_Response = lobj_APICaller.CallWebService(ls_WorkLanguageURI).Result;
//This call will work
lobj_HTTPResponse = await lobj_HTTPClient.GetAsync(ls_WorkLanguageURI);**
if (lobj_HTTPResponse.IsSuccessStatusCode)
{
if (this.Items_ForList != null)
this.Items_ForList.Clear();
ls_Response = await lobj_HTTPResponse.Content.ReadAsStringAsync();
Items_ForList = JsonConvert.DeserializeObject<ObservableCollection<GBSLanguage_ForList>>(ls_Response);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
finally
{
this.IsDataLoaded = true;
NotifyPropertyChanged("GBSLanguages_ForList");
}
}
/// <summary>
/// Notifies subscribers that a property has changed.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I have all my ViewModels in a static class so I only ever get one instance of them as follows:
namespace WebAPIHelper
{
public static class ViewModelObjects
{
private static VM_Languages iobj_Languages;
public static VM_Languages Languages
{
get
{
if (iobj_Languages == null)
iobj_Languages = new VM_Languages();
return iobj_Languages;
}
}
}
}
In my on appearing code of my main page I have the following call to retrieve the data from the WebAPI
protected override async void OnAppearing()
{
Device.BeginInvokeOnMainThread(() =>
{
if (!ViewModelObjects.Languages.IsDataLoaded)
ViewModelObjects.Languages.LoadData();
});
//If the DOW and Language data are not loaded yet - wait
while (!ViewModelObjects.Languages.IsDataLoaded)
{
await Task.Delay(1000);
}
}
The problem is when I attempt to use my WebAPICaller class, it appears to crash on the line. I never get a return from it. No exceptions are ever raised and my program never continues.
lobj_HTTPResponse = await lobj_HTTPClient.GetAsync(ps_URI);
If I make what I believe to be the exact same call from my ViewModel, it works. (I have both the call to the WebAPICaller class as well as a direct call to GetAsync in the View Model so you can test it out by commenting and uncommenting.)
Any idea as to what I am doing wrong?
Link to full sample project:
https://1drv.ms/u/s!Ams6cZUzaeQy3M8uGAuaGggMt0Fi-A
So here is what I found. It seems that awaiting the HTTPClient.GetAsync was causing the error. (Pretty sure the thread was blocked.) So to start with I took out the await and added code to delay the task when HTTPClient's return task was not completed.
var lobj_Result = lobj_HTTPClient.GetAsync(ps_URI);
while (!lobj_Result.IsCompleted)
{
Task.Delay(100);
}
Because I no longer await the call in the LoadData method, I was able to remove the async Task declaration and simply make it a method.
public void LoadData()
{
HttpClient lobj_HTTPClient = null;
HttpResponseMessage lobj_HTTPResponse = null;
string ls_Response = "";
try
{
IsDataLoaded = false;
string ls_WorkLanguageURI = ic_LanguagesAPIUrl;
//Get the Days of the Week
lobj_HTTPClient = new HttpClient(new NativeMessageHandler());
lobj_HTTPClient.BaseAddress = new Uri(App.APIPrefix);
lobj_HTTPClient.DefaultRequestHeaders.Accept.Clear();
lobj_HTTPClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//This call will not work
WebAPICaller lobj_APICaller = new WebAPICaller();
ls_Response = lobj_APICaller.CallWebService(ls_WorkLanguageURI).Result;
if (ls_Response.Trim().Length > 0)
{
if (this.Items_ForList != null)
this.Items_ForList.Clear();
Items_ForList = JsonConvert.DeserializeObject<ObservableCollection<GBSLanguage_ForList>>(ls_Response);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
finally
{
this.IsDataLoaded = true;
NotifyPropertyChanged("GBSLanguages_ForList");
}
}
The I could remove the async from my on appearing event and simply call the loaddata event synchronously.
if (!ViewModelObjects.Languages.IsDataLoaded)
ViewModelObjects.Languages.LoadData();
After making all these changes, the desired result was achieved. Everything ran in synchronous manner (I know the call to GetAsync function of the HTTPClient is still async) and did not return until the results were retrieve and loaded into the object.
I hope this helps other people out. :)
There are a couple of things I see going on. First, the commented-out code:
//This call will not work
//WebAPICaller lobj_APICaller = new WebAPICaller();
//ls_Response = lobj_APICaller.CallWebService(ls_WorkLanguageURI).Result;
Is using .Result instead of await. This may be the root of your problem. Using .Result should be avoided in general, just use await. See the answer here Await on a completed task same as task.Result? for more details on why.
The second thing is that you are already on the UI thread when OnAppearing is called, so there is no need to call Device.BeginInvokeOnMainThread. What you're doing in that method currently is equivalent to:
protected override async void OnAppearing()
{
if (!ViewModelObjects.Languages.IsDataLoaded)
await ViewModelObjects.Languages.LoadData();
}
The next question is whether or not it's a great idea to be doing this in OnAppearing(). This can cause your app to seem non-responsive.
The general use of Device.BeginInvokeOnMainThread is for when you don't know if you're currently on the main thread, but these UI event handlers always are called on the main thread by the Xamarin platform.
Based on the source code on github
void IPageController.SendAppearing()
{
if (_hasAppeared)
return;
_hasAppeared = true;
if (IsBusy)
MessagingCenter.Send(this, BusySetSignalName, true);
OnAppearing();
EventHandler handler = Appearing;
if (handler != null)
handler(this, EventArgs.Empty);
var pageContainer = this as IPageContainer<Page>;
((IPageController)pageContainer?.CurrentPage)?.SendAppearing();
}
there is still a way to do this with async/await approach.
You will notice that the OnAppearing method is called just before the event is triggered.
Subscribe to the Appearing event of the page/view
protected override void OnAppearing() {
this.Appearing += Page_Appearing;
}
and create an async method like you did originally but this time have it on an actual even handler
private async void Page_Appearing(object sender, EventArgs e) {
if (!ViewModelObjects.Languages.IsDataLoaded)
await ViewModelObjects.Languages.LoadData();
//unsubscribing from the event
this.Appearing -= Page_Appearing;
}
This way there is no need to busy wait delay the thread while waiting for the task to complete.

How to monitor windows services using c#

How can i monitor windows services using c# and i also have to save those services name, started time and services end time using in a CSV file. If any new services started than it should automatically write services name, started time and services end time using in existing CSV file.
In case someone is looking for a solution to this in 2021, you can do this using a service controller, async task and the WaitForStatus() method:
Update: I realized my initial solution would not work so I rewrote it completely:
CLASS DEFINITION
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.ServiceProcess; // not referenced by default
public class ExtendedServiceController: ServiceController
{
public event EventHandler<ServiceStatusEventArgs> StatusChanged;
private Dictionary<ServiceControllerStatus, Task> _tasks = new Dictionary<ServiceControllerStatus, Task>();
new public ServiceControllerStatus Status
{
get
{
base.Refresh();
return base.Status;
}
}
public ExtendedServiceController(string ServiceName): base(ServiceName)
{
foreach (ServiceControllerStatus status in Enum.GetValues(typeof(ServiceControllerStatus)))
{
_tasks.Add(status, null);
}
StartListening();
}
private void StartListening()
{
foreach (ServiceControllerStatus status in Enum.GetValues(typeof(ServiceControllerStatus)))
{
if (this.Status != status && (_tasks[status] == null || _tasks[status].IsCompleted))
{
_tasks[status] = Task.Run(() =>
{
try
{
base.WaitForStatus(status);
OnStatusChanged(new ServiceStatusEventArgs(status));
StartListening();
}
catch
{
// You can either raise another event here with the exception or ignore it since it most likely means the service was uninstalled/lost communication
}
});
}
}
}
protected virtual void OnStatusChanged(ServiceStatusEventArgs e)
{
EventHandler<ServiceStatusEventArgs> handler = StatusChanged;
handler?.Invoke(this, e);
}
}
public class ServiceStatusEventArgs : EventArgs
{
public ServiceControllerStatus Status { get; private set; }
public ServiceStatusEventArgs(ServiceControllerStatus Status)
{
this.Status = Status;
}
}
USAGE
static void Main(string[] args)
{
ExtendedServiceController xServiceController = new ExtendedServiceController("myService");
xServiceController.StatusChanged += xServiceController_StatusChanged;
Console.Read();
// Added bonus since the class inherits from ServiceController, you can use it to control the service as well.
}
// This event handler will catch service status changes externally as well
private static void xServiceController_StatusChanged(object sender, ServiceStatusEventArgs e)
{
Console.WriteLine("Status Changed: " + e.Status);
}
You can list running services using ServiceController or ManagementObjectSearcher.
Here is a sample using the ManagementObjectSearcher :
using System.Management;
...
StringBuilder sb = new StringBuilder();
string format = "{0},{1},{2},{3},{4}";
// Header line
sb.AppendFormat(format, "DisplayName",
"ServiceName",
"Status",
"ProcessId",
"PathName");
sb.AppendLine();
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("SELECT * FROM Win32_Service");
foreach( ManagementObject result in searcher.Get() )
{
sb.AppendFormat(format, result["DisplayName"],
result["Name"],
result["State"],
result["ProcessId"],
result["PathName"]
);
sb.AppendLine();
}
File.WriteAllText(
#"C:\temp\ManagementObjectSearcher_services.csv",
sb.ToString()
);
For getting start and stop times it looks like you have to query the Windows Event Log.
This blog post show how you can monitor the event log to get notified when a service is stopped or started:
https://dotnetcodr.com/2014/12/02/getting-notified-by-a-windows-service-status-change-in-c-net/

Xamarin iOS Perform Segue with Scandit

I am using a barcode scanner to grab a barcode and then I want to segue to my next screen right after that barcode is grabbed and I use that to find some specific data. The scanning works fine, and when the barcode is scanned The method DidScanBarcode is hit and runs through, is in this method that I try and perform my segue but the app either freezes or crashes without ever performing the segue and the method PrepareForSegue is never hit after the PerformSegue is run. Any thoughts?
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
using RedLasterPrototype;
using System.Threading.Tasks;
using CoreGraphics;
using ZXing.Mobile;
using ScanditSDK;
namespace Prototype
{
partial class ScanViewController : UIViewController
{
public static ProductElement ScannedProduct { get; set; }
ScanditDelegate scanditDelegate;
public static string appKey = "xxxxx";
public ScanViewController(IntPtr handle) : base (handle)
{
}
public async override void ViewDidLoad()
{
var picker = new ScanditSDK.SIBarcodePicker (appKey);
scanditDelegate = new ScanditDelegate ();
picker.OverlayController.Delegate = scanditDelegate;
PresentViewController (picker, true, null);
picker.StartScanning ();
}
public static ProductElement GetScannedData(string upc)
{
var _service = new RestService ();
var data = _service.GetDataFromUpc (upc);
if (data != null)
{
return data;
}
return null;
}
public override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
{
base.PrepareForSegue (segue, sender);
if (segue.Identifier == "SegueToProductPage")
{
var destination = (ScannedProductViewController)segue.DestinationViewController;
destination.product = ScannedProduct;
}
}
public class ScanditDelegate : SIOverlayControllerDelegate
{
public override void DidScanBarcode (SIOverlayController overlayController, NSDictionary barcode) {
// perform actions after a barcode was scanned
Console.WriteLine ("barcode scanned: {0}, '{1}'", barcode["symbology"], barcode["barcode"]);
var code = barcode ["barcode"].ToString();
if(code != null)
{
ScannedProduct = GetScannedData (code);
var x = new ScanViewController (this.Handle);
x.PerformSegue ("SegueToProductPage", this);
}
}
public override void DidCancel (SIOverlayController overlayController, NSDictionary status) {
// perform actions after cancel was pressed
}
public override void DidManualSearch (SIOverlayController overlayController, string text) {
// perform actions after search was used
}
}
}
}

Using gps location system services dependency injection

I am looking to get platform specific location details using Xamarin's dependency injection but running into issues. More than likely from doing it wrong.
Here is my current setup:
nuMaps/Interfaces/ILocationService.cs
using Xamarin.Forms.Maps;
namespace nuMaps
{
public interface ILocationService
{
void initLocationService();
Position getCurrentPosition();
}
}
nuMaps/nuMaps.Droid/Interfaces/LocationService.cs
using System;
using nuMaps;
using nuMaps.Droid;
using Xamarin.Forms.Maps;
using Android.App;
using Android.Gms.Common;
using Android.Gms.Common.Apis;
using Android.Gms.Location;
using Android.Locations;
using Android.Widget;
[assembly: Xamarin.Forms.Dependency (typeof (LocationService))]
namespace nuMaps.Droid
{
public class LocationService : Java.Lang.Object, ILocationService, IGoogleApiClientConnectionCallbacks, IGoogleApiClientOnConnectionFailedListener, Android.Gms.Location.ILocationListener
{
readonly IGoogleApiClient _googleApiClient;
readonly LocationRequest _locRequest;
Position _currentPosition;
Location _currentLocation;
public LocationService()
{
Console.WriteLine ("LocationService constructor");
_currentPosition = new Position (0, 0);
_googleApiClient = new GoogleApiClientBuilder (Xamarin.Forms.Forms.Context)
.AddApi (LocationServices.Api)
.AddConnectionCallbacks (this)
.AddOnConnectionFailedListener (this)
.Build ();
_locRequest = new LocationRequest ();
}
#region ILocationService implementation
public void initLocationService()
{
_googleApiClient.Connect ();
}
public Position getCurrentPosition ()
{
if (_googleApiClient.IsConnected) {
_currentLocation = LocationServices.FusedLocationApi.GetLastLocation (_googleApiClient);
_currentPosition = new Position (_currentLocation.Latitude, _currentLocation.Longitude);
}
_googleApiClient.Disconnect ();
return new Position (_currentLocation.Latitude, _currentLocation.Longitude);
}
#endregion
public void OnLocationChanged(Location l)
{
Console.WriteLine ("OnLocationChanged");
_currentLocation = l;
}
public void OnConnectionFailed (ConnectionResult result)
{
Console.WriteLine ("ConnectionFailed");
}
#region IGoogleApiClientConnectionCallbacks implementation
public void OnConnected (Android.OS.Bundle connectionHint)
{
Console.WriteLine ("OnConnected");
if (!_googleApiClient.IsConnected)
LocationServices.FusedLocationApi.RequestLocationUpdates (_googleApiClient, _locRequest, this);
_currentLocation = LocationServices.FusedLocationApi.GetLastLocation (_googleApiClient);
}
public void OnConnectionSuspended (int cause)
{
Console.WriteLine ("OnConnectionSuspended");
}
#endregion
}
}
Usage in nuMaps/Views/MapPage.xaml.cs
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using System;
using System.Diagnostics;
namespace nuMaps
{
public partial class MapPage : ContentPage
{
public MapPage ()
{
InitializeComponent ();
Position p = DependencyService.Get<ILocationService>().getCurrentPosition();
MyMap.MoveToRegion (
MapSpan.FromCenterAndRadius (
p, Distance.FromMiles (1)
)
);
}
}
}
nuMaps/Views/Loginpage.xaml.cs
using System;
using Xamarin.Forms;
using nuMaps;
namespace nuMaps
{
public partial class LoginPage : ContentPage
{
public LoginPage ()
{
InitializeComponent ();
/*
* Init platform specific location service.
* TODO: This *shouldn't* need to happen, but we don't get location information until
* the OnConnected callback happens which is too slow to put in getCurrentLocation method.
*/
DependencyService.Get<ILocationService>().initLocationService();
}
}
}
I believe the problem is in your implementation of ILocationService.
I would remove implementing activity (why do you want to use OnCreate?) and take a look at http://developer.xamarin.com/guides/android/platform_features/maps_and_location/location/.
I'd recommend on Android getting the GPS location via the google play apis, which will require implementing ILocationListener, IGoogleApiClientConnectionCallbacks, and IGoogleApiClientOnConnectionFailedListener. Hope that helps!
Edit for comments:
If the LocationService in the question is up to date, I don't see that you're implementing IGoogleApiClientConnectionCallbacks or ILocationListener. It may be that because the mappage is using gps, GetLastKnownLocation works, because a location has recently been obtained.
GPS location requesting is an async operation - one of the methods with IGoogleApiClientConnectionCallbacks is OnConnected, where you should call something like:
LocationServices.FusedLocationApi.RequestLocationUpdates(googleApiClient, locationRequest, this);
This will actively request location updates, and then fire OnLocationChanged(Location location) when an location update is returned. This is all async, so you'll likely need to expose these events in your LocationService and subscribe to them.
You could give TinyIoC a try instead of the Xamarin Dependency Service. It works well for platform-specific implementations, like location services.
Maybe the Xamarin Dependency Service can be used for these types of things, but I've only used it for custom Renderers so far. For more service-based stuff, I use TinyIoC.

How can I call this webservice asynchronously?

In Visual Studio I created a web service (and checked "generate asynchronous operations") on this URL:
http://www.webservicex.com/globalweather.asmx
and can get the data out synchronously but what is the syntax for getting the data out asychronously?
using System.Windows;
using TestConsume2343.ServiceReference1;
using System;
using System.Net;
namespace TestConsume2343
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
GlobalWeatherSoapClient client = new GlobalWeatherSoapClient();
//synchronous
string getWeatherResult = client.GetWeather("Berlin", "Germany");
Console.WriteLine("Get Weather Result: " + getWeatherResult); //works
//asynchronous
client.BeginGetWeather("Berlin", "Germany", new AsyncCallback(GotWeather), null);
}
void GotWeather(IAsyncResult result)
{
//Console.WriteLine("Get Weather Result: " + result.???);
}
}
}
Answer:
Thanks TLiebe, with your EndGetWeather suggestion I was able to get it to work like this:
using System.Windows;
using TestConsume2343.ServiceReference1;
using System;
namespace TestConsume2343
{
public partial class Window1 : Window
{
GlobalWeatherSoapClient client = new GlobalWeatherSoapClient();
public Window1()
{
InitializeComponent();
client.BeginGetWeather("Berlin", "Germany", new AsyncCallback(GotWeather), null);
}
void GotWeather(IAsyncResult result)
{
Console.WriteLine("Get Weather Result: " + client.EndGetWeather(result).ToString());
}
}
}
I suggest using the event provided by the auto-generated proxy instead of messing with the AsyncCallback
public void DoWork()
{
GlobalWeatherSoapClient client = new GlobalWeatherSoapClient();
client.GetWeatherCompleted += new EventHandler<WeatherCompletedEventArgs>(client_GetWeatherCompleted);
client.GetWeatherAsync("Berlin", "Germany");
}
void client_GetWeatherCompleted(object sender, WeatherCompletedEventArgs e)
{
Console.WriteLine("Get Weather Result: " + e.Result);
}
In your GotWeather() method you need to call the EndGetWeather() method. Have a look at some of the sample code at MSDN. You need to use the IAsyncResult object to get your delegate method so that you can call the EndGetWeather() method.

Categories

Resources