I have a Xamarin Forms application that should fire a method to execute once it detects Internet Connectivity. I have used
CrossConnectivity.Current.ConnectivityChanged
to monitor internet connectivity changes which works well.
I then invoke the method in the constructor of the page along with other methods that need to be executed on page load. But when I changed the status of the internet connection, the method SendUntransferedData(); does not get executed. Hence all my untransferred data are not transferred. Can anyone please help me to resolve this issue or provide me an alternative way of doing this?
The following code in MainPage.cs are:
public MainPage() {
DoSomething();
SearchData();
SendUntransferedData();
}
The code is implemented in the cs also.
private void SendUntransferedData()
{
CrossConnectivity.Current.ConnectivityChanged += (sender, args) =>
{
DataAccess da = new DataAccess();
da.SendUntransferredData();
};
}
Step1:
First, you need to add these two packages
Xam.Plugin.Connectivity
plugin.wifiinfo
in all platforms
Step2:
Create one class in PCL.
NetworkCheck.cs
public static bool IsNetworkConnected ()
{
bool retVal = false;
try
{
retVal = CrossConnectivity.Current.IsConnected;
return retVal;
}
catch (Exception ex) {
System.Diagnostics.Debug.WriteLine (ex.Message);
throw ex;
}
}
Step3:
In your pages use the code below
if (CheckNetworkAccess.IsNetworkConnected ())
{
Navigation.PushAsync (new HomePage ());
}
else
{
await DisplayAlert ("Your app name", "Please check your network connection", "OK");
}
The alternative I use is the following. In my App.xaml.cs file I add the code to hook up the ConnectivityChanged. That way I have one spot in my app where this is handled and since App.xaml.cs is always around for the lifetime of my app it's an ideal spot to put this.
If hooks up to the events from CrossConnectivity and then uses the Xamarin Forms MessagingCenter to broadcast a message to all the subscribers.
protected override void OnStart()
{
// Handle when your app starts
OnResume();
}
protected override void OnResume()
{
// Handle when your app resumes
Settings.IsConnected = CrossConnectivity.Current.IsConnected;
CrossConnectivity.Current.ConnectivityChanged += ConnectivityChanged;
}
protected override void OnSleep()
{
// Handle when your app sleeps
CrossConnectivity.Current.ConnectivityChanged -= ConnectivityChanged;
}
protected async void ConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
{
// Save current state and then set it
var connected = Settings.IsConnected;
Settings.IsConnected = e.IsConnected;
// If connectivity changes we inform our listeners of that.
if (connected != e.IsConnected)
MessagingService.Current.SendMessage(MessageKeys.ConnectivityChanged);
// If we disconnected, show a message for the user that we did.
if (connected && !e.IsConnected)
{
// We went offline, should alert the user and also update ui (done via settings)
var task = UserDialogs.Instance.AlertAsync("You are offline.", "Connection lost", "OK");
if (task != null)
await task;
}
}
I then create a property in a base viewmodel that all my other viewmodels inherit from. This can be bound to interface controls whenever necessary.
public bool IsConnected { get; set; }
In my viewmodel I then subscribe to the event that is being thrown in App.xaml.cs.
MessagingService.Current.Subscribe(MessageKeys.ConnectivityChanged, (c) =>
{
IsConnected = CrossConnectivity.Current.IsConnected;
// Additional things you want to do such as
// DataAccess da = new DataAccess();
// da.SendUntransferredData();
});
You could probably abstract this a bit further depending on the MVVM framework you use (if you use one) but I will not go into that since it's unrelated to the original question. This solution uses additional NuGet packages namely:
FormsToolkit which has a simplified version of the MessagingCenter
Settings plugin to store the IsConnected state.
Related
I decided to ask my question here because I can't find answer in any other place.
My task is to prepare upgrade process with managed bootstrapper UI, but it doesn't want to work properly.
I prepared all of needed MSI packages. I mean I added Product Id="*", I added MajorUpgrade tag and configured it and I change versions between bundle(for test purposes), I also added a few properties which should helps me with distinguish is it an Install, Uninstall or Upgrade process.
And my problem starts here, because when I was using default burn UI it worked properly I mean during installation property _INSTALL was set to 1, during upgrade (installing version 2 of bundle) property _UPGRADE was set to 2 and the same with uninstallation, but now when I added Custom UI to that, UPGRADE property isn't set at all. Instead of that during trial of UPGRADE first starts Installation process and it goes to some point and then new window with Uninstallation appears.
My question is can I somehow make my Custom UI to behave like a Default UI for burn?
Thank you everyone for comments. Inspired by How to perform Wix Upgrade with custom bootstrapper I understood I didn't handle situation when installer is run quietly.
So I prepared another class for SilentUninstall and did it in my Bootstrapper class:
public class BootstrapperApp : BootstrapperApplication
{
public static Dispatcher Dispatcher { get; set; }
protected override void Run()
{
Dispatcher = Dispatcher.CurrentDispatcher;
var model = new BootstrapperApplicationModel(this);
var command = model.BootstrapperApplication.Command;
if (command.Action == LaunchAction.Uninstall && (command.Display == Display.None || command.Display == Display.Embedded))
{
model.LogMessage("Starting silent uninstaller.");
var viewModel = new SilentUninstallViewModel(model, Engine);
Engine.Detect();
}
else
{
model.LogMessage("Starting installer.");
var viewModel = new InstallViewModel(model);
var view = new InstallView(viewModel);
view.Closed += (sender, e) => Dispatcher.InvokeShutdown();
model.SetWindowHandle(view);
Engine.Detect();
view.Show();
}
Dispatcher.Run();
Engine.Quit(model.FinalResult);
}}
and my SilentUninstaller class:
public class SilentUninstallViewModel
{
private BootstrapperApplicationModel model;
private Engine engine;
public SilentUninstallViewModel(BootstrapperApplicationModel model, Engine engine)
{
this.model = model;
this.engine = engine;
WireUpEventHandlers();
}
private void WireUpEventHandlers()
{
this.model.BootstrapperApplication.PlanComplete += PlanCompleted;
this.model.BootstrapperApplication.DetectComplete += DetectCompleted;
this.model.BootstrapperApplication.ApplyComplete += ApplyCompleted;
}
private void DetectCompleted(object sender, DetectCompleteEventArgs e)
{
this.model.LogMessage("Detecting has been completed for silent uninstallation.");
this.model.PlanAction(LaunchAction.Uninstall);
}
private void ApplyCompleted(object sender, ApplyCompleteEventArgs e)
{
this.model.LogMessage("Applying has been completed for silent uninstallation.");
this.model.FinalResult = e.Status;
this.engine.Quit(this.model.FinalResult);
}
private void PlanCompleted(object sender, PlanCompleteEventArgs e)
{
this.model.LogMessage("Planning has been started for silent uninstallation.");
model.ApplyAction();
}
}
and it seems to works properly. Even property _UPGRADE is raised in particular MSIs ;)
Recently I started learning C# by writing a simple application that watches directory and updates form based on lines written to file in that directory. At some point I was stuck with common InvalidOperationException while trying to update form element from FileWatcher event.
I've searched stackoverflow, and it seems that I should use Task-based Asynchronous Pattern (TAP) in such situations, but I can't figure out which method I should flag as async, and which to start as a Task. There are many related questions on stackoverflow, but none I've found cover all 3 aspects of my application:
Using FileWatcher
Updating Form element
Using TAP
So, what is the best practice to update Form elements from events, fired by FileWatcher if I want to use Task-based Asynchronous Pattern? Or should I use another pattern / another application structure?
Here is a simplified example of my app:
// Form
public partial class FormMain : Form, IDisplayInterface
{
private CoreClass coreClass;
public void SetSomeVaue(string value)
{
label.Text = value;
}
public FormMain()
{
coreClass = new CoreClass();
coreClass.StartFileWatcher();
}
private void FormMain_Shown(object sender, EventArgs e)
{
coreClass.DisplayInterface = this;
}
}
// Interface
interface IDisplayInterface
{
void SetSomeVaue(string value);
}
// CoreClass
class CoreClass
{
public IDisplayInterface DisplayInterface;
public void StartFileWatcher()
{
FileSystemWatcher watcher = new FileSystemWatcher("C:\Some\Folder")
{
NotifyFilter = NotifyFilters.Size
};
watcher.Changed += new FileSystemEventHandler(FileUpdated);
watcher.EnableRaisingEvents = true;
}
private void FileUpdated(object source, FileSystemEventArgs e)
{
ParseFile(Path.Combine("C:\Some\Folder", e.Name));
}
private void ParseFile(string File)
{
// foreach (var line in newFileLines)
ParseNewRecord(line);
}
private void ParseNewRecord(string line)
{
if (someCondition && DisplayInterface != null)
{
// This triggers Exception for accessing FormMain from a thread that did not create it
DisplayInterface.SetSomeValue(someValue);
}
}
}
UPDATE 21.07:
It looks that I got the wrong idea about using TAP everywhere, so I finally did it by invoking a delegate containing my SetSomeVaue method and it works correctly (I hope that is a correct decision).
Thanks for response!
So I am just messing around here nothing production just proof of concept with my first ever Windows Service.
I am trying to essentially create a windows service that sits as the listener for a signalr connection. In essence, I will have a windows application and a windows service. The win service will handle connecting to the signalr hub and on signalr calls fire an event. The windows application will listen for these events and perform actions based on them.
Currently I cannot get this to work. I have never worked with events, or windows services before. In my windows application my events never hit their break points, as well I log an error of null reference exception from the
ConnectToHub()
Alright if I comment out the OnConnected() method call I log a successful connection to the hub. I have never worked with events before so is my mistake with the events?
I debated that this approach was a bit overkill. However, for me it was a proof of concept that I could find a use for a long running windows service, and adding some events into the mix.
Code for service:
public delegate void MessageRecievedEventHanlder(object sender, MessageRecievedArgs e);
public delegate void ConnectedToHubEventHandler(object sender, ConnectedArgs e);
public partial class SignalRService : ServiceBase
{
IHubProxy _hub;
HubConnection connection;
string url = #"http://localhost:8080/";
private Message LastMessage;
public static event MessageRecievedEventHanlder NewMessage;
protected virtual void OnNewMessage(MessageRecievedArgs e)
{
NewMessage(null, e);
}
public static event ConnectedToHubEventHandler Connected;
protected virtual void OnConnected(ConnectedArgs e) {
System.IO.File.WriteAllText(#"C:\Users\Bailey Miller\Desktop\FTP\Logg.txt", "Hit OnConnected " + e.Success +" " + Connected != null ? "Isn't null" : "Null event");
Connected(null, e);
}
public SignalRService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
ConnectToHub().Wait();
}
private async Task ConnectToHub()
{
try
{
//Connecting
if (connection == null)
{
connection = new HubConnection(url);
}
if (_hub == null)
{
_hub = connection.CreateHubProxy("ChatHub");
}
await connection.Start();
//Connected
//Configure all the incoming options
_hub.On<Message>("RecieveMessage", IncomingMessage);
System.IO.File.WriteAllText(#"C:\Users\Bailey Miller\Desktop\FTP\Succes.txt", "Connected");
OnConnected(new ConnectedArgs(true));
}
catch (Exception ex)
{
//Failed
//OnConnected(new ConnectedArgs(false));
System.IO.File.WriteAllText(#"C:\Users\Bailey Miller\Desktop\FTP\Fail.txt", "Failed to connect " + ex.Message.ToString());
}
}
private void IncomingMessage(Message state)
{
DateTime? lmt;
//Determine if has lastmessagetime
if (LastMessage == null) {
lmt = null;
}
else {
lmt = LastMessage.RecievedAt;
}
LastMessage = state;
//New Message
//OnNewMessage(new MessageRecievedArgs(state, lmt));
}
protected override void OnStop()
{
}
}
public class MessageRecievedArgs : EventArgs
{
public Message NewMessage { get; }
public DateTime? LastMessageTime { get; }
public MessageRecievedArgs(Message msg, DateTime? lmt) {
this.NewMessage = msg;
this.LastMessageTime = lmt;
}
}
public class ConnectedArgs : EventArgs {
public bool Success { get; }
public ConnectedArgs(bool suc) {
this.Success = suc;
}
}
My windows application as of now:
public MainWindow()
{
InitializeComponent();
SignalRService.SignalRService.NewMessage += SignalRService_NewMessage;
SignalRService.SignalRService.Connected += SignalRService_Connected;
}
private void SignalRService_Connected(object sender, SignalRService.ConnectedArgs e)
{
throw new NotImplementedException();
}
private void SignalRService_NewMessage(object sender, SignalRService.MessageRecievedArgs e)
{
throw new NotImplementedException();
}
Your question is a bit broad- you don't describe exactly what isn't working, so I am guessing that when you start your service, it says "starting..." for a long while and eventually windows service manager gives you an error saying your service didn't start in a timely fashion. The issue is that OnStart() is expected to return- you can't block the thread there with the Wait() call. My suggestion would be to spawn a new background thread here to perform the waiting, then exit. That should get you past the first hurdle.
As another aside... You can add a regular main method to a windows service project, change the project type to Console Application, and run it that way to reduce your debugging cycle time. Then when you are sure it basically works, change the project type back to Windows Service and install it.
EDIT: Now that you have a better error description, I see the real problem. The issue is that you are raising an event without checking for null first. Event fields are null until you attach a listener. So change your code as follows:
protected virtual void OnConnected(ConnectedArgs e) {
System.IO.File.WriteAllText(#"C:\Users\Bailey Miller\Desktop\FTP\Logg.txt", "Hit OnConnected " + e.Success +" " + Connected != null ? "Isn't null" : "Null event");
ConnectedToHubEventHandler connectedEvent = Connected;
if (connectedEvent != null) // This event might be null, so check first
connectedEvent(null, e);
}
I have an UWP application in which I am trying to store and retrieve some data from a local text file but no matter how I try to do it the application gets deadlocked. Due to synchronous stuff that needs to happen, I try to use a task and wait for its completion but nevertheless, the application locks.
I have a page in my UWP application called "MainPage" and in it's constructor I have the following code:
var listenkeyViewModel = new ListenkeyViewModel();
listenkeyViewModel.GetKey();
listenkey = listenkeyViewModel.Listenkey;
The get key is the issue here because it calls a method on the ViewModel (which I created to be synchronous because I thought making the call synchronous asap would be preferable.
public void GetKey()
{
try
{
var listenKeyTask = RetrieveListenKey();
_listenkey = listenKeyTask.Result;
}
catch (Exception e)
{
}
}
public static async Task<string> RetrieveListenKey()
{
try
{
var storageFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
var listenkeyFile = await storageFolder.GetFileAsync("listenkey.txt");
return await Windows.Storage.FileIO.ReadTextAsync(listenkeyFile);
}
catch (Exception e)
{
throw new Exception("Could not load file");
}
}
I know the thing is "async all the way down" but this is not possible here. I cannot make the constructor where the original code lies asynchronous. How are you supposed to not get deadlocked? I do not understand.
Convert GetKey to async/await
public async Task GetKey() {
try {
var listenKeyTask = RetrieveListenKey();
_listenkey = await listenKeyTask;
} catch (Exception e) {
//...should handle/log error
}
}
Move the calling of this out of the constructor and into an event handler. like page load or some other event called early in the lifecycle of the page.
partial class MainPage : Page {
ListenkeyViewModel listenkeyViewModel;
string listenkey;
public MainPage() {
InitializeComponent();
listenkeyViewModel = new ListenkeyViewModel();
// add a handler to be called when the page has been loaded
this.Loaded += OnPageLoaded;
}
async void OnPageLoaded(object sender, RoutedEventArgs e) {
await listenkeyViewModel.GetKey();
listenkey = listenkeyViewModel.Listenkey;
}
// Shown for demonstration purposes only.
// This is typically autogenerated by Visual Studio.
private void InitializeComponent() {
}
}
async void is allowed on event handlers so this should allow the process to flow without deadlock.
First of all, I'm Java programmer and I'm new on C# and I need opinion of C# developers. I'm developing an application that connecting to database (firebird 1.5), query some data and return to me so there's nothing to be complicated but unfortunately I've stuck in some things :
As we know the database connection should be realised in separate thread cause it's a highweight operation and all the connections should be in connection pool in order to reuse already opened connection instead create the new one.
So here go my first question - how to organize connection pool properly?
(What about connection pool I've read that usually connection pool is already realised by data providers and I can just set it in connection parametres someway like "connectionBuilder.Pooling = true;")
What about queries? I mean that I've always use a Query per-Thread (and I think that is right cause we also do a highweight operation, am I wrong? Anyway I'd glad to see your best practices with organizing database work) and in Java I just do return Query result from separate thread by use an interfaces and anonymous classes like this:
In DBHelper.class (DBHelper is a singleton)
public interface QueryListener {
public void onSuccess(ArrayList<?>);
public void onError(Exception e);
}
public synchronized void getPromoActions(final QueryListener listener) {
if (listener != null) {
try {
ArrayList<String> myPromoActions;
.............
// some query's code
.....
listener.onSucces(myPromoActions);
} catch(Exception e) {
listener.onError(e);
} finally {
closeDatabase();
}
}
}
in some UI-class (for eaxample MainWindow)
public void getPromoActions(){
new Thread(new Runnable() {
#Override
public void run() {
DBHelper.getInstance().getPromoActions(new QueryListener() {
#Override
public void onSuccess(ArrayList<?>) {
// set Data to UI element such as Table
}
#Override
public void onError(Exception e){
// Handling exception
}
});
}
}).start();
}
In C# I should use delegates to mark which method will execute in thread, but unfortionally I can't send any callback as parameter - so how I should return my Query results to main UI thread?
UPD
I've understand a little bit how to work with delegates and events but have a problem with raising a custom event. I had declared an EventHandler and an custom EventArgs:
public delegate void QueryResultEventHandler(object sender, QueryResultEventArgs e);
public class QueryResultEventArgs : EventArgs
{
public List<String> QueryResult { get; set; }
public int QueryRecordsCount { get; set; }
}
And in My DBHelper.class I declared a next field and event:
private QueryResultEventHandler _queryResult;
public event QueryResultEventHandler onQueryResult
{
add
{
lock (this)
{
_queryResult += value;
}
}
remove
{
lock (this)
{
_queryResult -= value;
}
}
}
In UI class (MainWindow) I use next code:
public void GetAllDistricts() {
DBHelper.Instance.onQueryResult += new QueryResultEventHandler(GetAllDistricsResultHandler);
DBHelper.Instance.GetAllDistricts();
}
public void GetAllDistricsResultHandler(object sender, QueryResultEventArgs e){
// Here I'm adding the query result to Table
}
So my problem now is a how to raise an event asynchronously? In my DBHelper.class I'm trying to use beginInvoke&endInvoke with _query delegate but it seems that I had missed some code lines whatever it was I can't understand what I'm doing wrong an how to raise event asynchronously? Here my DBHelper.class code:
public void GetAllDistricts() {
try
{
if (_queryResult != null)
{
//** This code should run asynchronously ---------->
using (FbConnection connection = GetConnection())
{
FbCommand getAllDistrictsCommand = new FbCommand();
getAllDistrictsCommand.CommandText = "SELECT * FROM SEND";
getAllDistrictsCommand.Connection = connection;
QueryResultEventArgs args = new QueryResultEventArgs();
using (FbDataReader reader = getAllDistrictsCommand.ExecuteReader())
{
while (reader.Read())
{
//Here must be the processing of query results and filling the
//QueryResultEventArgs
args.QueryResult.Add(reader[0].ToString());
}
args.QueryRecordsCount = reader.GetInt32(reader.GetOrdinal("Rows"));
// And here after sucessfull query I should call OnQueryResult()
OnQueryResult(args);
}
}
//**<--------------------
}
else
{
throw new Exception("...Some exception message...");
}
}
catch (Exception e)
{
log.ErrorException(e.Message, e);
throw new Exception("...Some exception message...");;
}
finally {
CloseConnection();
}
}
// The QueryResultEvent method
protected void OnQueryResult(QueryResultEventArgs e)
{
if (_queryResult != null)
{
_queryResult(this, e);
}
}
First about connection pooling. If you will use ADO.NET then you do not need to worry about that, because it's already there. You don't need to do any extra work, you just create a connection:
using (var connection = new SqlConnection(connectionString))
{
// Queries to DB
}
You should always Close or Dispose you connections. The names of the methods look "scary" but actually connections are reused. Please read this MSDN article to get more details.
The code you proposed looks over-complicated. I think you should consider using async/await pattern which is in general not multithreaded, but it handles UI responsiveness issues and simplifies writing/reading of the code. In newer versions of .NET almost all methods that are potentially long to execute has async versions. So for example your data access layer might look like that (I'm using Dapper ORM's QueryAsync method just to keep code short and simple):
public async Task<IList<District>> GetAllDistrictsAsync()
{
using (var connection = await GetConnectionAsync())
{
return (await connection.QueryAsync<District>("select * from Districts")).ToList();
}
}
public async Task<IDbConnection> GetConnectionAsync()
{
var connectionString =
ConfigurationManager.ConnectionStrings["DbConnectionString"].ConnectionString;
var connection = new SqlConnection(connectionString);
await connection.OpenAsync();
return connection;
}
And then somewhere on UI:
private async void Button_Click(object sender, EventArgs e)
{
var districts = await GetAllDistrictsAsync();
}
If you still need to execute some code in different thread you should look at Tasks namespace.
Task.Factory
.StartNew<IList<District>>(GetAllDistricts)
.ContinueWith(districts =>
{
// UI thread
}, TaskScheduler.FromCurrentSynchronizationContext());
In this example GetAllDistricts is not async and is executed in different thread. But ContinueWith will be executed in UI thread because of TaskScheduler.FromCurrentSynchronizationContext().
public void GetAllDistricts() {
DBHelper.Instance.onQueryResult +=
new QueryResultEventHandler(GetAllDistricsResultHandler);
new Thread(
new ThreadStart(DBHelper.Instance.GetAllDistricts)
).Start();
}
But the problem you will face is that you won't be able to access your UI controls from the EventHandler as it will be denied because you are not in the same thread anymore...
Refer to that article for some explanation
How to update the GUI from another thread in C#?
To avoid this you can maybe use the BackgroundWorker control.
Use this option
http://www.asp.net/mvc/overview/older-versions-1/models-(data)/creating-model-classes-with-the-entity-framework-cs
it is easy to use and easy to database operation with less code.