WP8.1 HttpClient doesn't download string after first request - c#

I'm wondering for a few days what's going on. I'm writing an app for Windows Phone 8.1 that uses HttpClient to download json string from Internet. It works fine BUT only once after running the app (in OnNavigatedTo event). Later, smashing 'Refresh' button that is supposed to download string again doesn't work. It's still the same string value that has been download as first. On server, this string changes and I can confirm that by looking at it in browser on PC.
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace WP8App
{
public sealed partial class MainPage : Page
{
private readonly Uri Website = new Uri("https://some-website.com/files/status.json");
private HttpClient http = new HttpClient();
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Refresh();
}
private async void Button_Refresh_Click(object sender, RoutedEventArgs e)
{
Refresh();
}
private async void Refresh()
{
var response = await http.GetStringAsync(Website);
JsonObject api = JsonConvert.DeserializeObject<JsonObject>(response);
TextBox_A.Text = api.value;
TextBox_B.Text = api.length;
TextBox_C.Text = api.size;
TextBox_F.Text = api.volume;
}
private async void ShowDialog(string value)
{
MessageDialog box = new MessageDialog(value);
await box.ShowAsync();
}
}
}
I'm not a master at async, so I count on your eagle eyes xD Thanks

Requests caching is very aggressive on Windows Phone. The easiest way to bypass it is adding a random parameter at the end of the URL. Something like:
private readonly string Website = "https://some-website.com/files/status.json?nocache={0}";
Then change the value every time you use it. Using the current timestamp is a good and cheap way to ensure that the URL will always be different:
var response = await http.GetStringAsync(new Uri(string.Format(Website, DateTime.UtcNow.Ticks));

Related

Apparent Memory Leak when dispatching from HttpClient continuation

The Issue: After using HttpClient correctly (as a static single instance) over a long time, ConcurrentStack+Node instances consistently grow in size causing increased memory usage. Edit: This seems related to the dispatcher called in SetText and AddText.
The Use-Case: I am polling a device on my local network through HTTP transmission. I use System.Threading.Timer to control the frequency of my requests. The callback for the polling timer is async void so that the await operator can be used for continuation control. The default window dispatcher is used to display text results after the HttpRequest is called.
The Code for Recreation: .NET Framework 4.5 ; WPF ; All standard settings with a single TextBlock created in MainWindow with x:Name="Debug"
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace LeakIsolator
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
static MainWindow()
{
WebClient.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
HttpClient.DefaultRequestHeaders.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue()
{
NoStore = true,
NoCache = true
};
}
public MainWindow()
{
InitializeComponent();
Timer = new Timer(Poll, null, Timeout.Infinite, Timeout.Infinite);
Loaded += MainWindow_Loaded;
}
private static HttpClient HttpClient { get; } = new HttpClient();
private static WebClient WebClient { get; } = new WebClient();
private Timer Timer { get; }
private void SetText(string text)
{
Dispatcher.Invoke(() => Debug.Text = text);
}
private void AddText(string text)
{
Dispatcher.Invoke(() => Debug.Text += text);
}
private async void Poll(object a)
{
try
{
SetText("Getting status...");
SetText(await GetResponseStringHttpClient("http://10.10.10.87/status"));
}
catch (Exception e)
{
SetText($"Exception. {e.Message}");
}
finally
{
Start();
}
}
private async Task<string> GetResponseStringWebClient(string address)
{
return await WebClient.DownloadStringTaskAsync(address);
}
private async Task<string> GetResponseStringHttpClient(string address)
{
using (var response = await HttpClient.GetAsync(address))
{
if (response.IsSuccessStatusCode)
{
AddText(" Success...");
return await response.Content.ReadAsStringAsync();
}
else
{
AddText(" Fail.");
return null;
}
}
}
private void Start()
{
Timer.Change(1000, Timeout.Infinite);
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Start();
}
}
}
Using ANTS memory profiler, and running the application for 37 minutes in the most recent test, 2.618 MB (small for now, but this is a long-running application) inaccessible-to-me bytes are allocated by a PinnableBufferCache, presumably stored in the gen 2 heap.
I am not sure if this is a memory leak or is a part of something I do not understand. Why am I seeing these memory increases and why am I unable to dictate the local caching behavior of HttpClient and WebClient?
I would guess AddText, you could try commenting out the code in that method and see if the memory leak goes away.

No overload for 'OnClientReady' matches delegate 'AsyncEventHandler<DiscordClient, ReadyEventArgs>'

I try to make a discord bot in c# with plugin d# and I have this error that shouldn't exist
I watch a tutorial and I copy the code so it should work
using DSharpPlus;
using DSharpPlus.EventArgs;
using System;
using System.Threading.Tasks;
namespace DisordBot
{
public class Bot
{
public DiscordClient Client { get; private set; }
public async Task RunAsync()
{
var config = new DiscordConfiguration
{
};
Client = new DiscordClient(config);
Client.Ready += OnClientReady;
}
private Task OnClientReady(ReadyEventArgs e)
{
return null;
}
}
}
Try to setup configure, bot cant start without token, make sure that he exists.
Delete "return null" from you code, this event can be empty, like all events.
change this:
private Task OnClientReady(ReadyEventArgs e)
to this:
private Task OnClientReady(object sender, ReadyEventArgs e)

Change starting page in app created with Windows Template Studio

I created an app with Windows Template Studio on Visual Studio 2017.
The app is mainly a NavigationDrawer with different pages.
Everything was ok, until I wanted to add a login page.
So I created the XAML of the login page, etc. But now I want it to show before the NavigationDrawer page on app startup.
I seeked some documentation about the App.xaml.cs to know what to change to do that but, because of the use of Windows Template Studio, the code is not really vanilla anymore.
I tried a few things and the only thing I'm able to do right now is to change the shell page of the NavigationDrawer to my Login page.
That's not exactly what I want because my first intention was to make the app unavailable until you log in, and because the NavigationDrawer is still usable the user can still do what he wants to.
My app.xaml.cs looks like this :
using System;
using BasePosteMobilite.Services;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
namespace BasePosteMobilite
{
public sealed partial class App : Application
{
private Lazy<ActivationService> _activationService;
private ActivationService ActivationService
{
get { return _activationService.Value; }
}
public App()
{
InitializeComponent();
// Deferred execution until used. Check https://msdn.microsoft.com/library/dd642331(v=vs.110).aspx for further info on Lazy<T> class.
_activationService = new Lazy<ActivationService>(CreateActivationService);
}
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
if (!args.PrelaunchActivated)
{
await ActivationService.ActivateAsync(args);
}
}
protected override async void OnActivated(IActivatedEventArgs args)
{
await ActivationService.ActivateAsync(args);
}
private ActivationService CreateActivationService()
{
return new ActivationService(this, typeof(ViewModels.LoginViewModel), new Lazy<UIElement>(CreateShell));
}
private UIElement CreateShell()
{
return new Views.ShellPage();
}
}
}
ShellPage.xaml.cs :
using System;
using BasePosteMobilite.ViewModels;
using Windows.UI.Xaml.Controls;
namespace BasePosteMobilite.Views
{
// TODO WTS: Change the icons and titles for all NavigationViewItems in ShellPage.xaml.
public sealed partial class ShellPage : Page
{
private ShellViewModel ViewModel
{
get { return ViewModelLocator.Current.ShellViewModel; }
}
public ShellPage()
{
InitializeComponent();
DataContext = ViewModel;
ViewModel.Initialize(shellFrame, navigationView, KeyboardAccelerators);
}
}
}
ViewModel.Initialize :
public void Initialize(Frame frame, WinUI.NavigationView navigationView, IList<KeyboardAccelerator> keyboardAccelerators)
{
_navigationView = navigationView;
_keyboardAccelerators = keyboardAccelerators;
NavigationService.Frame = frame;
NavigationService.NavigationFailed += Frame_NavigationFailed;
NavigationService.Navigated += Frame_Navigated;
_navigationView.BackRequested += OnBackRequested;
}
You can create a project with login required feature and you will see the following code from ActivateAsync method:
var silentLoginSuccess = await IdentityService.AcquireTokenSilentAsync();
if (!silentLoginSuccess || !IdentityService.IsAuthorized())
{
await RedirectLoginPageAsync();
}
That's it. If you want to redirect to your own page, write the detectation code under ActivationService.ActivateAsync(args) method. If you see the customer is not logged in. Call redirect login method. Here is the code from template studio about redirectlogin:
public async Task RedirectLoginPageAsync()
{
var frame = new Frame();
NavigationService.Frame = frame;
Window.Current.Content = frame;
await ThemeSelectorService.SetRequestedThemeAsync();
NavigationService.Navigate<Views.LogInPage>();
}

Awesomium not loading page or triggering any events

I want to do something a simple as loading a webpage. For some reason Awesomium is not updating properties such as IsLoading, or triggering events such as DocumentReady or LoadingFrameComplete and I have no idea why, can anyone help me out?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Awesomium.Core;
namespace DownloaderTest
{
class ParsingHelper
{
WebView wv;
public ParsingHelper(WebView web)
{
this.wv = web;
}
public void ParsingInitiation(string link)
{
wv.LoadingFrameComplete +=wv_LoadingFrameComplete;
wv.Source = new Uri(link);
}
void wv_LoadingFrameComplete(object sender, FrameEventArgs e)
{
if(e.IsMainFrame)
{
//BeginParsing
((WebView)sender).LoadingFrameComplete -= wv_LoadingFrameComplete;
}
}
}
class Teste
{
WebView MainWeb = WebCore.CreateWebView(1024,768);
public object[] ObtainInformation(int id)
{
ParsingHelper ph = new ParsingHelper(MainWeb);
ph.ParsingInitiation("http://www.google.com");
//More code
return new object[] {};
}
}
}
If I run something like...
Teste t = new Teste();
t.ObtainInformation(1);
wv_LoadingFrameComplete is never triggered and I have no idea why.
try this code to detect page loaded completely
loadingFrameCompete event + IsLoading property
private void Awesomium_Windows_Forms_WebControl_LoadingFrameComplete(object sender, Awesomium.Core.FrameEventArgs e)
{
if (!webControl1.IsLoading)
MessageBox.Show("Page Loaded Completely");
}
Answered here: http://answers.awesomium.com/questions/2260/awesomium-not-loading-page-or-triggering-any-event.html
You are either using Awesomium in non UI environment (not WPF/WinForms control) and must call WebCore.Update() implicitly or you just blocking the same thread so it can't fire events.

Self Hosting WebApi C# with WindowsForms error

I took a sample project webapi Self Hosting, the Microsoft page. The webapi starts correctly, but when accessing the address, it gives the error below. I'm using VS2010 and Windows Forms. With Console Applicattion its working, and Windows Forms not working.
Program code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Web.Http.SelfHost;
using System.Web.Http;
using System.Net.Http;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
HttpSelfHostServer server;
HttpSelfHostConfiguration config;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var config = new HttpSelfHostConfiguration("http://localhost:9090");
config.Routes.MapHttpRoute(
"API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
using (HttpSelfHostServer server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
}
}
private void button2_Click(object sender, EventArgs e)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:9090");
//Console.WriteLine("Products in '{0}':", category);
string query = string.Format("api/products?category={0}", "testes");
var resp = client.GetAsync(query).Result;
//resp.EnsureSuccessStatusCode();
var products = resp.Content.ReadAsAsync<string>().Result;
MessageBox.Show(products);
}
}
}
Controller:
namespace SelfHost
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Http;
public class ProductsController : ApiController
{
public string GetProductsByCategory(string category)
{
return (category ?? "Vazio");
}
}
}
Error:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Object reference not set to an instance of an object.
</ExceptionMessage>
<ExceptionType>System.NullReferenceException</ExceptionType>
<StackTrace>
at System.Web.Http.SelfHost.HttpSelfHostServer.ProcessRequestContext(ChannelContext channelContext, RequestContext requestContext)
</StackTrace>
</Error>
Your code has a bunch of mistakes which I see, and I don't think that I can include them all in commentary. Maybe if you will fix them - this exception will gone.
Issues:
Right after this code server.OpenAsync().Wait(); you call Dispose method on server (because you wrapped everything in using statement). This means that when OpenAsync will be finished (and this task will be finished when server is running) - right after this you will close the server.
You have a bunch of deadlocks on main thread when you call Wait on the task. Check this article http://blogs.msdn.com/b/pfxteam/archive/2011/01/13/10115163.aspx on this.
This is my try to rewrite your example to fix these two issues:
public partial class Form1 : Form
{
HttpSelfHostServer server;
HttpSelfHostConfiguration config;
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
config = new HttpSelfHostConfiguration("http://localhost:9090");
config.Routes.MapHttpRoute(
"API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
HttpSelfHostServer server = new HttpSelfHostServer(config);
await server.OpenAsync();
// Server is running: you can show something to user like - it is running
MessageBox.Show("Server is ready!");
}
private async void button2_Click(object sender, EventArgs e)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:9090");
string query = string.Format("api/products?category={0}", "testes");
var resp = await client.GetAsync(query);
var products = await resp.Content.ReadAsAsync<string>();
MessageBox.Show(products);
}
}

Categories

Resources