bring variable declared inside async task to different class - c#

I have pulled some information using newtonsoft.json and HttpClient:
public class Main {
static async Task Main() {
using(var client = new HttpClient() {
url = "webapilink goes here";
var response = await client.GetStringAsync(url);
apiStuff(the class i used to match the JSON format) variableName =
JsonConvert.DeserializeObject<apiStuff>(response);
}
}
}
I want to get the variable "variableName" to a seperate class, and for the life of me, cannot figure it out. I get an error when trying to use it anywhere outside of the HttpClient part.

As written, your async method would return void if it was not async. But it could be rewritten to return an instance of apiStuff, so that other methods (and other classes) could get that instance of apiStuff and use it:
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
public class MainClass
{
public static async Task<apiStuff> Main()
{
using (var client = new HttpClient())
{
string url = "webapilink goes here";
var response = await client.GetStringAsync(url);
apiStuff variableName =
JsonConvert.DeserializeObject<apiStuff>(response);
return variableName;
}
}
}
public class SecondClass
{
public static async Task GetApiStuff()
{
apiStuff variableName = await MainClass.Main();
// do more work with variableName
}
}
public class apiStuff { /* defined elsewhere */ }
If this wasn't what you were asking about, please clarify in the original question. (And I assume the method is not really named Main - could be confusing.)

Related

Make ProcessCmdKey async await - C# [duplicate]

I am overriding a method in a base class library. However, inside my overridden implementation I am using the new HttpClient which is all based on async methods. I therefore have to mark my method as async, which means that I need to change the return parameter of the method from string to Task. The compiler however gives an error: "The return type must be 'string' to match overridden member ...."
public class BaseClass
{
public virtual string GetName()
{
...
}
}
public class MyClass : BaseClass
{
public override async Task<string> GetName()
{
HttpClient httpClient = new HttpClient();
var response = await httpClient.GetAsync("");
if (response.IsSuccessStatusCode)
{
var responseContent = response.Content;
return await responseContent.ReadAsStringAsync();
}
return null;
}
}
Of course the obvious solution would be to change the return type of GetName() in BaseClass to Task<string>, but I have no control over BaseClass as it is an external library;
My current solution is to use the HttpClient classes in a synchronous fashion, i.e. change MyClass as follows:
public class MyClass : BaseClass
{
public override string GetName()
{
HttpClient httpClient = new HttpClient();
var response = httpClient.GetAsync("");
if (response.Result.IsSuccessStatusCode)
{
var responseContent = response.Result.Content;
return responseContent.ReadAsStringAsync()
.Result;
}
return null;
}
}
Is there any other way to do this?
Unfortunately there isn't a good solution here. There is no way to override a non-async method with an async one. I think your best bet is to have an async non-override method and call into that from the non-async one:
public class MyClass : BaseClass
{
public override string GetName()
{
return GetNameAsync().Value;
}
public async Task<string> GetNameAsync()
{
...
}
}
Note that this can cause problems though. If the original code didn't expect for any async code to be executing introducing this pattern could break expectations. I would avoid it if possible.
Luckily the ReadAsStringAsync().Result is not causing a deadlock since it is likely to have ConfigureAwait(false) within.
To prevent a deadlock, you could use one of the following methods:
public static T GetResult<T>(Func<Task<T>> func)
{
var httpContext = HttpContext.Context;
var proxyTask = Task.Run(() =>
{
HttpContext.Context = httpContext;
return func();
});
return proxyTask.Result;
}
// or
public static T GetResult<T>(Func<Task<T>> func)
{
var syncContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
var task = func();
SynchronizationContext.SetSynchronizationContext(syncContext);
return task.Result;
}
This way you would call
public override string GetName()
{
...
return GetResult(() => responseContent.ReadAsStringAsync());
...
}
The former has a performance overhead by spawning a new thread, while the latter suffers from breaking SynchronizationContext flow, which makes any context bound to it unavailable in the task being called, e.g. HttpContext.Current.
I've also had this problem, and the solution was using an interface, in which 'async' isn't part of the method's signature.
public abstract class Base : IInvokable {
/* Other properties ... */
public virtual async Task Invoke() {
/*...*/
}
}
public interface IInvokable {
Task Invoke();
}
public class Derived
{
public override async Task Invoke() {
// Your code here
}
}

Triggering DynamicData cache update using Reactive Subject

As a caveat I'm a novice with Rx (2 weeks) and have been experimenting with using Rx, RxUI and Roland Pheasant's DynamicData.
I have a service that initially loads data from local persistence and then, upon some user (or system) instruction will contact the server (TriggerServer in the example) to get additional or replacement data. The solution I've come up with uses a Subject and I've come across many a site discussing the pros/cons of using them. Although I understand the basics of hot/cold it's all based on reading rather than real world.
So, using the below as a simplified version, is this 'right' way of going about this problem or is there something I haven't properly understood somewhere?
NB: I'm not sure how important it is, but the actual code is taken from a Xamarin.Forms app, that uses RxUI, the user input being a ReactiveCommand.
Example:
using DynamicData;
using System;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
public class MyService : IDisposable
{
private CompositeDisposable _cleanup;
private Subject<Unit> _serverSubject = new Subject<Unit>();
public MyService()
{
var data = Initialise().Publish();
AllData = data.AsObservableCache();
_cleanup = new CompositeDisposable(AllData, data.Connect());
}
public IObservableCache<MyData, Guid> AllData { get; }
public void TriggerServer()
{
// This is what I'm not sure about...
_serverSubject.OnNext(Unit.Default);
}
private IObservable<IChangeSet<MyData, Guid>> Initialise()
{
return ObservableChangeSet.Create<MyData, Guid>(async cache =>
{
// inital load - is this okay?
cache.AddOrUpdate(await LoadLocalData());
// is this a valid way of doing this?
var sync = _serverSubject.Select(_ => GetDataFromServer())
.Subscribe(async task =>
{
var data = await task.ConfigureAwait(false);
cache.AddOrUpdate(data);
});
return new CompositeDisposable(sync);
}, d=> d.Id);
}
private IObservable<MyData> LoadLocalData()
{
return Observable.Timer(TimeSpan.FromSeconds(3)).Select(_ => new MyData("localdata"));
}
private async Task<MyData> GetDataFromServer()
{
await Task.Delay(2000).ConfigureAwait(true);
return new MyData("serverdata");
}
public void Dispose()
{
_cleanup?.Dispose();
}
}
public class MyData
{
public MyData(string value)
{
Value = value;
}
public Guid Id { get; } = Guid.NewGuid();
public string Value { get; set; }
}
And a simple Console app to run:
public static class TestProgram
{
public static void Main()
{
var service = new MyService();
service.AllData.Connect()
.Bind(out var myData)
.Subscribe(_=> Console.WriteLine("data in"), ()=> Console.WriteLine("COMPLETE"));
while (Continue())
{
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine($"Triggering Server Call, current data is: {string.Join(", ", myData.Select(x=> x.Value))}");
service.TriggerServer();
}
}
private static bool Continue()
{
Console.WriteLine("Press any key to call server, x to exit");
var key = Console.ReadKey();
return key.Key != ConsoleKey.X;
}
}
Looks very good for first try with Rx
I would suggest few changes:
1) Remove the Initialize() call from the constructor and make it a public method - helps a lot with unit tests and now you can await it if you need to
public static void Main()
{
var service = new MyService();
service.Initialize();
2) Add Throttle to you trigger - this fixes parallel calls to the server returning the same results
3) Don't do anything that can throw in Subscribe, use Do instead:
var sync = _serverSubject
.Throttle(Timespan.FromSeconds(0.5), RxApp.TaskPoolScheduler) // you can pass a scheduler via arguments, or use TestScheduler in unit tests to make time pass faster
.Do(async _ =>
{
var data = await GetDataFromServer().ConfigureAwait(false); // I just think this is more readable, your way was also correct
cache.AddOrUpdate(data);
})
// .Retry(); // or anything alese to handle failures
.Subscribe();
I'm putting what I've come to as my solution just in case there's others that find this while they're wandering the internets.
I ended up removing the Subjects all together and chaining together several SourceCache, so when one changed it pushed into the other and so on. I've removed some code for brevity:
public class MyService : IDisposable
{
private SourceCache<MyData, Guid> _localCache = new SourceCache<MyData, Guid>(x=> x.Id);
private SourceCache<MyData, Guid> _serverCache = new SourceCache<MyData, Guid>(x=> x.Id);
public MyService()
{
var localdata = _localCache.Connect();
var serverdata = _serverCache.Connect();
var alldata = localdata.Merge(serverdata);
AllData = alldata.AsObservableCache();
}
public IObservableCache<MyData, Guid> AllData { get; }
public IObservable<Unit> TriggerLocal()
{
return LoadLocalAsync().ToObservable();
}
public IObservable<Unit> TriggerServer()
{
return LoadServerAsync().ToObservable();
}
}
EDIT: I've changed this again to remove any chaining of caches - I just manage the one cache internally. Lesson is not to post too early.

Xamarin.Forms with Net.Http [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Guys and ladies can you tell me what a problem in this code or in which way I can change Xamarin settings for successful code execution? Xam.Plugin.Connectivity.CrossConnectivity says:"Device is connected to the internet", but in any realization DownloadCountriesListAsync() stucks (UWP doesnt works, Android with selected INTERNET parameter in manifest too). This code is working in c# console app.
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace radacodeTestApp
{
public class ListsDownloader
{
public List<Country> Countries { get; private set; }
public ListsDownloader()
{
Countries = new List<Country>();
var task = DownloadCountriesListAsync();
}
public async Task<bool> DownloadCountriesListAsync()
{
try
{
var vkjsonResponse = await GetResponse(#"https://api.vk.com/api.php?oauth=1&method=database.getCountries&need_all=1&v=5.60");
var jsonObject = JObject.Parse(vkjsonResponse);
foreach (var jO in jsonObject["response"]["items"])
Countries.Add(JsonConvert.DeserializeObject<Country>(jO.ToString()));
}
catch (OperationCanceledException)
{
return false;
}
return true;
}
public async Task<string> GetResponse(string url)
{
using (var httpClient = new HttpClient())
return await httpClient.GetStringAsync(url);
}
}
public class Country
{
public int Cid { get; set; }
public string Title { get; set; }
public override string ToString()
{
return Title;
}
}
}
Call the DownloadCountriesListAsync method from a background thread; your code is currently calling DownloadCountriesListAsync from the Main Thread (also known as the UIThread), which can cause the UIThread to freeze.
I've updated your code below to show how to call the DownloadCountriesListAsync method from a background thread.
Async/Await is a tricky beast. Marking a method async doesn't mean it will automatically run on a background thread; it just means that the async method has the capability to yield its process to its parent thread until its process is complete. #Clancey did a great presentation on Async/Await at the most recent Xamarin conference. I highly recommend it!
https://www.youtube.com/watch?v=jgxJbshvCXQ
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace radacodeTestApp
{
public class ListsDownloader
{
public List<Country> Countries { get; private set; }
public ListsDownloader()
{
Countries = new List<Country>();
Task.Run(async () => await DownloadCountriesListAsync());
}
public async Task<bool> DownloadCountriesListAsync()
{
try
{
var vkjsonResponse = await GetResponse(#"https://api.vk.com/api.php?oauth=1&method=database.getCountries&need_all=1&v=5.60");
var jsonObject = JObject.Parse(vkjsonResponse);
foreach (var jO in jsonObject["response"]["items"])
Countries.Add(JsonConvert.DeserializeObject<Country>(jO.ToString()));
}
catch (OperationCanceledException)
{
return false;
}
return true;
}
public async Task<string> GetResponse(string url)
{
using (var httpClient = new HttpClient())
return await httpClient.GetStringAsync(url);
}
}
public class Country
{
public int Cid { get; set; }
public string Title { get; set; }
public override string ToString()
{
return Title;
}
}
}

How to fix the error : Cannot call the requested method (GetBasicPropertiesAsync). A previous call to this method is pending

I am using this GetBasicPropertiesAsync method to fetch file properties one by one in a loop.
But I land up with this error:
WinRT Information : Cannot call the requested method
(GetBasicPropertiesAsync). A previous call to this method is pending
and must return before the method can be called again.
My main function has the following code to enumerate all files and folders from the pictures library.
List<BaseStorage> listOfFiles = new List<BaseStorage>();
IReadOnlyList<StorageFolder> foldersList = await curFolder.MCMFolder.GetFoldersAsync();
// For each folder found ...
foreach (StorageFolder folder in foldersList)
{
listOfFiles.Add(new Folder(folder, parents));
}
// Enumerate all files in the Pictures library.
IReadOnlyList<StorageFile> fileList = await curFolder.MCMFolder.GetFilesAsync();
// For each file found ...
foreach (StorageFile file in fileList)
{
listOfFiles.Add(new Document(file));
}
return listOfFiles;
Folder and Document class inherits BaseStorage Class.
class BaseStorage
{
public BaseStorage(IStorageItem storageItem)
{
this.Name = storageItem.Name;
this.CreationDate = storageItem.DateCreated.ToString();
setModifiedDateAndOwner(storageItem);
}
private async void setModifiedDateAndOwner(IStorageItem storageItem)
{
// await Task.Delay(500);
Windows.Foundation.IAsyncOperation<BasicProperties> basicPropsTask = storageItem.GetBasicPropertiesAsync();
BasicProperties _basicProps = await storageItem.GetBasicPropertiesAsync();
this.ModifiedDate = _basicProps.DateModified.ToString();
string fileOwnerProperty = "System.FileOwner";
List<string> propertiesToFetch = new List<string>();
propertiesToFetch.Add(fileOwnerProperty);
IDictionary<string, object> props = await _basicProps.RetrievePropertiesAsync(propertiesToFetch);
this.Owner = props[fileOwnerProperty].ToString();
return;
}
}
class Document
{
public Document()
{
setSize();
}
private async void setSize()
{
BasicProperties _basicProps = await file.GetBasicPropertiesAsync();
ulong fileSizeInBytes = _basicProps.Size;
}
}
The problem here is the method setModifiedDateAndOwner has a call to GetBasicPropertiesAsync method. Even before this method is complete, the
child class - Document calls setSize method which again has a call to GetBasicPropertiesAsync method.
This causes the exception to occur. However the behaviour is not very consistent due to threads.
How do I make sure that the method setModifiedDateAndOwner in the Base class is complete before calling the methods in its child class.
Constructors can't be async, but there are some ways to work around that.
Since you're using inheritance, you can't use the Factory Pattern from the above article directly, but you can combine the Factory Pattern for the derived class with a version of the The Asynchronous Initialization Pattern for the base class:
class BaseStorage
{
protected BaseStorage(IStorageItem storageItem)
{
this.Name = storageItem.Name;
this.CreationDate = storageItem.DateCreated.ToString();
Initialization = setModifiedDateAndOwner(storageItem);
}
protected Task Initialization { get; private set; }
private async Task setModifiedDateAndOwner(IStorageItem storageItem)
{
…
}
}
class Document : BaseStorage
{
private Document(IStorageFile storageFile)
: base(storageFile)
{ }
public static async Task<Document> Create(IStorageFile storageFile)
{
var result = new Document(storageFile);
await result.Initialization;
return result;
}
}
This way, you have to be careful when implementing Document and other classes that inherit from BaseStorage, but you can only use those classes correctly (you have to await the Task to get the created instance).

C# IDisposable object for entire class

The project that I'm working on at the moment uses an IDisposable object in every method in a class. It has started getting tedious re-typing the using block at the start of every method, and was wondering if there was a way to specify a disposable variable for use in every method of the class?
public static class ResourceItemRepository
{
public static ResourceItem GetById(int id)
{
using (var db = DataContextFactory.Create<TestDataContext>())
{
// Code goes here...
}
}
public static List<ResourceItem> GetInCateogry(int catId)
{
using (var db = DataContextFactory.Create<TestDataContext>())
{
// Code goes here...
}
}
public static ResourceItem.Type GetType(int id)
{
using (var db = DataContextFactory.Create<TestDataContext>())
{
// Code goes here...
}
}
}
No, there's nothing particularly geared towards this. You could write:
public static ResourceItem GetById(int id)
{
WithDataContext(db =>
{
// Code goes here...
});
}
// Other methods here, all using WithDataContext
// Now the only method with a using statement:
private static T WithDataContext<T>(Func<TestDataContext, T> function)
{
using (var db = DataContextFactory.Create<TestDataContext>())
{
return function(db);
}
}
I'm not sure that it would be particularly beneficial though.
(Note that I've had to change it from Action<TestDataContext> in my original version to Func<TestDataContext, T> as you want to be able to return values from your methods.)
Frankly, i'd keep the verbose code, but using a snippet instead of typing it all each time.
Either create your own snippet with a special tool or use text-replacement tools like Texter
Maybe a simple refactoring is the best that you can do without resorting to something like PostSharp:
public static class ResourceItemRepository {
public static ResourceItem GetById(int id) {
using (var db = CreateDataContext()) {
// Code goes here...
}
}
public static List<ResourceItem> GetInCateogry(int catId) {
using (var db = CreateDataContext()) {
// Code goes here...
}
}
public static ResourceItem.Type GetType(int id) {
using (var db = CreateDataContext()) {
// Code goes here...
}
}
private static TestDataContext CreateDataContext() {
return DataContextFactory.Create<TestDataContext>();
}
}

Categories

Resources