I have a simple asp.net webservice which has a simple async function like so:
public class TestService : System.Web.Services.WebService
{
[WebMethod]
public async Task<string> HelloWorld()
{
await Task.Delay(TimeSpan.FromSeconds(2));
return "Hello World";
}
}
and I want to get the result of it in my asp.net webforms app like so:
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
RegisterAsyncTask(new PageAsyncTask(GetFullName));
}
async Task<string> GetFullName()
{
var client = new TestService.TestServiceSoapClient();
return await client.HelloWorldAsync();
}
}
but I get the error:
CS0029 Cannot implicitly convert type 'digital_sig_webapp.TestService.HelloWorldResponse' to 'string'
I am expecting a result type of string here, so what is happening?
how can I get the value out of it?
What you are looking for is one of the HelloWorldResponse's fileds. The name should be HelloWorldResult. So your code can be something like this(Not tested):
async Task<string> GetFullName()
{
var client = new TestService.TestServiceSoapClient();
var response = await client.HelloWorldAsync();
return response.HelloWorldResult;
}
Related
I am trying to get some weather data from Open Weather Maps and l use HTTPClient and API ASP.NET in C#.
My code keeps returning:
System.Threading.Tasks.Task`1[System.String]
I've made my methods async and await but I still get the above returned. I thought making it await would return the value.
I am just trying to get the string from Open Weather Maps, I'll worry about parsing it to JSON once I have this working. Here is my code, "MY_APPID" is replaced with my API key, I just removed it here.
My main:
private async Task<string> GetLocationJson()
{
const string APPID = "(MY_APPID)";
const string LOCATIONID = "2172797";
string jsonAsString = "";
string callStringJson = "api.openweathermap.org/data/2.5/weather?id=" + LOCATIONID + "&appid=" + APPID;
ApiCalls weatherApi = new ApiCalls(callStringJson);
jsonAsString = await weatherApi.GetLocationJson();
return jsonAsString;
}
//ShowLocationJson is called on button click
protected void ShowLocationJson(object sender, EventArgs e)
{
litOutput.Text = GetLocationJson().ToString();
}
And my ApiCalls Class is:
public class ApiCalls
{
HttpClient client = new HttpClient();
Uri url;
public ApiCalls(string link)
{
url = new Uri("https://" + link);
}
public async Task<string> GetLocationJson()
{
string content = await client.GetStringAsync(url);
return content;
}
}
url variable is being passed the correct values so I know it's ok up to there.
Im using ASP.NET Framework 4.5 as well
As Steve and mason have already noticed you have to await all methods returning Task. You need to change your ShowLocationMethod to:
protected async void ShowLocationJson(object sender, EventArgs e)
{
litOutput.Text = await GetLocationJson();
}
You receive System.Threading.Tasks.Task1[System.String] because you call method ToString() of Task object. The default implementation of the ToString method returns the fully qualified name of the type of the object: Task<String>
{
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;
}
}
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();
}
}
On startup, how do I execute an async function inside another class by redirecting a route?
The code below first runs the Home() function inside the StartupController() class but I want to run the GetString() function in the HelloApiController() class and pass the string variable. The method I am using doesn't work, is there something I am missing?
public class StartupController()
{
[HttpPost]
[Route("api/forge/run")]
public async Task<dynamic> Home()
{
string text = "Hello Api";
RedirectToRoute("api/forge/String", "text");
return null;
}
}
public class HelloApiController()
{
[HttpGet]
[Route("api/forge/String")]
public async Task<dynamic> GetString(string text)
{
return text;
}
}
I create a method in class :
public async void Foo()
{
.....
string response = await Utilities.sendData(data);
....
}
I create break point and run,when it call foo method,but break point run at
string response = await Utilities.sendData(data)
and then break point is disappear,if i call in code behind (xaml)it no problem
You can call an async method from synchronous code.
The async modifier says that the code within that method can await on other async methods. Here's a silly example
public class Foo
{
public void DoSomething()
{
await Something(); //invalid
Something(); //valid
}
public async void Something()
{
await SomethingElse(); //valid
SomethingElse(); // also valid, but synchronous
}
public async void SomethingElse()
{
}
}