I have this class with two public async methods, which also calls some private methods that are async.
Here's the class:
public class AggregatedDataService
{
public async Task<OrganizationAggregatedInfo> GetOrganizationAggregatedInfo(int organizationId)
{
var organization = await GetOrganization(organizationId);
var organizationContact = await GetOrganizationContact(organization.ID);
var associations = await GetOrganizationAssociations(organization.ID);
//await Task.WhenAll(organizationContact, associations);
return new OrganizationAggregatedInfo(organization.Name, organization.Address, organizationContact,
associations);
}
public async Task<SchoolAggregatedInfo> GetSchoolAggreagtedInfo(int schoolId)
{
if(schoolId < 1)
return null;
var school = await GetSchool(schoolId);
if (school == null)
{
return null;
}
var getSchoolAddressTask = GetSchoolAddress(schoolId);
var getMemberSchoolsTask = GetMemberSchools(schoolId);
var getSchoolCurriculumTask = GetSchoolCurriculum(schoolId);
var getSchoolFacilitiesTask = GetSchoolFacilities(schoolId);
var getSchoolAssociationsTask = GetSchoolAssociations(schoolId);
var getSchoolAcreditationsTask = GetSchoolAcreditations(schoolId);
var getGovernanceStructureTask = GetGovernanceStructure(schoolId);
await Task.WhenAll(getSchoolAddressTask, getMemberSchoolsTask, getSchoolCurriculumTask,
getSchoolFacilitiesTask, getSchoolAssociationsTask, getSchoolAcreditationsTask,
getGovernanceStructureTask);
var schoolAddress = getSchoolAddressTask.Result;
var memberSchools = getMemberSchoolsTask.Result;
var teacherInfo = await GetTeacherInformation(schoolAddress.SchoolID);
var curriculum = getSchoolCurriculumTask.Result;
var facilities = getSchoolFacilitiesTask.Result;
var associations = getSchoolAssociationsTask.Result;
var accreditations = getSchoolAcreditationsTask.Result;
var studentInfo = await GetStudentInformation(schoolAddress.SchoolID);
var governanceStructure = getGovernanceStructureTask.Result;
SchoolContactReadView contact = null;
if (schoolAddress != null)//TODO: consider using null propagation
{
if (schoolAddress.SchoolContact != null)
contact = SchoolContactReadView.ShowSchoolContactView(schoolAddress.SchoolContact);
}
var schoolAggregateInfo = new SchoolAggregatedInfo
{
Name = school.Name,
Address = school.Address,
MemberSchoolsCount = memberSchools.Count(),
GovernanceStructure = governanceStructure,
Accreditations = accreditations.ToList(),
Associations = associations.ToList(),
Contact = contact,
Curriculum = curriculum,
Facilities = facilities.ToList()
};
return schoolAggregateInfo;
}
private async Task<List<OrganizationAssociationReadView>> GetOrganizationAssociations(int organizationId)
{
HttpResponseMessage response = await client.GetAsync("api/organization/associations/" + organizationId);
if (response.StatusCode == HttpStatusCode.OK)
{
var contentResult = await response.Content.ReadAsAsync<List<OrganizationAssociation>>();
associations = contentResult.Select(OrganizationAssociationReadView.MapFrom).ToList();
}
else
{
_log.Error("API Error Reason: " + response.ReasonPhrase);
}
}
private async Task<OrganizationContactReadView> GetOrganizationContact(int organizationId)
{
HttpResponseMessage response = await client.GetAsync("api/organization/contact/" + organizationId);
if (response.StatusCode == HttpStatusCode.OK)
{
var contentResult = await response.Content.ReadAsAsync<OrganizationContact>();
var organizationContactReadView = OrganizationContactReadView.MapFrom(contentResult);
organizationContact = organizationContactReadView;
}
else
{
_log.Error("API Error Reason: " + response.ReasonPhrase);
}
}
private async Task<OrganizationReadView> GetOrganization(int organizationId)
{
same as the other other methods....
}
private async Task<GovernanceStructureReadView> GetGovernanceStructure(int schoolId)
{
....
}
private async Task<IEnumerable<AccreditationReadView>> GetSchoolAcreditations(int schoolId)
{
....
}
.... all other method ....
}
and I also consume this method e.g
var obj = await GetSchoolAggreagtedInfo(21).ConfigureAwait(false);
I feel like I have too much async methods and which I'm afraid may cause more harm than good.
Is there a better way of doing all this async stuff (maybe a pattern), or is the code OK?
Related
my problem is the following: I just want to run x requests at the same time depending on the user.
Well, it seems to work fine when the MaxConcurrentDownloads variable is equal to 1, but when I increase it, say 10: I have to wait for the 10taches to finish for it to execute so that Console.WriteLine as to write, when it's supposed to run asynchronously, right?
Can you help me? Here is a minimalist version of my "problem" (Also I want to specify that I have no compiler or syntax errors)
main.c
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace test_client
{
class Program
{
private static client cli = new client();
private static readonly string PATH = #Directory.GetCurrentDirectory();
private static int concurrency = 100;
private static async Task<bool> MakeJOB(int pos)
{
return await cli.NewRequest<bool>((HttpClient client)=>
{
try
{
HttpClientHandler handler = null;
if (cli.handler != null)
handler = cli.GethandlerIndexed(pos);
client = new HttpClient(handler);
cli.AssignDefaultHeaders(client);
using (HttpResponseMessage response = client.GetAsync("https://api.my-ip.io/ip.txt").Result)
using (HttpContent content = response.Content)
Console.WriteLine(content.ReadAsStringAsync().Result + " / " + Task.CurrentId);
return true;
}
catch { /* exception .. */ return false; }
});
}
static void Main(string[] args)
{
ServicePointManager.DefaultConnectionLimit = 100;
MainAsync(args).GetAwaiter().GetResult();
Console.ReadLine();
}
static async Task MainAsync(string[] args)
{
cli.SetConcurrentDownloads(concurrency);
var t = new Task[concurrency];
int pos = 0;
for (int i = 0; i < t.Length; i++, pos++)
t[i] = MakeJOB(pos++);
await Task.WhenAll(t);
}
}
}
client.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Http;
using System.Collections.Concurrent;
using System.Threading;
namespace test_client
{
public class client
{
private readonly ConcurrentDictionary<string, HttpClient> Clients;
public SemaphoreSlim Locker;
private CancellationTokenSource TokenSource = new CancellationTokenSource();
public HttpClientHandler[] handler { get; set; }
public string[] address { get; set; }
public string[] port { get; set; }
public string[] username { get; set; }
public string[] password { get; set; }
public int MaxConcurrentDownloads { get; set; }
private void initializeHandler(string address = "", string port = "", string user = "", string pass = "")
{
initializeHandler(new string[] { string.Concat(address, ":", port, ":", user, ":", pass) });
}
private void initializeHandler(string[] proxies_client)
{
if (proxies_client == null || proxies_client.Length == 0)
return;
this.address = new string[proxies_client.Length];
this.port = new string[proxies_client.Length];
this.username = new string[proxies_client.Length];
this.password = new string[proxies_client.Length];
for (int i = 0; i < proxies_client.Length; i++)
{
var split = proxies_client[i].Split(new char[] { ':' });
this.address[i] = split[0] != "" ? split[0] : "";
this.port[i] = split[1] != "" ? split[1] : "";
this.username[i] = split[2] != "" ? split[2] : "";
this.password[i] = split[3] != "" ? split[3] : "";
}
var proxies = new WebProxy[proxies_client.Length];
NetworkCredential[] credential = new NetworkCredential[proxies_client.Length];
for (int i = 0; i < proxies_client.Length; i++)
{
if (this.username[i] != "")
credential[i] = new NetworkCredential(this.username[i], this.password[i]);
else
credential[i] = CredentialCache.DefaultNetworkCredentials;
}
const string protocol = "http://";
for (int i = 0; i < proxies.Length; i++)
{
if (this.address[i] != "")
{
var uri = proxies_client[i].Split(new char[] { ':' });
if (!uri[0].Contains(protocol))
uri[0] = string.Concat(protocol, uri[0]);
proxies[i] = new WebProxy()
{
Address = new Uri(string.Concat(uri[0], ":", uri[1])),
Credentials = credential[i],
};
}
};
this.handler = new HttpClientHandler[proxies.Length];
for (int i = 0; i < proxies.Length; i++)
{
if (proxies[i].Address.AbsoluteUri != "")
this.handler[i] = new HttpClientHandler() { Proxy = proxies[i] };
else
this.handler[i] = new HttpClientHandler();
}
}
public HttpClientHandler GethandlerIndexed(int index)
{
return (this.handler[index % this.handler.Length]);
}
public void SetConcurrentDownloads(int nb = 1)
{
Locker = new SemaphoreSlim(nb, nb);
}
public client(string[] proxies = null)
{
Clients = new ConcurrentDictionary<string, HttpClient>();
if (Locker is null)
Locker = new SemaphoreSlim(1, 1);
if (proxies != null)
initializeHandler(proxies);
}
private async Task<HttpClient> CreateClient(string Name, bool persistent, CancellationToken token)
{
if (Clients.ContainsKey(Name))
return Clients[Name];
HttpClient newClient = new HttpClient();
if (persistent)
{
while (Clients.TryAdd(Name, newClient) is false)
{
token.ThrowIfCancellationRequested();
await Task.Delay(1, token);
}
}
return newClient;
}
public async Task<T> NewRequest<T>(Func<HttpClient, T> Expression, int? MaxTimeout = 2000, string Id = null)
{
await Locker.WaitAsync(MaxTimeout ?? 2000, TokenSource.Token);
bool persistent = true;
if (Id is null)
{
persistent = false;
Id = string.Empty;
}
try
{
HttpClient client = await CreateClient(Id, persistent, TokenSource.Token);
T result = await Task.Run<T>(() => Expression(client), TokenSource.Token);
if (persistent is false)
client?.Dispose();
return result;
}
finally
{
Locker.Release();
}
}
public void AssignDefaultHeaders(HttpClient client)
{
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36");
//client.Timeout = TimeSpan.FromSeconds(3);
}
public async Task Cancel(string Name)
{
if (Clients.ContainsKey(Name))
{
CancellationToken token = TokenSource.Token;
HttpClient foundClient;
while (Clients.TryGetValue(Name, out foundClient) is false)
{
token.ThrowIfCancellationRequested();
await Task.Delay(1, token);
}
if (foundClient != null)
{
foundClient?.Dispose();
}
}
}
public void ForceCancelAll()
{
TokenSource?.Cancel();
TokenSource?.Dispose();
TokenSource = new CancellationTokenSource();
foreach (var item in Clients)
{
item.Value?.Dispose();
}
Clients.Clear();
}
}
}
One thing I spotted in a quick skim: Your line in main.cs::Program.MakeJOB:
using (HttpResponseMessage response = client.GetAsync("https://api.my-ip.io/ip.txt").Result)
should instead read
using (HttpResponseMessage response = await client.GetAsync("https://api.my-ip.io/ip.txt"))
This may not be your only issue, but by not awaiting the GetAsync method, you are effectively blocking on the request rather than yielding control back to the caller so that it can, for instance, context switch between tasks or queue up other tasks.
Same goes for
Console.WriteLine(content.ReadAsStringAsync().Result + " / " + Task.CurrentId);
which should be
Console.WriteLine((await content.ReadAsStringAsync()) + " / " + Task.CurrentId);
Although that one is not likely to block for a significant amount of time.
I've got a problem with my Xamarin App. The App uses a custom API to my website. I have not much experience in async/await methods.
The following code shows the App.xaml.cs:
public partial class App : Application
{
public static bool IsUserLoggedIn { get; set; }
public static UserModel currentLoggedInUser { get; set; }
public static List<ActionTypeModel> listTypes;
public static List<ActionSubTypeModel> listSubtypes;
public static List<UserModel> listFriends;
public static List<List<ActionModel>> listActiveActions;
public static List<ActionModel> listLastAction;
public App()
{
this.InitializeComponent();
APIHelper.InitializeClient();
StartApp().Wait();
}
private async Task StartApp()
{
//// DEBUG
//MyAccountStorage.Logout();
string username = await MyAccountStorage.GetUsername().ConfigureAwait(false);
string password = await MyAccountStorage.GetPassword().ConfigureAwait(false);
string user_id = await MyAccountStorage.GetId().ConfigureAwait(false);
if (username != null && password != null)
{
currentLoggedInUser = new UserModel();
if (user_id != null)
currentLoggedInUser.user_id = Convert.ToInt32(user_id);
currentLoggedInUser.username = username;
currentLoggedInUser.password = password;
bool isValid = false;
isValid = await AreCredentialsCorrect(0, currentLoggedInUser.username, currentLoggedInUser.password).ConfigureAwait(false);
if (isValid)
{
IsUserLoggedIn = true;
await FillLists().ConfigureAwait(false);
MainPage = new NavigationPage(await MyPage.BuildMyPage().ConfigureAwait(false));
}
else
{
IsUserLoggedIn = false;
MainPage = new NavigationPage(await LoginPage.BuildLoginPage().ConfigureAwait(false));
}
}
else
{
IsUserLoggedIn = false;
MainPage = new NavigationPage(await LoginPage.BuildLoginPage().ConfigureAwait(false));
}
}
private async Task FillLists()
{
listFriends = await DataControl.GetFriends(App.currentLoggedInUser.user_id, App.currentLoggedInUser.username, App.currentLoggedInUser.password).ConfigureAwait(false);
if (listFriends == null)
listFriends = new List<UserModel>();
listTypes = await DataControl.GetTypes(App.currentLoggedInUser.username, App.currentLoggedInUser.password).ConfigureAwait(false);
if (listTypes == null)
listTypes = new List<ActionTypeModel>();
listActiveActions = new List<List<ActionModel>>();
for (int i = 0; i < listTypes.Count; i++)
listActiveActions.Add(await DataControl.GetActiveActions(listTypes[i].action_type_id, currentLoggedInUser.user_id, currentLoggedInUser.username, currentLoggedInUser.password).ConfigureAwait(false));
listSubtypes = await DataControl.GetSubtypes(App.currentLoggedInUser.username, App.currentLoggedInUser.password).ConfigureAwait(false);
if (listSubtypes == null)
listSubtypes = new List<ActionSubTypeModel>();
listLastAction = await DataControl.GetLastAction(App.currentLoggedInUser.user_id, App.currentLoggedInUser.username, App.currentLoggedInUser.password).ConfigureAwait(false);
if (listLastAction == null)
listLastAction = new List<ActionModel>();
}
public static async Task<bool> AreCredentialsCorrect(int type, string user, string pass, string nick = "", string email = "")
{
List<UserModel> listUsers;
if (type == 1)
listUsers = await DataControl.CheckCredentials(1, user, pass, nick, email).ConfigureAwait(false);
else
listUsers = await DataControl.CheckCredentials(0, user, pass).ConfigureAwait(false);
if (listUsers != null)
if (listUsers.Any())
{
currentLoggedInUser = listUsers.First();
currentLoggedInUser.password = pass;
return true;
}
return false;
}
}
I have the API in DataControl.cs:
public static async Task<List<UserModel>> CheckCredentials(int type, string username, string pass, string email = "", string nickname = "")
{
string password = APIHelper.GetHashSha256(pass);
string url = string.Empty;
if (type == 0)
url = APIHelper.ApiClient.BaseAddress + "/account/login.php?username=" + username + "&password=" + password;
if (type == 1)
{
string nick = string.Empty;
if (string.IsNullOrEmpty(nickname) == false)
nick = "&nickname=" + nickname;
url = APIHelper.ApiClient.BaseAddress + "/account/signup.php?username=" + username + "&password=" + password + "&email=" + email + nick;
}
if (string.IsNullOrEmpty(url))
return null;
using (HttpResponseMessage response = await APIHelper.ApiClient.GetAsync(url).ConfigureAwait(false))
{
if (response.IsSuccessStatusCode)
{
List<UserModel> listUsers = JsonConvert.DeserializeObject<List<UserModel>>(await response.Content.ReadAsStringAsync().ConfigureAwait(false));
return listUsers;
}
else
return null;
}
}
That's one of the different async methods. When I leave out the ConfigureAwait(false), I run into a deadlock. When I add it to the code I run into an error.
Could you please help me.
As #GSerg already wrote, you have to restructure the code. The App constructor must set the MainPage to some page. That one can be empty saying something like "Loading data".
Then you can start a background Task which retrieves the data you need.
When the data has been loaded, then you can update your page with the newly loaded data. But UI updates always have to happen on the UI thread. This is the same on all platforms. So you have to switch back with Device.BeginInvokeOnMainThread(...).
public App()
{
InitializeComponent();
APIHelper.InitializeClient();
MainPage = new LoadingPage();
// start a background thread
Task.Run(async () =>
{
try
{
await StartApp(); // load the data
// go back to the main thread
Device.BeginInvokeOnMainThread(() =>
{
// replace the MainPage with one which shows the loaded data
MainPage = new DataPage();
});
}
catch (Exception ex)
{
// handle the exception
}
});
}
You can use Task.Run(
//call your async method here
);
So in your case:
Task.Run(Startup);
Brand new both to .net core as well as for unit testing, so please be at my help pointing out where the problem lies in my code.
[TestMethod]
public void RetrieveAsync_AddModel_ReturnsNotEmptyPersonList()
{
// Arrange
var data = new List<Person>();
var mySet = new Mock<DbSet<Person>>();
var defaultHttpContext = new DefaultHttpContext();
var httpContextAccessorMock = new Mock<IHttpContextAccessor>();
httpContextAccessorMock.Setup(m => m.HttpContext).Returns(defaultHttpContext);
var myContextMock = new Mock<MyContext>(new DbContextOptions<MyContext>(), httpContextAccessorMock.Object);
myContextMock.Setup(c => c.Set<Person>()).Returns(mySet.Object);
var id = Guid.NewGuid();
var service = new PersonService(myContextMock.Object);
var model = new Person
{
Id = id
};
// Act
var createdModel = service.CreateAsync(model).Result;
data.Add(createdModel);
var findModelById = data.Find(item => item.Id == createdModel.Id).Id;
**var retrievedModel = service.RetrieveAsync(findModelById).Result; // null**
// Assert
**Assert.AreEqual(id, createdModel.Id); // correct, test passes
Assert.AreEqual(id, retrievedModel.Id); // retrievedModel is null, test fails**
}
Generics methods I have to test are as follows:
public async Task<T> CreateAsync(T model)
{
_dbContext.Set<T>().Add(model);
await _dbContext.SaveChangesAsync();
return model;
}
public async Task<T> RetrieveAsync(Guid id)
{
return await _dbContext.Set<T>().FindAsync(id);
}
The question is, why retrievedModel is null?
Hello I am trying to catch messages from database and transfer to caller but when I used Clients.Caller method then it pass me error like
Using a Hub instance not created by the HubPipeline is unsupported
If I am using
var context = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
context.Clients.All.receiver(respose);
then it replying nothing. So please help me to solve out this question.
and I am using below code:
public async Task GetAllMessages(int roomid, int fromuserId, int touserId, int index, int pageSize, int broadcastid = 0)
{
ResponseModel respose = new ResponseModel();
try
{
var model = new MessageDetailModel
{
Index = index,
PageSize = pageSize,
FromUserId = fromuserId,
ToUserId = touserId,
ChatRoomId = roomid,
BroadCastId = broadcastid
};
MesaageModel totalmessages = new MesaageModel();
List<RecentMessage> messages = new List<RecentMessage>();
var usermessages = await _userService.GetAllMessages(model);
messages.AddRange(usermessages);
foreach (var message in messages)
{
model.BroadCastMessageId = model.BroadCastId == 0 ? 0 : message.BroadCastMessageId;
model.ChatRoomMessageId = model.BroadCastId == 0 ? message.ChatRoomMessageId : 0;
List<UserDetail> userofseenby = new List<UserDetail>();
var users = await _userService.GetMessageSeenBy(model);
userofseenby.AddRange(users);
message.SeenBy = userofseenby;
}
//totalmessages.Messages.AddRange(messages);
totalmessages.Messages = messages;
totalmessages.UnseenMessageCount = await _userService.GetUnSeenCount(messages.FirstOrDefault().ChatRoomId, fromuserId);
if (messages.FirstOrDefault().IsBroadCast == true)
totalmessages.Users = (List<UserDetail>)await _userService.GetUsersByBroadCastId(messages.FirstOrDefault().BroadCastId);
else if (messages.FirstOrDefault().IsGroup == true)
totalmessages.Users = (List<UserDetail>)await _userService.GetUsersByChatRoomId((int)messages.FirstOrDefault().ChatRoomId);
respose = ResponseHelper.SuccessResponse("onAllMessagesReceived", totalmessages);
Clients.Caller.receiver(respose); // Error catch here
}
catch (Exception ex)
{
respose.ActionCommand = "onAllMessagesReceived";
respose = ResponseHelper.ErrorResponse(respose.ActionCommand, ex.ToString());
Clients.Caller.receiver(respose);
}
}
And Constructors of class is below :
public ChatHub()
{
_userService = new UserBusinessLogic();
_chatterService = new ChatterBusinessLogic();
}
public ChatHub(IChatterBusinessLogic chatterService, IUserBusinessLogic userService)
{
_chatterService = chatterService;
_userService = userService;
}
And Controller constructor are like this :
public ChatterController()
{
_userService = new UserBusinessLogic();
_chatterService = new ChatterBusinessLogic();
}
public ChatterController(IChatterBusinessLogic chatterService, IUserBusinessLogic userService)
{
_chatterService = chatterService;
_userService = userService;
}
I used to work with browser-based applications. for example Angular simple repository.
function getSomeData(params) {
...
return $http({
url: conf.urlDev + 'some/rest-url',
method: "GET",
params: params,
cache: true
}).then(getDataComplete);
function getDataComplete(response) {
return response.data;
}
}
How it will look the same in c# (XAMARIN for example)?
i try :
public class BaseClient
{
protected Http _client = null;
protected string _urlObj;
protected string _basePath;
public BaseClient ()
{
_client = new Http(new HttpClientHandler());
}
public string Path
{
set
{
_urlObj = value;
}
}
public async Task<Result<IList<T>>>getList<T>(Dictionary<string,object> parametrs = null)
{
if (parametrs != null)
{
foreach(KeyValuePair<string, object> keyValue in parametrs)
{
_urlObj = _urlObj.SetQueryParam(keyValue.Key, keyValue.Value);
}
}
var response = await _client.GetAsync(_urlObj.ToString());
if (response.IsSuccessStatusCode)
{
return new Result<IList<T>>()
{
Success = true,
Value = JsonConvert.DeserializeObject<IList<T>>(await response.Content.ReadAsStringAsync())
};
}
else
{
var error = new Result<IList<T>>()
{
Error = response.StatusCode.ToString(),
Message = response.ReasonPhrase,
Success = false
};
return error;
}
}
in my service:
public async Task<IList<News>> GetAllNewsByParams(DateTime from,
string orderBy = "-published",
DateTime to = new DateTime(),
int page = 1, int category = 0)
{
_client.Path = _config.NewsPath;
var dict = new Dictionary<string, object> {
{"from", from.ToString("s")},
{"order_by", orderBy.ToString()},
{"to", to.ToString("s")},
{"page", page.ToString()}
};
if (category != 0)
{
dict.Add("category", category.ToString());
}
var res = await _client.getList<News>(dict);
return res.Value;
}
and im ny viewmodel
foreach (var item in await _newsService.GetAllNewsByParams(
_To,
_OrderBy,
_From, _Page,
selectedTag == null ? _SeletedNewsTagId : selectedTag.Id))
{
NewsList.Add(item);
}
Is his query executed synchronously ?
How do I make it an asynchronous?
First of all I would really encourage you to use RestSharp, it really simplifies making HTTP requests and deserialise them. Add a RestSharp nuget package to your project. Here is how your code will look like using RestSharp.
public class BaseClient
{
protected IRestClient _client = null;
protected string _urlObj;
protected string _basePath;
public BaseClient()
{
_client = new RestClient();
}
public async Task<Result<IList<T>>> GetList<T>(string path, Dictionary<string, object> parametrs = null)
{
var request = new RestRequest(path, Method.GET);
if (parametrs != null)
{
foreach (var keyValue in parametrs)
{
request.AddQueryParameter(keyValue.Key, keyValue.Value);
}
}
var response = await _client.Execute<List<T>>(request);
if (response.IsSuccess)
{
return new Result<IList<T>>()
{
Success = true,
Value = response.Data
};
}
else
{
var error = new Result<IList<T>>()
{
Error = response.StatusCode.ToString(),
Message = response.StatusDescription,
Success = false
};
return error;
}
}
}
In your service
public async Task<IList<News>> GetAllNewsByParams(DateTime from,
string orderBy = "-published",
DateTime to = new DateTime(),
int page = 1, int category = 0)
{
var dict = new Dictionary<string, object> {
{"from", from.ToString("s")},
{"order_by", orderBy.ToString()},
{"to", to.ToString("s")},
{"page", page.ToString()}
};
if (category != 0)
{
dict.Add("category", category.ToString());
}
var res = await _client.GetList<News>(_config.NewsPath, dict);
return res.Value;
}
And in your viewmodel
var news = await _newsService.GetAllNewsByParams(
_To,
_OrderBy,
_From, _Page,
selectedTag == null ? _SeletedNewsTagId : selectedTag.Id);
foreach (var item in news)
{
NewsList.Add(item);
}
This will be 100% asynchronous.