Cannot call method from another class without static field - c#

I have interface with this code
interface IHttpRequest
{
Task<string> GetCountries();
}
That I inherit in class like this
public class GettingCountries: IHttpRequest
{
public async Task<string> GetCountries()
{
var client = new RestClient("http://api.xplorpal.com");
var request = new RestRequest("/countries", Method.POST);
var response = await client.ExecuteTaskAsync(request);
var content = response.Content;
var responseCountries = JsonConvert.DeserializeObject<IEnumerable<GettingCountry.RootObjectCountries>>(content);
GettingCountry.CountriesList.Clear();
GettingCountry.ListOfCountriesRoot.Clear();
foreach (var country in responseCountries)
{
GettingCountry.CountriesList.Add(country.nicename);
GettingCountry.ListOfCountriesRoot.Add(new GettingCountry.RootObjectCountries(country.id, country.nicename));
}
return content;
}
}
After this I need to call method of this class somewhere, like this for example var countries_list = await GettingCountries.GetCountries();
But now I have error.
How I can solve it? I can make it static, but is this ok? Maybe smth other?

Related

How to show warning for a method if it is called directly in c#

{
public class MyClass
{
// all the call to GetData() of apiHelper should pass through this method
public async Task<T> InitiateAPICallAsync<T>(Task<T> apiCall) where T : BaseResponse
{
var response = await apiCall;
// some common code work using response data
return response;
}
public async void MyFunc()
{
var helper = new APIHelper("1", "2");
//
var response1 = await InitiateAPICallAsync(helper.GetData<Response1>()); // correct way
var rewponse2 = await helper.GetData<Response1>(); // incorrect way, need to show warning
}
}
public class APIHelper
{
public APIHelper(string a, string b)
{
// some code
}
public async Task<T> GetData<T>()
{
await Task.Delay(1000); // network call
// other code
return default;
}
}
public class Response1 : BaseResponse { }
public class Response2 : BaseResponse { }
public class BaseResponse { }
}
in my application MyClass, there is a method named InitiateAPICallAsync(). All call to the GetData() method of APIHelper must be pass through this method. I need to showing warning, if GetAsync() method called directly without passing through InitiateAPICallAsync.
Note: It is a sample code snippet, where in my real time project the APIHelper represents a Connectivity library. and MyClass represents another library named service.
How to show warning for a method if it is called directly in c#
Using CallerMemberName attribute is core thread of the following solution, thanks for Fumeaux's comment, I tried place CallerMemberName attribute above GetData method directly to get the caller, but the result is MyFunc but not InitiateAPICallAsync. So I tried use delegate as the InitiateAPICallAsync parameter that could make sure GetData will called by InitiateAPICallAsync. The following code has been simplified.
public delegate Task<int> PrintCaller([CallerMemberName] string Caller = null);
public class MyClass
{
public async Task<string> InitiateAPICallAsync(PrintCaller apiCall)
{
var response = await apiCall();
return "Test";
}
public async void MyFunc()
{
var helper = new APIHelper();
var str1 = await InitiateAPICallAsync(new PrintCaller(helper.GetData));
var str2 = await helper.GetData();
}
}
public class APIHelper
{
public async Task<int> GetData([CallerMemberName] string Caller = null)
{
if (Caller == "InitiateAPICallAsync")
{
// do some thing
}
else
{
//Show Warning
var dialog = new MessageDialog("Waring!!! Please don't call it directly");
await dialog.ShowAsync();
}
return 0;
}
}

Having trouble with returning HTTP response via Service to ViewModel (UWP MVVM)

I have an interface that is defined as follows:
internal interface IHttpService
{
Task SendGetRequest(string param);
}
And the following concrete class (obviously there is compilation errors):
public class HttpService : IHttpService
{
private readonly HttpClient client;
private const string httpLink = "https://somesite.org/search?q=";
private const string httpSuffix = "&format=json&ads=1";
public HttpService()
{
client = new HttpClient();
client.DefaultRequestHeaders.Add("user-agent", "myapp");
}
public async Task SendGetRequest(string param)
{
var response = await client.GetAsync(httpLink + param + httpSuffix);
return response.Content.ReadAsStringAsync();
}
}
So I obviously get a compilation error when returning the ReadAsStringAsync function, but I want my viewmodel to get the response from this function. My viewmodel is as follows:
public SearchViewModel()
{
httpService = (App.Current as App).Container.GetService<IHttpService>();
SearchCommand = new RelayCommand(() =>
{
// Will need to do some proper validation here at some point
var response = await httpService.SendGetRequest(httpStringToSend);
});
}
I'm sure i'm missing something but i'm not entirely sure what...
ReadAsStringAsync is asynchronous and needs to be awaited.
You also need to use the generic Task<T> as your return type rather than Task, because your asynchronous operation is returning a value i.e. string.
public async Task<string> SendGetRequest(string param)
{
var response = await client.GetAsync(httpLink + param + httpSuffix);
return await response.Content.ReadAsStringAsync();
}
HttpResponseMessage is also IDisposable so you should add a using block:
public async Task<string> SendGetRequest(string param)
{
using (var response = await client.GetAsync(httpLink + param + httpSuffix))
{
return await response.Content.ReadAsStringAsync();
}
}

Can a static helper class be used for WebApi calls (from UI)?

I have X controllers that use a API site (WebApi). I have created an ApiHelper class. Which I use in these controllers. Now my question is this. Can I make this ApiHelper a static class? I think I can because the httpClient is instanced. Or do I overlook something, and does it need to be an instanced ApiHelper. (the use of static still confuses me sometimes). Example code below.
public class HomeController : Controller
{
public async Task<string> VersionDemo()
{
var response = await ApiHelper.Call("/api/config/version");
var data = response.Content.ReadAsStringAsync();
var res = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(data.Result);
return res;
}
}
public class ConfigController : Controller
{
private async Task<List<ConfigSetting>> GetGeneralConfigurationDemo()
{
var generalConfiguration = new List<ConfigSetting>();
var response = await ApiHelper.Call("api/configuration/GetGeneralConfiguration");
var data = response.Content.ReadAsStringAsync();
generalConfiguration = JsonConvert.DeserializeObject<List<ConfigSetting>>(data.Result);
return generalConfiguration;
}
}
public static class ApiHelper
{
public static async Task<HttpResponseMessage> Call(string url)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var baseAdress = System.Configuration.ConfigurationManager.AppSettings["ApiBaseAddress"];
string apiUrl = baseAdress + url;
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(apiUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(apiUrl);
return response;
}
}
}
Make base controller and hide http client as protected thing.
public abstract class BaseController : Controller
{
protected ApiHelper Api { get; set; }
}
Then derive your controllers from BaseController
public class ConfigController : BaseController {}
public class HomeController : BaseController {}
Note : try not to use static classes cause they make your heap littered. They are allocated in "high-frequency" heap, which is never garbage collected.
There would be no problem to leave your class static as the HttpClient stays on the method scope and thus each call to your static method will use a different HttpClient. It would not be safe if you used a static member (field or property) as it would be shared by all the callers and you would need to synchronize the access (for a multi thread usage).
After reading (httpClient your are doing it wrong , singleton pattern) and subsequently testing. I ended up using the following code. Main goal is one httpClient application wide and avoid socket exhaustion.
In my controllers where I'm in need of a httpClient I use the HttpClientSingleton.Instance see below.
And here is a BaseController you can inherit from in your controllers that are going to use your API.
public class BaseController : Controller
{
public readonly string ApiBaseAdress = System.Configuration.ConfigurationManager.AppSettings["ApiBaseAddress"];
public BaseController()
{
//Set as needed Servicepoint settings
//string SecurityProtocolTypeFromConfig = System.Configuration.ConfigurationManager.AppSettings["SecurityProtocolType"];
//SecurityProtocolType fromConfig;
//Enum.TryParse(SecurityProtocolTypeFromConfig, out fromConfig);
//ServicePointManager.SecurityProtocol = fromConfig;
//possible ServicePoint setting needed in some cases.
//ServicePointManager.Expect100Continue = false;
//ServicePointManager.MaxServicePointIdleTime = 2000;
//ServicePointManager.SetTcpKeepAlive(false, 1, 1);
}
}
And here is the HttpClientSingleton class:
public sealed class HttpClientSingleton
{
private static readonly Lazy<HttpClient> lazy = new Lazy<HttpClient>(() => new HttpClient());
public static HttpClient Instance { get { return lazy.Value; } }
private HttpClientSingleton()
{
}
}
So putting it together. Here is an example of getting some loginfo from the API.
public class MyLogController : BaseController
{
[HttpPost]
public async Task<JsonResult> log(string requestId)
{
var url = ApiBaseAdress + string.Format("/api/runs/log/{0}", requestId);
List<Log> logs = new List<Log>();
var response = await HttpClientSingleton.Instance.GetAsync(url);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadAsStringAsync();
logs = JsonConvert.DeserializeObject<List<Log>>(result);
return Json(logs);
}
}
You can write a static helper class. If the name is ApiHelper, then add a Microsoft.AspNet.WebApi.Client reference. When your app is initialized, call the class's InitializeClient() method, and you can call the GetAsync() method if you need. The code is below:
public static class ApiHelper
{
public static HttpClient ApiClient { get; set; }
public static void InitializeClient()
{
ApiClient = new HttpClient();
ApiClient.DefaultRequestHeaders.Accept.Clear();
ApiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public static async Task<T> GetAsync<T>(string url)
{
using (HttpResponseMessage response = await ApiHelper.ApiClient.GetAsync(url))
{
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<T>();
return result;
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
}
}

Create generic async task function

I have created a function that returns an object using async/await. I would like to make the function generic so that it can return whatever object that I pass in. The code is boilerplate except for the objects being returned. I would like to be able to call GetAsync and have it return the correct object
public Patron getPatronById(string barcode)
{
string uri = "patrons/find?barcode=" + barcode;
Patron Patron = GetAsync(uri).Result;
return Patron;
}
private async Task<Patron> GetAsync(string uri)
{
var client = GetHttpClient(uri);
var content = await client.GetStringAsync(uri);
JavaScriptSerializer ser = new JavaScriptSerializer();
Patron Patron = ser.Deserialize<Patron>(content);
return Patron;
}
What about a generic method?
private async Task<T> GetAsync<T>(string uri)
{
var client = GetHttpClient(uri);
var content = await client.GetStringAsync(uri);
var serializer = new JavaScriptSerializer();
var t = serializer.Deserialize<T>(content);
return t;
}
Normally, you should place this method into another class and make it public, in order it can be used by methods in different classes.
Regarding the way you call this method, you could try the following:
// I capitalized the first letter of the method,
// since this is a very common convention in .NET
public Patron GetPatronById(string barcode)
{
string uri = "patrons/find?barcode=" + barcode;
var Patron = GetAsync<Patron>(uri).Result;
return Patron;
}
Note: In the above snippet I assumed that you haven't moved the GetAsync into another class. If you move it, then you have to make a slight change.
Update
I'm not following what you mean by your note. Do I need to make GetPatronById a task function as well - like Yuval has done below?
I mean something like this:
// The name of the class may be not the most suitable in this case.
public class Repo
{
public static async Task<T> GetAsync<T>(string uri)
{
var client = GetHttpClient(uri);
var content = await client.GetStringAsync(uri);
var serializer = new JavaScriptSerializer();
var t = serializer.Deserialize<T>(content);
return t;
}
}
public Patron GetPatronById(string barcode)
{
string uri = "patrons/find?barcode=" + barcode;
var Patron = Repo.GetAsync<Patron>(uri).Result;
return Patron;
}
Generic can be easily done with:
private async Task<T> GetAsync(string uri)
{
var client = GetHttpClient(uri);
var content = await client.GetStringAsync(uri);
return JsonConvert.DeserializeObject<T>(content);
}
Things to note:
JavaScriptSerializer has been deprecated for ages, avoid using it. Try out Json.NET instead.
This:
Patron Patron = GetAsync(uri).Result;
is dangerous and can cause potential deadlocks, especially in Web API. You need to go "async all the way":
public Task<Patron> GetPatronByIdAsync(string barcode)
{
string uri = $"patrons/find?barcode={barcode}";
return GetAsync<Patron>(uri);
}
And only your top most level invoker need await on the Task. Possibly some controller action:
public async Task SomeAction()
{
await GetPatronByIdAsync("hello");
}

Error with await operator

There is problem with my code. How can I solve this problem? This problem in await operator.
public MyModel()
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("https://api.vkontakte.ru/method/video.get?uid=219171498&access_token=d61b93dfded2a37dfcfa63779efdb149653292636cac442e53dae9ba6a049a75637143e318cc79e826149");
string googleSearchText = await response.Content.ReadAsStringAsync();
JObject googleSearch = JObject.Parse(googleSearchText);
IList<JToken> results = googleSearch["response"].Children().Skip(1).ToList();
IList<MainPage1> searchResults = new List<MainPage1>();
foreach (JToken result in results)
{
MainPage1 searchResult = JsonConvert.DeserializeObject<MainPage1>(result.ToString());
searchResults.Add(searchResult);
}
You're trying to use await within a constructor. You can't do that - constructors are always synchronous.
You can only use await within a method or anonymous function with the async modifier; you can't apply that modifier to constructors.
One approach to fixing this would be to create a static async method to create an instance - that would do all the relevant awaiting, and then pass the results to a simple synchronous constructor. Your callers would then need to handle this appropriately, of course.
public static async Task<MyModel> CreateInstance()
{
string googleSearchText;
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage response = await client.GetAsync(...))
{
googleSearchText = await response.Content.ReadAsStringAsync();
}
}
// Synchronous constructor to do the rest...
return new MyModel(googleSearchText);
}
You can't use await in the constructor of a class.
An async method returns a Task object which can be executed async. A constructor does not have a return type and thus can't return a Task object, and thus can't be awaited.
A simple fix for this problem is create a Init function:
public MyModel()
{
}
public async Task Init()
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("https://api.vkontakte.ru/method/video.get?uid=219171498&access_token=d61b93dfded2a37dfcfa63779efdb149653292636cac442e53dae9ba6a049a75637143e318cc79e826149");
string googleSearchText = await response.Content.ReadAsStringAsync();
JObject googleSearch = JObject.Parse(googleSearchText);
IList<JToken> results = googleSearch["response"].Children().Skip(1).ToList();
IList<MainPage1> searchResults = new List<MainPage1>();
foreach (JToken result in results)
{
MainPage1 searchResult = JsonConvert.DeserializeObject<MainPage1>(result.ToString());
searchResults.Add(searchResult);
}
}
Then when you create your model:
var model = new MyModel();
await model.Init();

Categories