WPF Application does not seem to be receiving a response - c#

I currently have two separate projects, one is a WPF application with .NET Framework 4.7.2 and the other is a console application with ASP.NET Core 3.1. The console application used to be .NET 4.7.2 as well however I have just finished moving it to Core.
The WPF Application sends an object to the console application and the console application does some stuff with it and returns a response. My issue currently is that the WPF application successfully sends the object, the console application receives it and does what it needs, however when it sends the response, the WPF application just hangs and must be completely stopped. Here is the code for both:
WPF Application (was working perfectly fine before moving the console to core):
static async Task SendRequest(UploadDetails u)
{
System.Diagnostics.Debug.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(u));
HttpResponseMessage response = await _client.PostAsJsonAsync(_clientUrl, u);
if (response.IsSuccessStatusCode)
{
var responseLink = await response.Content.ReadAsStringAsync();
responseLink = responseLink.Replace("\"", "");
System.Diagnostics.Debug.WriteLine("SUCCESSFUL UPLOAD"); //TODO: Add response
Messenger.Default.Send(new NotificationMessage(responseLink));
}
else
{
System.Diagnostics.Debug.WriteLine("UNSUCCESSFUL UPLOAD"); //TODO: Add response
}
}
Console Application (even sends correct response with postman):
[HttpPost("upload")]
public ActionResult Upload(UploadDetails data)
{
try
{
Task.Factory.StartNew(() => { _Uploader.Upload(data); });
return Ok("Started");
}
catch (Exception e)
{
return NotFound();
}
}
Any help would be greatly appreciated.

Without further information it is hard to determine the actual problem....
But just by looking at the code provided I see one problem:
You are sending JSON yet your action is not inspecting the body.
So I would make one change:
1 Your parameter should have an attribute [FromBody] like this:
[HttpPost]
public ActionResult Upload([FromBody] UploadDetails data)
Also you have to make sure your HttpClient has the correct headers when initialized like this:
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
The last thing I can think of is that you are calling your async method wrong in the WPF application....
For example this would hang on the "await _client.PostAsJsonAsync....." line
private void Button_Click(object sender, RoutedEventArgs e)
{
SendRequest(new UploadDetails { }).Wait();
}
This would NOT hang:
private async void Button_Click(object sender, RoutedEventArgs e)
{
await SendRequest(new UploadDetails { });
}
The reason is that the first one would block the main thread and the second one would not.
But without the code that calls the SendRquest it is impossible to know.

Related

I am not getting any output and i don't know why

using System;
using System.Text;
namespace ConsoleApp7
{
class Program
{
static void Main(string[] args)
{
YourClient client = new YourClient();
client.Put();
}
public class YourClient
{
private readonly HttpClient _client;
public YourClient()
{
_client = new HttpClient();
}
public async Task Put() // must be async
{
using (var request = new HttpRequestMessage(HttpMethod.Put, "https://api.minecraftservices.com/minecraft/profile/name/egg"))
{
request.Headers.Add("Authorization", "Bearer token");
request.Content = new StringContent("body", Encoding.UTF8, "content-type");
using (var response = await _client.SendAsync(request))
{
var data = await response.Content.ReadAsStringAsync();
var code = response.StatusCode;
Console.WriteLine(Convert.ToString(code));
// do something with data
}
}
}
}
}
}
I'm not getting any output and I don't know why. I'm trying to print the response code of the request but nothing is output, is it to do with my method?
I have tried printing hi after Client.Put() and it was printed, so I know that my code is actually running, I just don't know why it isn't printing the status code ...
The excellent comment by Prolog points out one of two issues. If your Console app is built on < C# 7.1 you will need a workaround to prevent the app from exiting (before the request has time to process) so in this case add Console.ReadKey() as the very last line. This will spin the message loop until you hit a key. But this is not the main issue and I would like to offer a couple of debugging tips.
The big issue is this:
If I run your code, your http request is failing and is throwing a System.FormatException
Usually this type of exception is not set to Break when Thrown. (You can verify this by looking in the Exception Settings window.) Unfortunately, this is giving you a silent failure in this case, so you must take matters into your own hands to observe it.
Suggestions for debugging your code
Use a try-catch block around any code that has any likelihood of failing.
Use System.Diagnostics.Debug.Assert which will cause your program to break on a line if any condition expression evaluates to false (but only when you're running in Debug mode not Release mode).
Add output statements to trace execution. Using Debug.WriteLine will send messages to the Output window (but again, only in Debug mode). Alternatively, since we have a Console app here, I'm using the main app window to output trace statements.
Example using 1-3:
public async Task Put() // must be async
{
Console.WriteLine("Begin Put()");
try
{
using (var request = new HttpRequestMessage(HttpMethod.Put, "https://api.minecraftservices.com/minecraft/profile/name/egg"))
{
request.Headers.Add("Authorization", "Bearer token");
request.Content = new StringContent("body", Encoding.UTF8, "content-type");
using (var response = await _client.SendAsync(request))
{
var data = await response.Content.ReadAsStringAsync();
var code = response.StatusCode;
Console.WriteLine(Convert.ToString(code));
// do something with data
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.Assert(condition: false, message: ex.Message);
}
Console.WriteLine("End Put()");
}
Now, if I run the code it will break and show what the problem is.
Use the Exception Settings window to turn on all exceptions (if in doubt). Now the code will break on the exact line that is the problem.
Verify that you are Setting Authorization Header of HttpClient correctly as this may be part of the root cause of the exception.
Finally, if you continue after the Debug.Assert you will see the following text in your console which will confirm whether your Put method has had a chance to complete or not.
Hope these suggestions help you solve this problem and future ones!
// This workaround for C# versions below 7.1 attempts to
// mimic an `async Main` method.
static void Main(string[] args)
{
RunAsync();
Console.ReadKey();
}
private static async void RunAsync()
{
YourClient client = new YourClient();
// Put() should be awaited inside an async method
await client.Put();
}

.NET Core GetFromJsonAsync exits with no error or debugging information

I am trying to debug a request by GetFromJsonAsync which is supposed to fetch data from a Flask API and convert to JSON within a .NET Core cli app.
The issue I am having however is that after performing the request the cli app simply exits with no error. I have tried implementing try/catch block but nothing shows up there.
the Flask endpoint builds jsonifies a number of uuids and messages from Postgres and returns them to the client.
As GetFromJsonAsync is asynchronous I have tried making the Flask endpoint likewise but that has not seemed to help at all. The latter works fine and has been validated with curl.
I know the call executes as I can see it in my web server logs.
A similar call which simply returns plain javascript object {"foo": "bar"} works fine which is why I think this could by an async issue but I cannot see any errors etc to troubleshoot. I have placed a breakpoint on the foreach after the call but this is never hit.
What am I missing here?
public static async void GetMessages()
{
ConfigureHeaders();
try
{
var client = Client;
var res = await Client.GetFromJsonAsync<Received>(Url + "/api/chat/message"); // stops here
foreach (var c in res!.messages) // breakpoint here is never hit
Console.WriteLine(c);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public class Received
{
public Dictionary<string,string> messages { get; set; }
}
Flask
#message.get("/api/chat/message")
#csrf.exempt
async def get_messages():
new_msgs = {}
msgs = await get_unreplied() # DB gets called from another function here
try:
for m in msgs:
new_msgs[m.id] = m.message
if len(new_msgs) != 0:
return jsonify(new_msgs)
else:
return jsonify("no messages")
except Exception as e:
print(str(e))
This returns...
{
"id_foo1": "message_bar1",
"id_foo2": "message_bar2"
}
Best guess: your Main function is not awaiting the call to GetMessages
public async Task<int> Main(string []args)
{
await GetMessages();
}

called from Blazor client HttpClient.GetJsonAsync returns (with data), but then times out

I am making a Http.JsonAsync<MyType>("api/MyController/Users"); call which returns very quickly but then times out in 5 secs rather than giving me the data.
I have made other such calls that have worked fine, but something weird is going on.
I started from the standard weather service Blazor client template and all worked fine
I kick it off from a button event
<button onclick=#load_click>LOAD!</button>
#functions {
private void load_click()
{
try
{
Logger.Log($"about to call PopulateExistingUsers");
var taskUsers = Http.GetJsonAsync<UsersPageData>("api/ShowerQ/Users");
Logger.Log($"returned from async requesting users");
if (!taskUsers.Wait(5000))
{
throw new Exception($"timeout!");
}
var users = taskUsers.Result;
Logger.Log($"populated existing users ok. Users.Count = {users.Users.Count()}");
}
catch (Exception e)
{
Logger.Log(e.ToString());
}
}
Server side Controller code:
[HttpGet("Users")]
public UsersPageData GetUsers()
{
try
{
var users = _repos.GetAllUsers().ToList();
Log($"returned from GetALlUsers() with {users.Count} users");
return new UsersPageData() {Users = users};
}
finally
{
Log($"aft6er returning from method {nameof(GetUsers)}");
}
}
Logger.Log just does Console.Writeline, which goes to the browser console - very handy!
Expected:
log output to console:
"populated existing users ok. Users.Count = 3"
ACtual logs:
The output I'm getting is:
WASM: 09:31:26.49:about to call PopulateExistingUsers
WASM: 09:31:26.56:returned from async requesting users
WASM: 09:31:31.57:System.Exception: timeout!
WASM: at ShowerQWeb2.Client.Pages.Index.load_click () [0x00048] in C:\Users\XXXX\Source\repos\ShowerQWeb2\ShowerQWeb2.Client\Pages\Index.razor:62
and on server side (which is running on same machine so clocks are in sync apart from a hour)
10:31:26.68:returned from GetALlUsers() with 3 users
10:31:26.68:aft6er returning from method GetUsers
The chrome network debug shows whats being returned:
response header:
Date: Mon, 13 May 2019 09:31:26 GMT
{"users":[{"id":1,"name":"David XX"},{"id":2,"name":"Sumith YY"},{"id":3,"name":"David ZZ"}]}
So, it looks like its getting stuck deserializing maybe?
You're probably getting stuck in a deadlock because you are abusing async. You shouldn't be calling .Wait() and .Result, use async code properly.
First make the method async and return a Task:
private async Task load_click()
{
// snip
}
Then await your HTTP calls properly:
var users = await Http.GetJsonAsync<UsersPageData>("api/ShowerQ/Users");

gRPC with WPF not working

I am trying to get the gRPC C# example working inside WPF.
The same code which is working inside a Console Application is not working. What am I missing.
The minimal class which works in the Console App and does not work in WPF looks like this:
public class GrpcClientImpl
{
private GrpcService.GrpcService.GrpcServiceClient client;
public GrpcTestClientImpl()
{
var channel = new Channel("127.0.0.1:6980", ChannelCredentials.Insecure);
client = new GrpcService.GrpcService.GrpcServiceClient(channel);
ProcessFeed().Wait();
}
public async Task ProcessFeed()
{
try
{
using (var call = client.Feed(new FeedRequest()))
{
var responseStream = call.ResponseStream;
while (await responseStream.MoveNext())
{
var result = responseStream.Current;
Console.WriteLine("received result");
}
}
}
catch (RpcException e)
{
Console.WriteLine("RPC failed " + e);
throw;
}
}
}
The responseStream.MoveNext() is where it is hanging. It does not respond to sent items and it does also not trigger an exception if the gRPC server is not there. What have I missed?
The problem is the blocking call ProcessFeed().Wait(); within the constructor.
This post explains why:
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
To solve the issue, call await ProcessFeed(); from outside (not in the costructor).

Xamarin.Android using async method on background thread causes screen flash

So I'm trying to create a loading/splash screen for an app that I'm creating. Basically, if the user isn't authenticated, then they shouldn't be able to access the other parts of the app. Additionally, I'd like the app to attempt to sync the necessary database objects before it loads up the main activity.
The problem is that when I call the Authenticate() method and the InitLocalStoreAsync() methods, the screen flashes (almost like an activity reload, or like the app is doing something that I don't understand that's hiding the activity) while the methods are executing. I'd like that not to happen.
I'm very new to Android App Dev and even newer to Xamarin.
I'm using modified code that comes from the Azure Mobile Services tutorial on authentication etc.
Should I be somehow executing these methods using RunOnUiThread? If so, how do I await in conjunction with RunOnUiThread? Or should I be doing this in a completely different way?
I'm very lost. I've tried to search and find tutorials to follow, but I can't seem to find the answer. Here's the code so far:
protected override async void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
SetContentView (Resource.Layout.Activity_Splash);
// Create your application here
try{
CurrentPlatform.Init ();
// Create the Mobile Service Client instance, using the provided
// Mobile Service URL and key
client = new MobileServiceClient (applicationURL, applicationKey);
statusText = FindViewById<TextView> (Resource.Id.SplashStatusText);
ThreadPool.QueueUserWorkItem(x => Initialize());
}catch(Java.Net.MalformedURLException){
CreateAndShowDialog (new Exception ("There was an error creating the Mobile Service. Verify the URL"), "Error");
}catch(Exception e) {
CreateAndShowDialog (e, "Error");
}
}
private async void Initialize()
{
RunOnUiThread(() => statusText.Text = "Authenticating...");
await Authenticate();
RunOnUiThread (() => statusText.Text = "Syncing...");
await InitLocalStoreAsync();
MoveToMainActivity();
}
private async Task Authenticate()
{
try
{
user = await client.LoginAsync(this, MobileServiceAuthenticationProvider.Google);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private async Task InitLocalStoreAsync()
{
// new code to initialize the SQLite store
string path = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), localDbFilename);
if (!File.Exists(path))
{
File.Create(path).Dispose();
}
var store = new MobileServiceSQLiteStore(path);
store.DefineTable<ToDoItem>();
// Uses the default conflict handler, which fails on conflict
// To use a different conflict handler, pass a parameter to InitializeAsync. For more details, see http://go.microsoft.com/fwlink/?LinkId=521416
await client.SyncContext.InitializeAsync(store);
}
How do I restructure this so that I don't get any screen flashes?
If you want to run an asynchronous method you have to use the Task Factory:
RunOnUiThread(() => statusText.Text = "Loading.");
Task.Run(() => AsyncWork()).ContinueWith(result => RunOnUiThread(() => statusText.Text = "Done!"));
The screen flashes i think it could be 2 things, the app crashed and is trying to recover the last activity or your are trying to update elements on the UI thread and doing processing/work too, so it might be "stutter".

Categories

Resources