My calls to a Google API from an API Controller in IIS express hang indefinitely when called sequentially using async await.
var id = CreateDocument("My Title").Result;
async Task<string> CreateDocument(string title)
{
var file = new GData.File { Title = title };
// Stepping over this line in the debugger never returns in IIS Express.
file = await Service.Files.Insert(file).ExecuteAsync();
return file.Id;
}
It does not hang calling the same method from a test console app.
The same logic also does not hang IIS Express when called using the corresponding synchronous method instead.
var id = CreateDocument("My Title");
string CreateDocument(string title)
{
var file = new GData.File { Title = title };
// This has no problem
file = Service.Files.Insert(file).Execute();
return file.Id;
}
Where should I look for the defect?
The defect is here:
var id = CreateDocument("My Title").Result;
As I explain on my blog, you should not block on async code.
Instead of Result, use await:
var id = await CreateDocument("My Title");
Related
I am getting data from a server via Rest API. But Whenever i am waiting for the client response the Methos is left by the Debugger and the Program start loading the GUI even though at this point there is no Data to Display. Im already stuck for a couple of days on it. How can i make the Code to wait for the Response? Iam already using Await
My Method to get The Data: (Client Call in Line 8)
public async Task<ObservableCollection<Datensatz>> getDataFromAzure()
{
string URL = URLForContent;
_client = new HttpClient();
_client.DefaultRequestHeaders.Add("ApiKey", PW);
var result1 = await _client.GetAsync(URL, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
if (result1.StatusCode == System.Net.HttpStatusCode.OK)
{
var result = await result1.Content.ReadAsStringAsync();
var ContentFromJson = JsonConvert.DeserializeObject<ObservableCollection<Datensatz>>(result);
string json = JsonConvert.SerializeObject(ContentFromJson, Formatting.Indented);
var filename = #"data.json";
var destinatioPath = Path.Combine(Android.App.Application.Context.GetExternalFilesDir(null).ToString(), filename);
File.WriteAllText(destinatioPath, json);
App.Database_Main.FillMainDBWithJsonEntrys();
return ContentFromJson;
}
return null;
}
You can use the Wait method of the Task. Such as
Task result = getDataFromAzure()
result.Wait();
You can also use the Thread.sleep(1000) to make the main thread sleep for a while. But this will reduce the function of the application because we don't know how long time the async method need and if the time if more than 5 seconds will cause the ANR.
When I create a database I want to initialize it with a ton of data.
I have the following initialization service.
// This needs to be a top-level method because it's run on a background isolate
DatabaseConnection _backgroundConnection() {
// construct the database. You can also wrap the VmDatabase in a "LazyDatabase" if you need to run
// work before the database opens.
final database = VmDatabase.memory();
return DatabaseConnection.fromExecutor(database);
}
Future<void> _initDatabase(Map<String, dynamic> args) async {
var moorIsolate = await MoorIsolate.spawn(_backgroundConnection);
var connection = await moorIsolate.connect();
var db = BillingDatabase.connect(connection);
_initBillingSpecialties(db, args["specialties"]);
}
Future<void> _initBillingSpecialties(BillingDatabase db, String specialtiesJson) async {
var json = jsonDecode(specialtiesJson);
var jsonSpecialties = json["specialties"] as List<dynamic>;
var specialities = jsonSpecialties.map((s) =>
DbSpecialtiesCompanion(name: Value(s["specialty_name"]),
mohNumber: Value(s["moh_specialty"]))).toList();
return db.specialtyDao.saveAllSpecialties(specialities);
}
#injectable
class InitDbService {
Future<void> initDatabase() async {
WidgetsFlutterBinding.ensureInitialized();
var specialties = await rootBundle.loadString("lib/assets/billing_specialties.json");
compute(_initDatabase, {"specialties": specialties});
//initDbSync(specialties);
}
Future<void> initDbSync(String specialtiesJson) async {
var json = jsonDecode(specialtiesJson);
var jsonSpecialties = json["specialties"] as List<dynamic>;
var specialities = jsonSpecialties.map((s) =>
DbSpecialtiesCompanion(name: Value(s["specialty_name"]),
mohNumber: Value(s["moh_specialty"]))).toList();
var dao = GetIt.instance.get<SpecialtyDao>();
return dao.saveAllSpecialties(specialities);
}
}
initDbSync runs and inserts just fine. While db.specialtyDao.saveAllSpecialties(specialities); never actually exectues any SQL. I have it printing log statements for the moment so I can see what it's doing.
Update: I found out that VmDatabase.memory(logStatements: true); was needed to see the SQL. I can see it printing the statements.
I'm running on a simulator so I can look at the raw db file. And there's nothing there. When I query in the app there's also nothing there.
So what's not really clear in the documentation is that VmDatabase.memory(); opens up a new database in memory. Not takes the database from memory.
You want to take your reference to the file that you pass in the constructor, and use
VmDatabase(File(dbFile));
then it will actually run on your sql.
I am using the Microsoft Cognitive Face API for implementing the Face Detection to Authenticate the person and login to the application.
For that, I am creating a PersonGroup and add the Person and then Face of Person. Train Person group and so on.
I want to implement it in the MVC Web Application. I have written the same code in MVC Web Application. But the API is not returning anything and just hanged at the Http request call.
So Do we need to get some different API Key for a Web application or Do we need to make any changes in Web.Config file to make a successful call?
I have tried the same code in the Console Application and WPF Application. There everything works perfectly fine.
public class HttpClientHelper
{
HttpClient httpClient = new HttpClient();
private const string subscriptionKey = "XXXXXXXXXXXXXXXXXXXXXXXXXX";
private const string faceEndpoint = "https://southeastasia.api.cognitive.microsoft.com/face/v1.0/";
public HttpClientHelper()
{
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
httpClient.BaseAddress = new Uri(faceEndpoint);
}
public async Task<T> GetAsync<T>(string url)
{
var response = await httpClient.GetAsync(url);
string contentString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(contentString);
}
}
public static async Task CreatePersonGroup(UserGroup userGroup)
{
bool isGroupExists = false;
PersonGroup personGroup;
try
{
HttpClientHelper httpClientHelper = new HttpClientHelper();
var response = httpClientHelper.GetAsync<PersonGroup>(string.Format("persongroups/{0}", userGroup.UserGroupId)).Result;
isGroupExists = true;
}
catch (APIErrorException ex)
{
if (ex.Body.Error.Code == "PersonGroupNotFound")
isGroupExists = false;
}
if (isGroupExists == false)
{
await faceClient.PersonGroup.CreateAsync(userGroup.UserGroupId, userGroup.Name);
}
}
I expect the same code must be working fine in Web Application also. As there is not a big logic in it. Just a simple API call.
private const string faceEndpoint =
"https://southeastasia.api.cognitive.microsoft.com/";
hopefully, it should work
I have been running into a very strange issue, and I am not even sure if this is an issue with my app or the web service I am calling.
I have a Web API Service with a Post method that accepts a complex parameter (it is my own custom object). In my Xamarin project I have some pretty straightforward code to call this service:
public async Task SubmitEReport(decimal amount, DateTime receivedDate,
byte[] image)
{
try
{
HttpClient client = new HttpClient();
var uri = new Uri("https://services.example.com/EPub/api/Expense/");
var eReport = new eReport()
{
UserName = "EMPLOYEE\" + Application.Current.Properties["username"].ToString(),
Cost = amount,
ReceivedDate= receivedDate,
ReceiptImageExtension = "jpg",
SubmittalDate = DateTime.Now,
Image = image
};
var json = JsonConvert.SerializeObject(eReport );
var content = new System.Net.Http.StringContent(json, Encoding.UTF8, "application/json");
content.Headers.Add("authorize-token", Application.Current.Properties["auth-token"] as string);
HttpResponseMessage response = null;
response = await client.PostAsync(uri, content);
var eResult = new EResult()
{
Success = response.IsSuccessStatusCode,
ErrorMessage = response.ReasonPhrase
};
return eResult ;
}
catch (Exception ex)
{
var errorResult = new eResult () { Success = false, ErrorMessage = ex.Message };
return errorResult;
}
}
The issue that I am having is that, when I test this on an Android the code works as expected: the service is called, the object passed over is not null and has the data in it. In short, the parameter binding works as expected. The same is not so on iOS: when I call the service using the app on an iPhone, I can see that it is reaching the service and the Post method, but the parameter binding is not working correctly as the object I am passing over is always null.
The issue is resolved. The problem was actually the size of the request. I discovered this in my Web Api service after examining the contents of the request object, and received an exception that the request length was exceeded. My solution was to increase the value of the property maxrequestlength in the web.config. This still does not explain why the request is so much larger in iOS than Android. Will follow up on this.
try to debug your code without using any async methods. async methods should work in general without any problems, but it's sometimes hard to comprehend how implemented logic actually behaves.
I am making a windows phone 8 application. Part of this application requires state to be saved. I am saving it as a string of Json. If I open the application, save some data, exit the application and the load it again, it hangs on either GetFolderAsync or OpenStreamForReadAsync. It does not happen every time, but once it starts hanging, I have to kill the whole emulator and make a new one to start the application again.
I have even tried just making an empty file with no data in it and the problem still persistes.
Below is the code I am using to save and load the data. It does not matter where I call the data load whether it be on application start or on the form load it still breaks.
private async Task SaveLists()
{
//XmlSerializer serializer = new XmlSerializer(typeof(ListHolder));
// Get the local folder.
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
// Create a new folder name DataFolder.
var dataFolder = await local.CreateFolderAsync("DataFolder",
CreationCollisionOption.OpenIfExists);
// Create a new file named DataFile.txt.
var file = await dataFolder.CreateFileAsync("Lists.json",
CreationCollisionOption.ReplaceExisting);
string json = JsonConvert.SerializeObject(Lists, Formatting.Indented);
byte[] fileBytes = System.Text.Encoding.UTF8.GetBytes(json.ToCharArray());
using (var s = await file.OpenStreamForWriteAsync())
{
s.Write(fileBytes, 0, fileBytes.Length);
}
}
private async Task LoadLists()
{
// Get the local folder.
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
if (local != null)
{
try
{
// Get the DataFolder folder.
var dataFolder = await local.GetFolderAsync("DataFolder");
// Get the file.
var files = dataFolder.GetFilesAsync();
var file = await dataFolder.OpenStreamForReadAsync("Lists.json");
string jsonString = "";
// Read the data.
using (StreamReader streamReader = new StreamReader(file))
{
jsonString = streamReader.ReadToEnd();
}
if (jsonString.Length > 0)
{
Lists = JsonConvert.DeserializeObject<List<ItemList>>(jsonString);
}
else
{
Lists = new List<ItemList>();
}
}
catch (Exception ex)
{
Lists = new List<ItemList>();
}
}
}
You are causing a deadlock by calling Result. I explain this deadlock on my blog and in a recent MSDN article. In summary, await will (by default) attempt to resume execution within a context (the current SynchronizationContext unless it is null, in which case it uses the current TaskScheduler).
In your case, the current SynchronizationContext is the UI context, which is only used by the UI thread. So when you block the UI thread by calling Result, the async method cannot schedule back to the UI thread to complete.