I have the following code that i can call from my universal app, and it works fine
// create our request with our data
var data = new JsonObject();
data.Add("param", JsonValue.CreateStringValue("abc"));
// convert to bytes
var dataAsBytes = System.Text.Encoding.UTF8.GetBytes(data.Stringify());
var httpRequest = HttpWebRequest.Create(URL + "Add");
httpRequest.Method = "POST";
httpRequest.ContentType = "application/json;charset=utf-8";
using (var requestStream = await httpRequest.GetRequestStreamAsync())
{
requestStream.Write(dataAsBytes, 0, dataAsBytes.Length);
}
var httpResponse = await httpRequest.GetResponseAsync();
using (var responseStream = httpResponse.GetResponseStream()) {
....
}
But this code seems to stop on var httpResponse = await httpRequest.GetResponseAsync() when i execute this from a backgroundTask?
To setup my background task, i have the following code.
var taskRegistered = false;
var taskName = "Upload Background Task";
var background = Windows.ApplicationModel.Background;
var iter = background.BackgroundTaskRegistration.allTasks.first();
while (iter.hasCurrent) {
var task = iter.current.value;
if (task.name === taskName) {
taskRegistered = true;
break;
}
iter.moveNext();
}
if (taskRegistered) {
successCallback(); // my javascript success callback
} else {
Windows.ApplicationModel.Background.BackgroundExecutionManager.requestAccessAsync().then(function () {
var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
builder.name = taskName;
builder.taskEntryPoint = "CordovaApp.Library.UploadTask";
builder.setTrigger(new Windows.ApplicationModel.Background.TimeTrigger(15, false));
builder.addCondition(new Windows.ApplicationModel.Background.SystemCondition(Windows.ApplicationModel.Background.SystemConditionType.internetAvailable));
return builder.register();
}).done(function () {
successCallback();
}, function (err) {
errorCallback(err);
});
}
Why is this not working? If i ran the task manually using visual studio it fails over on this line and it fails over on this line if i let the backgroundTask run itself after 15 minutes?
Problem solved.
I added the async keyword to my backgroundTask Run method so i could call my async method.
Instead of this, i removed the async keywork from my background Run method, and called the async code using
var result = Task.Run(async() => {
return myAsyncMethod();
}).Result;
Now all working
Related
Im trying to have Azure function that is HttpTrigger and after she is triggered she will subscribe to EventGrid, send POST request(that will eventually send data to EventGrid) and function will check if correct data were posted.
public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
var serviceProvider = new ServiceCollection().AddScoped<INotificationService, NotificationService>().BuildServiceProvider();
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
var generalCommand = converter.DeserializeObject<GeneralDto>(requestBody);
List<CommandDto> rawCommands = GetRaw(generalCommand);
//EventGrid
var notificationService = serviceProvider.GetService<INotificationService>();
notificationService?.DisplayNotificationsAsync(rawCommands, requestBody).GetAwaiter().GetResult();
var msg = SendMessage(requestBody);
var response = await ResponseAsync(notificationService);
if (response.Equals("Yes"))
{
return new OkObjectResult(response);
}
else
{
return new NotFoundObjectResult(response);
}
}
And function handling EventGrid
public async Task DisplayNotificationsAsync(List<CommandDto> rawCommands, string requestBody)
{
// Configuration
string? relayNamespace = "";
string? connectionNameRequest = "";
string? keyName = "";
string? key = "";
var messagePairs = new Dictionary<string, NotificationPair>();
// Display notifications
var cts = new CancellationTokenSource();
var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(keyName, key);
var listenerRequest = new HybridConnectionListener(new Uri(string.Format("sb://{0}/{1}", relayNamespace, connectionNameRequest)), tokenProvider);
listenerRequest.RequestHandler = async (context) =>
{
using (var streamReader = new StreamReader(context.Request.InputStream))
{
var content = await streamReader.ReadToEndAsync();
try
{
var gridEvents = JsonSerializer.Deserialize<List<EventGridEvent>>(content, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
foreach (var currentGridEvent in gridEvents)
{
var request = currentGridEvent.Data.ToString();
PayloadDto gridPayload = converter.DeserializeObject<PayloadDto>(request);
if (gridPayload.device_id.Equals("IRC_VIL_T2201"))
{
resultNew = Idk(rawCommands, gridPayload);
context.Response.Close();
await listenerRequest.CloseAsync();
break;
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error occurred:{ex.Message}");
}
}
};
await listenerRequest.OpenAsync();
}
When I find correct data on grid I will close listenerRequest but in case I don't(after not finding it in 10seconds) I will return in Run function. But from my understanding listenerRequest will be still running in my background and when I trigger function again I will run 2 at the same time. Is there a way to close or dispose of it in Run function or I can do that only in listener itself.
I don't understand why the response comes only if I use CompleteAsync().
using var call = _apiClient.GetToken(headers: _threadContext.Metadata, deadline: DateTime.UtcNow.AddSeconds(5));
var keyReq = new GetTokenRequest()
{
Key = publicKey
};
var readTask = Task.Run(async () =>
{
await foreach(var message in call.ResponseStream.ReadAllAsync())
{
if (message.Challenge != null)
{
var challenge = message.Challenge.ToByteArray();
var signature = await VerifySignature(challenge);
var signReq = new GetTokenRequest
{
Signature = ByteString.CopyFrom(signature)
};
await call.RequestStream.WriteAsync(signReq);
await call.RequestStream.CompleteAsync();
}
else if (message.Token != null)
{
token = message.Token;
}
}
});
await call.RequestStream.WriteAsync(keyReq);
await readTask;
If I change the end with this, I receive messages but in the response the next WriteAsync fails because the stream is closed.
await call.RequestStream.WriteAsync(keyReq);
await call.RequestStream.CompleteAsync();
await readTask;
And if I doesn't complete the request, response message never comes.
Any idea ?
Note: the server is in go.
This code doesn't work with Grpc.Net.Client.Web only. With classic SocketHttpHandler it's ok. Problem is solved. thanks.
I am trying to scrape Taobao website with Puppeteer Sharp.
Here is the code:
private static async Task SurfWithPuppeteer()
{
var options = new LaunchOptions{ Devtools = true };
Console.WriteLine("Downloading chromium");
await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
Console.WriteLine("Navigating to Hacker News");
using (var browser = await Puppeteer.LaunchAsync(options))
using (var page = await browser.NewPageAsync())
{
page.DefaultNavigationTimeout = 50000;
await page.GoToAsync("https://login.tmall.com/?spm=875.7931836/B.a2226mz.1.66144265pHmhvt&redirectURL=https%3A%2F%2Fwww.tmall.com%2F");
var frameElement= await page.QuerySelectorAsync("#J_loginIframe");
//var frameElement = await page.QuerySelectorAsync("div#mallPage iframe");
//var frameElement = await page.Frames.Select(f=>f.QuerySelectorAsync("#J_loginIframe")).FirstOrDefault();
var frame = await frameElement.ContentFrameAsync();
var frameContent = await frame.GetContentAsync();
await frame.TypeAsync("#TPL_username_1", "compuwizpiyu");
await frame.TypeAsync("#TPL_password_1", "Priyanka24$");
var btn = await frame.QuerySelectorAsync("#J_SubmitStatic");
await btn.ClickAsync();
var res= await frame.WaitForNavigationAsync();
var t= await frame.GetContentAsync();
//var url = page.Url;
}
}
But I am unable to navigate to the frame that has the login form (frame has no name, only src and id).
I have tried to check the frames with page.Frames, but since the iframes have no name, difficult to find the correct frame I am looking for.
I have tried couple of other options too like :
var frameElement = await page.QuerySelectorAsync("div#mallPage iframe");
var frameElement = await page.Frames.Select(f=>f.QuerySelectorAsync("#J_loginIframe")).FirstOrDefault()
But still unable to get the intended frame. Please help me with what is wrong here.
This may be due to CORS.
Try the following code.
var options = new LaunchOptions
{
Devtools = true,
Args = new[]
{
"--disable-web-security",
"--disable-features=IsolateOrigins,site-per-process",
},
};
I want to send a http post that can take a couple of seconds to reply without freezing my UI, currently this code just hangs my application when the method is callled.
What am I doing wrong and how do i achieve my goal?
private async Task<string> DoHttpClientPost(string method, IDictionary<string, object> args = null)
{
{
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
handler.Proxy = null;
HttpResponseMessage response;
using (var myHttpClient = new HttpClient(handler))
{
myHttpClient.DefaultRequestHeaders.ExpectContinue = false;
myHttpClient.DefaultRequestHeaders.Add("Accept-Charset", "ISO-8859-1,utf-8");
myHttpClient.DefaultRequestHeaders.Add(APPKEY_HEADER, CustomHeaders.GetValues(APPKEY_HEADER));
myHttpClient.DefaultRequestHeaders.Add(SESSION_TOKEN_HEADER, CustomHeaders.GetValues(SESSION_TOKEN_HEADER));
myHttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json-rpc"));
var call = new JsonRequest { Method = method, Id = 1, Params = args };
var jsonObject = JsonConvert.Serialize<JsonRequest>(call);
var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json-rpc");
response = await myHttpClient.PostAsync(new Uri(EndPoint), content);
}
Console.WriteLine("\nCalling: " + method + " With args: " + JsonConvert.Serialize<IDictionary<string, object>>(args));
string jsonResponse = await response.Content.ReadAsStringAsync();
return jsonResponse;
}
}
public T Invoke<T>(string method, IDictionary<string, object> args = null)
{
if (method == null)
throw new ArgumentNullException("method");
if (method.Length == 0)
throw new ArgumentException(null, "method");
var jsonString = DoHttpClientPost(method, args).Result;
var jsonResult = JsonConvert.Deserialize<JsonResponse<T>>(jsonString);
return jsonResult.Result;
}
var jsonString = DoHttpClientPost(method, args).Result;
This is your culprit. If you call .Result on a Task from the UI thread it will hang.
You'll need to async all the way up - so Invoke should be async and return a Task<T> and await the DoHttpClientPost call, the caller should be async etc. etc. etc.
You have to make two changes
Modify this line from
response = await myHttpClient.PostAsync(new Uri(EndPoint), content);
to
response = await myHttpClient.PostAsync(new Uri(EndPoint), content).ConfigureAwait(false);
And looks like your intention is to wait for the post call to complete and return the results, so modify this line from
var jsonString = DoHttpClientPost(method, args).Result;
to
var jsonStringTask = DoHttpClientPost(method, args);
jsonStringTask.Wait(); //wait for http post call to complete.
var jsonString = jsonStringTask.Result;
I have a functionality of search users. I have provided a textview and on that textview changed method I'm firing a method to get data from web server. But I'm facing problem when user types letter, because all the api hits done in async task. Service should be hit after 100 milli-sec of wait, means if user types a letter "a" then doesn't type for 100 milli-sec then We have to hit the service. But if user types "a" then "b" then "c", so one service should be hit for "abc", not for all.
I followed the official link, but it doesn't help me
https://msdn.microsoft.com/en-us/library/jj155759.aspx
So basically here is my code
textview.TextChange+= (sender,e) =>{
CancellationTokenSource cts = new CancellationTokenSource();
await Task.Delay(500);
// here some where I have to pass cancel token
var lst = await APIClient.Instance.GetUserSearch("/user/get?searchTerm=" + newText, "application/json",cts);
if (lst != null && lst.Count > 0){
lstSearch.AddRange(lst);
}
}
Here is my method to GetUser
public async Task<JResponse> GetUserSearch<JResponse>(string uri, string contentType,CancellationToken cts)
{
try
{
Console.Error.WriteLine("{0}", RestServiceBaseAddress + uri);
string url = string.Format("{0}{1}", RestServiceBaseAddress, uri);
var request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = contentType;
if (Utility.CurrentUser != null && !string.IsNullOrWhiteSpace(Utility.CurrentUser.AuthToken))
{
request.Headers.Add("api_key", Utility.CurrentUser.AuthToken);
}
request.Method = "POST";
var payload = body.ToString();
request.ContentLength = payload.Length;
byte[] byteArray = Encoding.UTF8.GetBytes(body.ToString());
request.ContentLength = byteArray.Length;
using (var stream = await request.GetRequestStreamAsync())
{
stream.Write(byteArray, 0, byteArray.Length);
stream.Close();
}
using (var webResponse = await request.GetResponseAsync())
{
var response = (HttpWebResponse)webResponse;
using (var reader1 = new StreamReader(response.GetResponseStream()))
{
Console.WriteLine("Finished : {0}", uri);
var responseStr = reader1.ReadToEnd();
var responseObj = JsonConvert.DeserializeObject<JResponse>(
responseStr,
new JsonSerializerSettings()
{
MissingMemberHandling = MissingMemberHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
});
return responseObj;
}
}
}
catch (System.Exception ex)
{
Utility.ExceptionHandler("APIClient", "ProcessRequestAsync", ex);
}
return default(JResponse);
}
In your example, you are creating a CancellationTokenSource - you need to hold a reference to it, so that the next time the handler is invoked, the previous search can be cancelled. Here is an example console app that you should be able to run, but the important piece is in the handler.
private CancellationTokenSource _cts;
private async void TextChangedHandler(string text) // async void only for event handlers
{
try
{
_cts?.Cancel(); // cancel previous search
}
catch (ObjectDisposedException) // in case previous search completed
{
}
using (_cts = new CancellationTokenSource())
{
try
{
await Task.Delay(TimeSpan.FromSeconds(1), _cts.Token); // buffer
var users = await _userService.SearchUsersAsync(text, _cts.Token);
Console.WriteLine($"Got users with IDs: {string.Join(", ", users)}");
}
catch (TaskCanceledException) // if the operation is cancelled, do nothing
{
}
}
}
Be sure to pass the CancellationToken into all of the async methods, including those that perform the web request, this way you signal the cancellation right down to the lowest level.
Try to use timer. First time then you change text - you create it. Then you change text after that - you restart timer. If you don't change text for 700 milliseconds - timer will fire PerformeSearch method. Use Timeout.Infinite for timer period parameter to prevent it from restarting.
textview.TextChange += (sender,e) =>
{
if (_fieldChangeTimer == null)
_fieldChangeTimer = new Timer(delegate
{
PerformeSearch();
}, null, 700, Timeout.Infinite);
else
{
_fieldChangeTimer.Change(700, Timeout.Infinite);
}
};
Instantiate the CancellationTokenSource.
cts = new CancellationTokenSource(); Example method
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}