MediaElement Memory leak on Win8.1 - c#

he below code just plays 2 videos over an over again using a xaml mediaelement. I'm noticing that the memory is not getting cleaned up on windows 8.1 systems and it eventually dies. I see memory getting reclaimed on Win8.0. Am I doing something wrong?
namespace PlaybackTest
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
StorageFile video1;
StorageFile video2;
StorageFile nextvid;
bool firstvid = true;
Windows.Storage.Streams.IRandomAccessStream _stream;
int iterctr = 0;
public MainPage()
{
this.InitializeComponent();
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
meMainPlayer.Source = null;
var filepath = Windows.ApplicationModel.Package.Current.InstalledLocation;
video1 = await filepath.GetFileAsync("Data\\output1.mp4");
video2 = await filepath.GetFileAsync("Data\\output2.mp4");
nextvid = video1;
}
private void MediaElement_MediaEnded_1(object sender, RoutedEventArgs e)
{
Debug.WriteLine("media ended event");
if (firstvid == true)
{
Debug.WriteLine("setting up second vid");
firstvid = false;
nextvid = video2;
}
else
{
Debug.WriteLine("setting up first vid");
firstvid = true;
nextvid = video1;
}
meMainPlayer.Stop();
Debug.WriteLine("after stop ");
meMainPlayer.Position = new TimeSpan(0);
Debug.WriteLine("after position set to 0 ");
meMainPlayer.Source = null;
Debug.WriteLine("meplayer source = null ");
}
private void MediaElement_CurrentStateChanged_1(object sender, RoutedEventArgs e)
{
if (meMainPlayer.CurrentState == MediaElementState.Closed)
{
Debug.WriteLine("current media element state closed");
if (_stream != null)
{
_stream.Dispose();
_stream = null;
}
LoadNextVid();
}
}
private async void LoadNextVid()
{
Debug.WriteLine("");
await System.Threading.Tasks.Task.Delay(1000);
try
{
Debug.WriteLine("before strem opened");
_stream = await nextvid.OpenAsync(FileAccessMode.Read);
Debug.WriteLine("after stream opened");
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
meMainPlayer.SetSource(_stream, nextvid.ContentType);
txtIter.Text = "Iteration:" + iterctr;
});
iterctr++;
Debug.WriteLine("after dispatcher");
}
catch (Exception ex)
{
Debug.WriteLine("exceoption caught " + ex.Message);
}
}
private async void btnStart_Click_1(object sender, RoutedEventArgs e)
{
LoadNextVid();
}
}
}

You're not leveraging the IDisposable construct when accessing the file as a resource.
Specifically you are missing the "Using" construct when accessing the file as a resource.
As a result, memory stays allocated because this resource does not get disposed.
_stream = await nextvid.OpenAsync(FileAccessMode.Read);
Consider the following example:
public async void ContinueFileOpenPicker(FileOpenPickerContinuationEventArgs args)
{
if (args.Files.Count > 0)
{
var imageFile = args.Files[0] as StorageFile;
// Ensure the stream is disposed once the image is loaded
using (IRandomAccessStream fileStream = await imageFile.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
// Set the image source to the selected bitmap
BitmapImage bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
ImageControl.Source = bitmapImage;
await _viewModel.Upload(imageFile);
}
}
}

Related

Windows 10 Bluetooth DeviceInformation Custom Pairing Access Denied

I have a .NET Core 3.1 Windows application (WinForm app) running on Windows 10 Version 10.0.17134 Build 17134. I am trying to connect and pair with Bluetooth devices using BluetoothLEAdvertisementWatcher. In the main form of the app I am using CefSharp.WinForms to display an HTML page.
My problem is that when I initialize the browser using _browser = new ChromiumWebBrowser(Settings.Default.IndexPageUrl); I can no longer pair with the Bluetooth device. I get AccessDenied returned from pairRequest.Status in my custom pairing event.
Here is the code:
using CefSharp;
using CefSharp.WinForms;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Enumeration;
namespace myApp
{
public partial class MainForm : Form
{
private readonly ILogger<MainForm> _logger;
private ChromiumWebBrowser _browser;
private static BluetoothLEAdvertisementWatcher _bleAdvertisementWatcher = null;
private static volatile ConcurrentDictionary<ulong,BleDeviceInfo> _bleDevicesInfo;
private readonly SemaphoreSlim _semaphoreSlim;
/// <summary>
/// Used to create a thread-safe boolean; do not access directly use AddingDevices instead
/// </summary>
private int _addingDevicesBool = 0;
public event Action<BleDeviceInfo> OnBleDeviceDetected;
public MainForm(): this(Program.LogFactory.CreateLogger<MainForm>())
{ }
public MainForm(ILogger<MainForm> logger)
{
_logger = logger;
_semaphoreSlim = new SemaphoreSlim(1, 1);
_bleDevicesInfo = new ConcurrentDictionary<ulong,BleDeviceInfo>();
InitBluetoothUtils();
InitializeBrowser();
}
#region browser setup
private void InitializeBrowser()
{
try
{
Cef.EnableHighDPISupport();
//When I comment out the 2 lines below I can succesfully pair with a BLE device
_browser = new ChromiumWebBrowser(Settings.Default.IndexPageUrl);
toolStripContainer.ContentPanel.Controls.Add(_browser);
//TODO: Uncomment the lines below to see Chrome Dev Tools
//#if DEBUG
// _browser.IsBrowserInitializedChanged += OnIsBrowserInitializedChanged;
//#endif
}
catch (Exception ex)
{
_logger.LogError(ex, Settings.BrowserInitError);
throw;
}
}
private void OnIsBrowserInitializedChanged(object sender, EventArgs e)
{
_browser.ShowDevTools();
}
#endregion
#region BLE setup
#region properties
/// <summary>
/// Thread-safe boolean property
/// </summary>
public bool ListeningForBleDevices
{
get { return (Interlocked.CompareExchange(ref _addingDevicesBool, 1, 1) == 1); }
set
{
if (value)
{
Interlocked.CompareExchange(ref _addingDevicesBool, 1, 0);
}
else
{
Interlocked.CompareExchange(ref _addingDevicesBool, 0, 1);
}
}
}
#endregion
private void InitBluetoothUtils()
{
StartListeningForBleDevices();
}
public void StartListeningForBleDevices()
{
ListeningForBleDevices = true;
StartBleWatcher();
}
private void StartBleWatcher()
{
try
{
ListeningForBleDevices = false;
if(_bleAdvertisementWatcher == null)
{
_bleAdvertisementWatcher = new BluetoothLEAdvertisementWatcher
{
ScanningMode = BluetoothLEScanningMode.Active
};
// Only activate the watcher when we're recieving values >= -80
_bleAdvertisementWatcher.SignalStrengthFilter.InRangeThresholdInDBm = -80;
// Stop watching if the value drops below -90 (user walked away)
_bleAdvertisementWatcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -90;
// Register events
_bleAdvertisementWatcher.Received += OnBleAdvWatcherReceived;
_bleAdvertisementWatcher.Stopped += OnBleAdvWatcherStopped;
// Wait 5 seconds to make sure the device is really out of range
_bleAdvertisementWatcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000);
_bleAdvertisementWatcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000);
}
//Start Watcher
ListeningForBleDevices = true;
_bleAdvertisementWatcher.Start();
}
catch (Exception ex)
{
_logger.LogError(ex, string.Empty);
throw;
}
}
public void StopBleWatcher()
{
_bleAdvertisementWatcher?.Stop();
ListeningForBleDevices = false;
}
private void OnBleAdvWatcherStopped(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementWatcherStoppedEventArgs args)
{
_logger.LogInformation("Ble Advertisement Watcher stopped");
}
/// <summary>
/// This event will fire multiple times for the same BLE device
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private async void OnBleAdvWatcherReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
if(!ListeningForBleDevices)
{
return;
}
BleDeviceInfo bleDeviceInfo = null;
try
{
var advLocalName = args.Advertisement.LocalName;
if (string.IsNullOrEmpty(advLocalName) || !advLocalName.Contains("my custom prefix", StringComparison.OrdinalIgnoreCase))
{
return;
}
_semaphoreSlim.Wait();
bleDeviceInfo = await SetBleDeviceInfo(args).ConfigureAwait(false);
_semaphoreSlim.Release();
}
catch (Exception ex)
{
_logger.LogError(ex, string.Empty);
_semaphoreSlim.Release();
throw;
}
if(bleDeviceInfo != null)
{
OnBleDeviceDetected?.Invoke(bleDeviceInfo);
}
}
private async Task<BleDeviceInfo> SetBleDeviceInfo(BluetoothLEAdvertisementReceivedEventArgs args)
{
BleDeviceInfo bleDeviceInfo = null;
try
{
var bluetoothAddress = args.BluetoothAddress;
var deviceExists = GetBleDevice(bluetoothAddress);
if(deviceExists == null)
{
BluetoothLEDevice bleDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(bluetoothAddress);
//TODO: Pairing will not work when ChromiumWebBrowser gets initialized
var isPaired = await PairDevice(bleDevice).ConfigureAwait(false);
bleDeviceInfo = new BleDeviceInfo(bleDevice, args);
_bleDevicesInfo.AddOrUpdate(bleDeviceInfo.BluetoothAddress, bleDeviceInfo, (key, bleDeviceInfo) => bleDeviceInfo);
}
}
catch (Exception ex)
{
_logger.LogError(ex, string.Empty);
throw;
}
return bleDeviceInfo;
}
public BleDeviceInfo GetBleDevice(ulong bluetoothAddress)
{
try
{
return _bleDevicesInfo.Values.FirstOrDefault(d => d.BluetoothAddress.Equals(bluetoothAddress));
}
catch (Exception ex)
{
_logger.LogError(ex, string.Empty);
throw;
}
}
public async Task<bool> PairDevice(BluetoothLEDevice bleDevice)
{
if (bleDevice == null)
{
return false;
}
var isPaired = false; // bleDevice.DeviceInformation.Pairing.IsPaired;
try
{
var canPair = bleDevice.DeviceInformation.Pairing.CanPair;
var deviceId = bleDevice.DeviceId;
if (canPair)
{
DeviceInformationCustomPairing customPairing = bleDevice.DeviceInformation.Pairing.Custom;
customPairing.PairingRequested += OnCustomPairingRequested;
var pairRequest = await customPairing.PairAsync(DevicePairingKinds.ProvidePin, DevicePairingProtectionLevel.None);
customPairing.PairingRequested -= OnCustomPairingRequested;
var resultStatus = pairRequest.Status;
isPaired = resultStatus == DevicePairingResultStatus.Paired;
if (isPaired)
{
//TODO: Verify this code block
bleDevice.Dispose();
Thread.Sleep(2000); //try 2 second delay.
//Reload device so that the GATT services are there. This is why we wait.
bleDevice = await BluetoothLEDevice.FromIdAsync(deviceId);
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, string.Empty);
throw;
}
return isPaired;
}
public async Task<bool> PairDevice(ulong bluetoothAddress)
{
BluetoothLEDevice bleDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(bluetoothAddress, BluetoothAddressType.Public);
return await PairDevice(bleDevice).ConfigureAwait(false);
}
private void OnCustomPairingRequested(DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs args)
{
try
{
//This method does not get called when ChromiumWebBrowser is initialized
//However, when _browser = new ChromiumWebBrowser is not called this method works as expected
var deviceName = args.DeviceInformation.Name;
var devicePin = GetBlePin(deviceName);
var pinDeferral = args.GetDeferral();
args.Accept(devicePin.ToString(CultureInfo.InvariantCulture));
pinDeferral.Complete();
}
catch (Exception)
{
throw;
}
}
private int GetBlePin(string serialNumber)
{
return 12345;
}
#endregion
}
}
Things I have tried:
Calling InitializeBrowser on a separate thread using Task.Run(() => { InitializeBrowser(); }).ConfigureAwait(false);
Calling InitBluetoothUtils on a separate thread using Task.Run(() => { InitBluetoothUtils(); }).ConfigureAwait(false);
Calling both InitializeBrowser and InitBluetoothUtils on separate threads
Tried using SynchronizationContext by getting the current context in the MainForm constructor, and then calling PairDevice(bleDevice) using that context
Each time I get AccessDenied. The only thing that works successfully is when I comment out _browser = new ChromiumWebBrowser(BASettings.Default.IndexPageUrl); and toolStripContainer.ContentPanel.Controls.Add(_browser);

How to call a function in a backgroundworker thread that is to be completed on the main UI thread? [duplicate]

So, first I have read a ton of threads on this particular problem and I still do not understand how to fix it. Basically, I am trying to communicate with a websocket and store the message received in an observable collection that is bound to a listview. I know that I am getting a response back properly from the socket, but when it tries to add it to the observable collection it gives me the following error:
The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
I've read some information on "dispatch" as well as some other things, but I am just massively confused! Here is my code:
public ObservableCollection<string> messageList { get; set; }
private void MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
{
string read = "";
try
{
using (DataReader reader = args.GetDataReader())
{
reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
read = reader.ReadString(reader.UnconsumedBufferLength);
}
}
catch (Exception ex) // For debugging
{
WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult);
// Add your specific error-handling code here.
}
if (read != "")
messageList.Add(read); // this is where I get the error
}
And this is the binding:
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
//await Authenticate();
Gameboard.DataContext = Game.GameDetails.Singleton;
lstHighScores.ItemsSource = sendInfo.messageList;
}
How do I make the error go away while still binding to the observable collection for my listview?
This solved my issue:
Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// Your UI update code goes here!
}
);
Correct way to get the CoreDispatcher in a Windows Store app
Try replacing
messageList.Add(read);
with
Dispatcher.Invoke((Action)(() => messageList.Add(read)));
If you're calling from outside your Window class, try:
Application.Current.Dispatcher.Invoke((Action)(() => messageList.Add(read)));
Slight modification for task based async methods but the code in here will not be awaited.
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// Your UI update code goes here!
}
).AsTask();
This code WILL await, and will allow you to return a value:
private async static Task<string> GetPin()
{
var taskCompletionSource = new TaskCompletionSource<string>();
CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
async () =>
{
var pin = await UI.GetPin();
taskCompletionSource.SetResult(pin);
}
);
return await taskCompletionSource.Task;
}
And on Android:
private async Task<string> GetPin()
{
var taskCompletionSource = new TaskCompletionSource<string>();
RunOnUiThread(async () =>
{
var pin = await UI.GetPin();
taskCompletionSource.SetResult(pin);
});
return await taskCompletionSource.Task;
}
Maby this is not a "good" practice, but it works.. I leave a message from webSocket, to mainBody instance, where I have a timered reader...
public class C_AUTHORIZATION
{
public Observer3.A_MainPage_cl parentPageInstance; //еще одни экземпляр родителя
public WebSocket x_Websocket;
private string payload = "";
private DateTime nowMoment = DateTime.Now;
public void GET_AUTHORIZED()
{
bitfinex_Websocket= new WebSocket("wss://*****.com/ws/2");
var apiKey = "";
var apiSecret = "";
DateTime nowMoment = DateTime.Now;
payload = "{}";
x_Websocket.Opened += new EventHandler(websocket_Opened);
x_Websocket.Closed += new EventHandler(websocket_Closed);
}
void websocket_Opened(object sender, EventArgs e)
{
x_Websocket.Send(payload);
parentPageInstance.F_messager(payload);
}
void websocket_Closed(object sender, EventArgs e)
{
parentPageInstance.F_messager("L106 websocket_Closed!");
GET_AUTHORIZED();
}
}
public sealed partial class A_MainPage_cl : Page
{
DispatcherTimer ChartsRedrawerTimer;
public bool HeartBeat = true;
private string Message;
public A_MainPage_cl()
{
this.InitializeComponent();
ChartsRedrawerTimer = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 0, 0, 100) };
ChartsRedrawerTimer.Tick += Messager_Timer;
ChartsRedrawerTimer.Start();
}
private void Messager_Timer(object sender, object e)
{
if(Message !=null) //
{
F_WriteLine(Message);
Message = null; //
}
}
public void F_messager(string message) //
{
Message = message;
}
In Xamarin, I got around this by using:
Device.BeginInvokeOnMainThread(() => {
// code goes here
});

Performace of multi-thread webbrowser control in ASP.NET Application

We have a .aspx page to programmatically load page content of up to 5 urls and check each for a keyword. The following code is working but need to improve cpu usage and time performance and I am not an expert in this area
First: use of async web form to wait for the urls
protected void Page_Load(object sender, EventArgs e)
{
//the page won't load till the registered task is completed
RegisterAsyncTask(new PageAsyncTask(ProcessURLsKeywords));
}
Second: create task for each url-keyword pair and wait for them all to finish then proceed to return page response
private async Task ProcessURLsKeywords()
{
List<Task> availableTasks = new List<Task>();
failedURLs = new ConcurrentBag<string>(); //thread-safe collection of unordered items
//start checking each keyword-url pair
if (key1 != null && !string.IsNullOrWhiteSpace(url1))
{
availableTasks.Add(CheckPageContent(url1, key1));
}
//do the same for url2,key2 and url3,key3...etc
await Task.WhenAll(availableTasks.ToArray());
//return response
}
Third: Function get content
private async Task CheckPageContent(string url, string key)
{
try
{
string content;
var browser = new WebProcessor();
content = await browser.GetGeneratedHTML(url);
if (content != null)
{
if (!content.ToLower().Contains(key.ToLower()))
{
failedURLs.Add(url);
}
}
content = null;
}
catch (Exception ex)
{
}
}
WebProcessor Class creates STA thread for each url and return the result
public class WebProcessor
{
private string GeneratedSource { get; set; }
private string URL { get; set; }
private MyWebBrowser wb { get; set; }
private static Mutex mutex = new Mutex();
public async Task<string> GetGeneratedHTML(string url)
{
URL = url;
await Task.Run(() =>
{
Thread t = new Thread(new ThreadStart(WebBrowserThread));
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
});
return GeneratedSource;
}
private void WebBrowserThread()
{
mutex.WaitOne();
wb = new MyWebBrowser();
try
{
wb.AllowNavigation = true;
wb.ScriptErrorsSuppressed = true;
wb.Navigate(URL);
wb.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(
wb_DocumentCompleted);
while (wb.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
//Added this line, because the final HTML takes a while to show up
GeneratedSource = wb.DocumentText;
//GeneratedSource = wb.Document.Body.InnerText;
}
catch (Exception ex)
{
}
finally
{
mutex.ReleaseMutex();
wb.Dispose();
}
}
private void wb_DocumentCompleted(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
try
{
MyWebBrowser wb = (MyWebBrowser)sender;
if (wb.ReadyState != System.Windows.Forms.WebBrowserReadyState.Complete)
return;
if (wb.Document == null)
return;
GeneratedSource = wb.Document.Body.InnerText;
//load frame content within page - web browser doesn't do that automatically
foreach (var frame in wb.Document.Window.Frames)
{
HtmlWindow winframe = frame as HtmlWindow;
WebProcessor webFrame = new WebProcessor();
try
{
System.Threading.SynchronizationContext.Current.Post(async delegate
{
try
{
GeneratedSource += await webFrame.GetGeneratedHTML(winframe.Url.AbsoluteUri);
}
catch (Exception ex)
{
}
}, null);
}
catch (Exception ex)
{
}
}
}
catch (Exception ex)
{
}
}
/*********************************************************************************************/
}
I tried integrating Application.Run() and message pump features but the code blocks on Application.Run()

Windows Phone 8.1 Post Request

I'm developing a windows phone 8.1 application.
I'm making use of Twilio to send text messages at one go with Azure services.
Thing is that I have to make a post request to a URL. When I use Fiddler to make the request, everything works great! However, I don't know how to reproduce the same using C#. I tried using HTTP Client and all but don't know how to make it work good.
Could anyone kindly help me?
Thanking you in advance.
using SDKTemplate;
using Windows.UI.Xaml.Controls;using System;
using System.Threading;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Navigation;
using Windows.Web.Http;
namespace SDKSample.HttpClientSample
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class Scenario6 : Page, IDisposable
{
// A pointer back to the main page. This is needed if you want to call methods in MainPage such
// as NotifyUser()
MainPage rootPage = MainPage.Current;
private HttpClient httpClient;
private CancellationTokenSource cts;
public Scenario6()
{
this.InitializeComponent();
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Helpers.CreateHttpClient(ref httpClient);
cts = new CancellationTokenSource();
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
// If the navigation is external to the app do not clean up.
// This can occur on Phone when suspending the app.
if (e.NavigationMode == NavigationMode.Forward && e.Uri == null)
{
return;
}
Dispose();
}
private async void Start_Click(object sender, RoutedEventArgs e)
{
Uri resourceAddress;
// The value of 'AddressField' is set by the user and is therefore untrusted input. If we can't create a
// valid, absolute URI, we'll notify the user about the incorrect input.
if (!Helpers.TryGetUri(AddressField.Text, out resourceAddress))
{
rootPage.NotifyUser("Invalid URI.", NotifyType.ErrorMessage);
return;
}
Helpers.ScenarioStarted(StartButton, CancelButton, OutputField);
rootPage.NotifyUser("In progress", NotifyType.StatusMessage);
try
{
HttpMultipartFormDataContent form = new HttpMultipartFormDataContent();
form.Add(new HttpStringContent(RequestBodyField.Text), "data");
HttpResponseMessage response = await httpClient.PostAsync(resourceAddress, form).AsTask(cts.Token);
await Helpers.DisplayTextResultAsync(response, OutputField, cts.Token);
rootPage.NotifyUser("Completed", NotifyType.StatusMessage);
}
catch (TaskCanceledException)
{
rootPage.NotifyUser("Request canceled.", NotifyType.ErrorMessage);
}
catch (Exception ex)
{
rootPage.NotifyUser("Error: " + ex.Message, NotifyType.ErrorMessage);
}
finally
{
Helpers.ScenarioCompleted(StartButton, CancelButton);
}
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
cts.Cancel();
cts.Dispose();
// Re-create the CancellationTokenSource.
cts = new CancellationTokenSource();
}
public void Dispose()
{
if (httpClient != null)
{
httpClient.Dispose();
httpClient = null;
}
if (cts != null)
{
cts.Dispose();
cts = null;
}
}
}
}
So okay,
I've tried that the below. It seems to be sending the request but without a body in json. How can I send a request in JSON using the following code?
using (var client = new HttpClient())
{
var values = new Dictionary<string, string>
{
{ "thing1", "hello" },
{ "thing2", "world" }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("http://www.example.com/recepticle.aspx", content);
var responseString = await response.Content.ReadAsStringAsync();
}
Here my new code which is not working (Getting error cannot convert cannot convert from 'windows.web.http.http stringcontent' to 'system.net.http.httpcontent' on line System.Net.Http.HttpResponseMessage response = await client.PostAsync("http://twilionotifs.azure-mobile.net/api/notificationqueue", stringContent);):
private async void Button_Click(object sender, RoutedEventArgs e)
{
HttpStringContent stringContent = new HttpStringContent("{ \"firstName\": \"John\" }",
Windows.Storage.Streams.UnicodeEncoding.Utf8,
"application/json");
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
System.Net.Http.HttpResponseMessage response = await client.PostAsync("http://twilionotifs.azure-mobile.net/api/notificationqueue", stringContent);
}
}

The application called an interface that was marshalled for a different thread - Windows Store App

So, first I have read a ton of threads on this particular problem and I still do not understand how to fix it. Basically, I am trying to communicate with a websocket and store the message received in an observable collection that is bound to a listview. I know that I am getting a response back properly from the socket, but when it tries to add it to the observable collection it gives me the following error:
The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
I've read some information on "dispatch" as well as some other things, but I am just massively confused! Here is my code:
public ObservableCollection<string> messageList { get; set; }
private void MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
{
string read = "";
try
{
using (DataReader reader = args.GetDataReader())
{
reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
read = reader.ReadString(reader.UnconsumedBufferLength);
}
}
catch (Exception ex) // For debugging
{
WebErrorStatus status = WebSocketError.GetStatus(ex.GetBaseException().HResult);
// Add your specific error-handling code here.
}
if (read != "")
messageList.Add(read); // this is where I get the error
}
And this is the binding:
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
//await Authenticate();
Gameboard.DataContext = Game.GameDetails.Singleton;
lstHighScores.ItemsSource = sendInfo.messageList;
}
How do I make the error go away while still binding to the observable collection for my listview?
This solved my issue:
Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// Your UI update code goes here!
}
);
Correct way to get the CoreDispatcher in a Windows Store app
Try replacing
messageList.Add(read);
with
Dispatcher.Invoke((Action)(() => messageList.Add(read)));
If you're calling from outside your Window class, try:
Application.Current.Dispatcher.Invoke((Action)(() => messageList.Add(read)));
Slight modification for task based async methods but the code in here will not be awaited.
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// Your UI update code goes here!
}
).AsTask();
This code WILL await, and will allow you to return a value:
private async static Task<string> GetPin()
{
var taskCompletionSource = new TaskCompletionSource<string>();
CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
async () =>
{
var pin = await UI.GetPin();
taskCompletionSource.SetResult(pin);
}
);
return await taskCompletionSource.Task;
}
And on Android:
private async Task<string> GetPin()
{
var taskCompletionSource = new TaskCompletionSource<string>();
RunOnUiThread(async () =>
{
var pin = await UI.GetPin();
taskCompletionSource.SetResult(pin);
});
return await taskCompletionSource.Task;
}
Maby this is not a "good" practice, but it works.. I leave a message from webSocket, to mainBody instance, where I have a timered reader...
public class C_AUTHORIZATION
{
public Observer3.A_MainPage_cl parentPageInstance; //еще одни экземпляр родителя
public WebSocket x_Websocket;
private string payload = "";
private DateTime nowMoment = DateTime.Now;
public void GET_AUTHORIZED()
{
bitfinex_Websocket= new WebSocket("wss://*****.com/ws/2");
var apiKey = "";
var apiSecret = "";
DateTime nowMoment = DateTime.Now;
payload = "{}";
x_Websocket.Opened += new EventHandler(websocket_Opened);
x_Websocket.Closed += new EventHandler(websocket_Closed);
}
void websocket_Opened(object sender, EventArgs e)
{
x_Websocket.Send(payload);
parentPageInstance.F_messager(payload);
}
void websocket_Closed(object sender, EventArgs e)
{
parentPageInstance.F_messager("L106 websocket_Closed!");
GET_AUTHORIZED();
}
}
public sealed partial class A_MainPage_cl : Page
{
DispatcherTimer ChartsRedrawerTimer;
public bool HeartBeat = true;
private string Message;
public A_MainPage_cl()
{
this.InitializeComponent();
ChartsRedrawerTimer = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 0, 0, 100) };
ChartsRedrawerTimer.Tick += Messager_Timer;
ChartsRedrawerTimer.Start();
}
private void Messager_Timer(object sender, object e)
{
if(Message !=null) //
{
F_WriteLine(Message);
Message = null; //
}
}
public void F_messager(string message) //
{
Message = message;
}
In Xamarin, I got around this by using:
Device.BeginInvokeOnMainThread(() => {
// code goes here
});

Categories

Resources