How can I complete this REST implementation? - c#

MyService calls a REST uri using HttpClient.GetAsync(). I'm calling the service method from the Main method of a console app within the same solution but the following result is returned:
Id = 3, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
What do I need to do to complete this REST implementation?
MyService:
using System.Net.Http;
using System.Threading.Tasks;
namespace Services
{
public class MyService
{
private static HttpClient Client = new HttpClient();
public void GetData()
{
var result = await Client.GetAsync("https://www.test.com/users");
}
}
}
Service call from Console Main():
var result = new MyService().GetData();
UPDATE
Ok I updated my method implementation to look like this:
public async Task<HttpResponseMessage> GetData()
{
var result = await Client.GetAsync("https://www.test.com/users");
return result;
}
However, this still returns the same value that I included in my original post. What am I missing here?

You didn't returned anything from method
public async Task GetData()
{
return await Client.GetAsync("https://www.test.com/users");
}
return your result from method.

Related

HttpClient Async Method return value

I studied over the Internet regarding Task Async method but cannot seem to find an approach to assign my return value in Task Async to another object. The first method is to prepare HTTP Request header and Uri.
public static async Task MainAsync()
{
string token = await AuthHelper.AcquireToken(tenantId, clientId, clientSecret);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
client.BaseAddress = new Uri("https://foo.net");
await GetValue(client);
}
}
The second method is to use GetAsync to call to an API to get the JSON and the two last lines I extract only value from the "Value" field in the JSON body.
public static async Task<String> GetValue(HttpClient client)
{
string url = $"/mykey/key01";
using (var httpResponse = await client.GetAsync(url))
{
httpResponse.EnsureSuccessStatusCode();
string responsContent = await httpResponse.Content.ReadAsStringAsync();
JObject json = JObject.Parse(responsContent);
string value = json["value"].ToString();
return value;
}
}
Now I would like to use this value to assign to another object, but not sure how to do so. I managed to return the valid value. Is it possible to retrieve the value from another method or even different class?
[Updated] The main function is:
static void Main(string[] args)
{
try
{
MainAsync().Wait();
}
catch (Exception e)
{
Console.WriteLine(e.GetBaseException().Message);
}
}
Update
To be more clear. The HTTP response message is a JSON format and I can return the value from Value property in this JSON. Now how I can to reuse the value from an external method or class
I'm not sure exactly what you are trying to achieve. And there would be thorough debates about your architecture, you can do something like this..
Update
Because your MainAsync is static it can be called form anywhere.
You just need to modify it a bit to return your result as follows :
public static async Task<string> MainAsync()
{
...
return await GetValue(client);
...
And somewhere else
public class MyAwesomeClass
{
public async Task DoMagic()
{
var newValueOfSomething = await MainAsync();
// hilarity ensues
}
}
You can Make it more generic and useful, something like below :
Your initial method can be changes to :
public async Task<T> GetContentAsync<T>(HttpClient client)
{
string url = $"/mykey/key01";
using (var httpResponse = await client.GetAsync(url))
{
httpResponse.EnsureSuccessStatusCode();
string responsContent = await httpResponse.Content.ReadAsStringAsync();
return Deserialize<T>(json);
}
}
private T Deserialize<T>(string json)
{
return JsonConvert.DeserializeObject<T>(json, SerializationSettings);
}
You can now call method like :
var person = await GetContentAsync<Person>(/*http client*/)

How to Get Cosmos Db Data in Azure Mobile App Service

I try to get Data in Cosmos Db using Azure Mobile App Service , I tried this documentation https://learn.microsoft.com/en-us/azure/cosmos-db/sql-api-dotnet-application#_Toc395637765 but I can't implement it from MVC to Azure Mobile App Service , I'm still very new in ASP and don't realy understand all the function, in this Documentation they use this to get the data from it.
public ActionResult Index()
{
return View();
}
[ActionName("Index")]
public async Task<ActionResult> IndexAsync()
{
var items = await DocumentDBRepository<Item>.GetItemsAsync(d => !d.Completed);
return View(items);
}
But because my ASP.NET is not MVC so I can't use ActionResult (my App Service will not have view) and that what make it confusing for me, I don't know how to return the task, and ussualy I'm using StreamReader to return the data but it says my Task doesn't contain StreamReader
This is the DocumentDB class which handle the GetData:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;
namespace gumilangService.Controllers
{
public static class DocumentDBRepository<T> where T : class
{
private static readonly string DatabaseId = ConfigurationManager.AppSettings["database"];
private static readonly string CollectionId = ConfigurationManager.AppSettings["collection"];
private static DocumentClient client;
public static void Initialize()
{
client = new DocumentClient(new Uri(ConfigurationManager.AppSettings["endpoint"]), ConfigurationManager.AppSettings["authKey"]);
}
public static async Task<IEnumerable<T>> GetItemsAsync(Expression<Func<T, string>> predicate)
{
IDocumentQuery<T> query = client.CreateDocumentQuery<T>(
UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId))
// .Where(predicate)
.AsDocumentQuery();
List<T> results = new List<T>();
while (query.HasMoreResults)
{
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
}
}
}
And this is my Controller so far:
public string Get()
{
var items = DocumentDBRepository<MyCollection>.GetItemsAsync(d => d.Id);
/* using (var streamReader = new StreamReader(items.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
return result;
}
*/
return items.ToString();
//return "Hello";
}
And it return this instead the data:
System.Threading.Tasks.Task`1[System.Collections.Generic.IEnumerable`1[gumilangService.DataObjects.MyCollection]]
Any idea how to implement this and get the data when I try it in Postman ?
You need to go back a bit further.
Your Get() method in the "controller" returns a string - it needs to return the actual data. ASP will serialize that data into a string using either XML or JSON.
public MyItem Get(string id){
Item item = DocumentDBRepository<MyItem>.Get(x => x.Id == id);
return item; // separate line so you can put a breakpoint here and look
}
You used an async method
var items = DocumentDBRepository<MyCollection>.GetItemsAsync(d => d.Id);
which returns Task. The correct way to call async methods is to make your own method async by replacing its return type with "async Task" and adding "await" before all async calls to other methods:
var items = await DocumentDBRepository<MyCollection>.GetItemsAsync(d => d.Id);
This is likely not the only issue... I strongly recommend that you download some sample project and understand how it works.

Task.Wait always returns false although task finished

I'm using HttpClient trying to execute a POST method in Web API controller. The controller method is synchronous. I'm doing so this way:
var response = owin.HttpClient.PostAsJsonAsync(uri, body);
After that I'm calling Wait:
var result = response.Wait(15000);
When running this code, I see the http finish executing, yet the result value is always false. What can I be missing?
Edit:
I now tried an async approach yet it didn't help me as well
public IHttpActionResult Add(Item item)
{
var result = _db.AddItem(item);
return Ok(result);
}
Test project:
TestServer _owinTestServer;
public async Task<HttpResponse message> Method1(string url, object body)
{
return await
_owinTestServer.HttpClient.PostAsJsonAsync(url,body);
}
public async Task<ItemPreview> Method2(object body);
{
return await Method1("..", body ).Result.Content.ReadAsAsync<ItemPreview>();
}
[TestMethod]
public void test1()
{
Item item = new(...);
Method2(item).Continue with(task => {// Never reach here }
}
What am I doing wrong?
When debugging I see that the controller method returns a good response, yet it never reaches back to my test
You are mixing async and blocking calls (ie .Result, .Wait()) which are leading to a deadlock.
This looks more like it is a blocking issue on the test client side.
You need to make the test async all the way through in this case if you want to await on results from the server.
Convert test method to async
[TestMethod]
public async Task test1() {
//Arrange
Item item = new Item(...);
//Act
var preview = await Method2(item);
//Assert
Assert.IsNotNull(preview);
}
And update the methods to not mix async and blocking calls.
Method1 does not need asyn/await if it is not using the task after the call so it can be removed and just have the method return the Task that can be awaited
TestServer _owinTestServer;
public Task<HttpResponse> Method1(string url, object body) {
return _owinTestServer.HttpClient.PostAsJsonAsync(url, body);
}
Method2 needs to await the response from Method1 and then get its content.
public async Task<ItemPreview> Method2(object body) {
var response = await Method1("..", body );
return await response.Content.ReadAsAsync<ItemPreview>();
}
It doesn't matter if the controller method is synchronous or not. That is purely a concern on the server code. Since the PostAsJsonAsync method is asynchronous, you need to await it:
var response = await owin.HttpClient.PostAsJsonAsync(uri, body);
Which will allow your code to wait for the response from the server.
I assume your initial code looked something like this...
var response = owin.HttpClient.PostAsJsonAsync(uri, body);
var result = response.Wait(15000);
var itemPreview = response.Result.Content.ReadAsAsync<ItemPreview>();
...
And yes, result will be false after waiting the 15 seconds. This is because you have setup the request, A.K.A response, but you haven't actually made the called and any response.Wait(n) will return false.
You just need to start the ReadAsAsync...
var response = owin.HttpClient.PostAsJsonAsync(uri, body);
var itemPreview = response.Result.Content.ReadAsAsync<ItemPreview>();
However, I think you will find you can skip the response.Wait(n) all together, as it will return true because the ReadAsAsync() will wait to return or fail. If you're looking to configure the request timeout, you can do that in the HttpClient and your ReadAsAsync will throw an AggregateException with an InnerException of TaskCanceledException.
On a side note, you don't need to use owin.HttpClient you can just instantiate a new HttpClient. I believe the owin object you are referring to is for self hosting your WebApi, I don't know if that matters. But let's say you are calling Add(Item item) on your WebApi and that db.AddItem(item) will return and ItemPreview object, your code could look like this:
[TestMethod]
public void test1()
{
Item item = new(...);
var uri = "..";
var client = new HttpClient();
var response = client.PostAsJsonAsync(uri, item);
var itemPreview = response.Result.Content.ReadAsAsync<ItemPreview>();
/* The things to happen once you have item preview */
}
The result may always be false because the _db.AddItem is returning false all the time. If not, I've made a change in your code ideally which should work for you
TestServer _owinTestServer;
public async Task<HttpResponse message> Method1(string url, object body)
{
return await _owinTestServer.HttpClient.PostAsJsonAsync(url,body);
}
public async Task<ItemPreview> Method2(object body);
{
return await Method1("..", body ).Result.Content.ReadAsAsync<ItemPreview>();
}
[TestMethod]
public void test1()
{
Item item = new(...);
await Method2(item).ContinueWith(task => {// Never reach here }
}
Since Method2 returns an Async Task, the ContinueWith will not wait for it to complete and hence it may required await on the method invocation.

Unit Testing Cache Behaviour of Akavache with TestScheduler

So I'm trying to test caching behaviour in an app that's using Akavache.
My test looks like this:
using Akavache;
using Microsoft.Reactive.Testing;
using Moq;
using NUnit.Framework;
using ReactiveUI.Testing;
using System;
using System.Threading.Tasks;
[TestFixture]
public class CacheFixture
{
[Test]
public async Task CachingTest()
{
var scheduler = new TestScheduler();
// replacing the TestScheduler with the scheduler below works
// var scheduler = CurrentThreadScheduler.Instance;
var cache = new InMemoryBlobCache(scheduler);
var someApi = new Mock<ISomeApi>();
someApi.Setup(s => s.GetSomeStrings())
.Returns(Task.FromResult("helloworld")).Verifiable();
var apiWrapper = new SomeApiWrapper(someApi.Object, cache,
TimeSpan.FromSeconds(10));
var string1 = await apiWrapper.GetSomeStrings();
someApi.Verify(s => s.GetSomeStrings(), Times.Once());
StringAssert.AreEqualIgnoringCase("helloworld", string1);
scheduler.AdvanceToMs(5000);
// without the TestScheduler, I'd have to 'wait' here
// await Task.Delay(5000);
var string2 = await apiWrapper.GetSomeStrings();
someApi.Verify(s => s.GetSomeStrings(), Times.Once());
StringAssert.AreEqualIgnoringCase("helloworld", string2);
}
}
The SomeApiWrapper uses an internal api (mocked with new Mock<ISomeApi>()) that - for simplicity's sake - just returns a string. The problem now is that the second string is never returned. The SomeApiWrapper class that handles the caching looks like this:
using Akavache;
using System;
using System.Reactive.Linq;
using System.Threading.Tasks;
public class SomeApiWrapper
{
private IBlobCache Cache;
private ISomeApi Api;
private TimeSpan Timeout;
public SomeApiWrapper(ISomeApi api, IBlobCache cache, TimeSpan cacheTimeout)
{
Cache = cache;
Api = api;
Timeout = cacheTimeout;
}
public async Task<string> GetSomeStrings()
{
var key = "somestrings";
var cachedStrings = Cache.GetOrFetchObject(key, DoGetStrings,
Cache.Scheduler.Now.Add(Timeout));
// this is the last step, after this it just keeps running
// but never returns - but only for the 2nd call
return await cachedStrings.FirstOrDefaultAsync();
}
private async Task<string> DoGetStrings()
{
return await Api.GetSomeStrings();
}
}
Debugging only leads me to the line return await cachedStrings.FirstOrDefaultAsync(); - and it never finishes after that.
When I replace the TestScheduler with the standard (CurrentThreadScheduler.Instance) and the scheduler.AdvanceToMs(5000) with await Task.Delay(5000), everything works as expected but I don't want unit tests running for multiple seconds.
A similar test, where the TestScheduler is advanced past the cache timeout also succeeds. It's just this scenario, where the cache entry should not expire in between the two method calls.
Is there something I'm doing wrong in the way I'm using TestScheduler?
This is a fairly common problem when bouncing between the Task and the IObservable paradigms. It is further exacerbated by trying to wait before moving forward in the tests.
The key problem is that you are blocking* here
return await cachedStrings.FirstOrDefaultAsync();
I say blocking in the sense that the code can not continue to process until this statement yields.
On the first run the cache can not find the key, so it executes your DoGetStrings. The issue surfaces on the second run, where the cache is populated. This time (I guess) the fetching of the cached data is scheduled. You need to invoke the request, observe the sequence, then pump the scheduler.
The corrected code is here (but requires some API changes)
[TestFixture]
public class CacheFixture
{
[Test]
public async Task CachingTest()
{
var testScheduler = new TestScheduler();
var cache = new InMemoryBlobCache(testScheduler);
var cacheTimeout = TimeSpan.FromSeconds(10);
var someApi = new Mock<ISomeApi>();
someApi.Setup(s => s.GetSomeStrings())
.Returns(Task.FromResult("helloworld")).Verifiable();
var apiWrapper = new SomeApiWrapper(someApi.Object, cache, cacheTimeout);
var string1 = await apiWrapper.GetSomeStrings();
someApi.Verify(s => s.GetSomeStrings(), Times.Once());
StringAssert.AreEqualIgnoringCase("helloworld", string1);
testScheduler.AdvanceToMs(5000);
var observer = testScheduler.CreateObserver<string>();
apiWrapper.GetSomeStrings().Subscribe(observer);
testScheduler.AdvanceByMs(cacheTimeout.TotalMilliseconds);
someApi.Verify(s => s.GetSomeStrings(), Times.Once());
StringAssert.AreEqualIgnoringCase("helloworld", observer.Messages[0].Value.Value);
}
}
public interface ISomeApi
{
Task<string> GetSomeStrings();
}
public class SomeApiWrapper
{
private IBlobCache Cache;
private ISomeApi Api;
private TimeSpan Timeout;
public SomeApiWrapper(ISomeApi api, IBlobCache cache, TimeSpan cacheTimeout)
{
Cache = cache;
Api = api;
Timeout = cacheTimeout;
}
public IObservable<string> GetSomeStrings()
{
var key = "somestrings";
var cachedStrings = Cache.GetOrFetchObject(key, DoGetStrings,
Cache.Scheduler.Now.Add(Timeout));
//Return an observerable here instead of "blocking" with a task. -LC
return cachedStrings.Take(1);
}
private async Task<string> DoGetStrings()
{
return await Api.GetSomeStrings();
}
}
This code is green and runs sub-second.

HttpClient await hangs on PostAsync with async void method

I'm still trying to wrap my head around async and I'm wondering why the following code is causing a deadlock. My use case is this: I have a service interface which attempts to abstract how the service is implemented. One of the services is an OAuth based web-service. The service interface has a method Connect() which anyone using the interface must do prior to using it.
On my client side I create my concrete service object and call Connect() in my view constructor (this is a prototype, so I'm just trying to get a proof of concept going). In the OAuth-based service, the connect call requires retrieving an access token, so it (attempts) to do this asynchronously. This Connect() call never returns, though, and the application is deadlocked (but the UI is active). I'm guessing I'm messing up and trying to synchronously use my client somewhere, but I'm not sure where.
Control
public class MainWindow
{
public MainWindow()
{
InitializeComponent();
_webService = new OAuthBasedWebService();
_webService.ShowAuthorizationPage += _webService_ShowAuthorizationPage; // this is defined on the concrete object -- i know, bad design
_webService.Connect();
}
}
OAuth based webservice
public class OAuthBasedWebService()
{
private OAuthWrapper _wrapper;
public async void Connect()
{
var uri = await _wrapper.GetAuthorizationUri();
OnShowAuthorizationPage(uri);
}
}
internal class OAuthWrapper
{
public async Task<Uri> GetAuthorizationUri()
{
var uri = await _consumer.GetAuthorizationUriAsync();
return uri;
}
}
internal class OAuthConsumer
{
public async Task<Uri> GetAuthorizationUriAsync()
{
using (var client = new HttpClient())
{
client.BaseAddress = "webservicebaseaddress";
var content = new FormUrlEncodedContent(new []
{
CreateParameter("oauth_consumer_key", "consumerkey"),
CreateParameter("oauth_consumer_secret", "consumersecret")
// etc., etc.
});
var response = await client.PostAsync("/method_path", content).ConfigureAwait(false);
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
// parse authorization uri from responseContent
return authorizationUri;
}
}
}
I know the design needs a little work but I'm trying to figure out why this is deadlocking. I'm guessing it is because _webService.Connect() is not being called asynchronously but I also cannot await that because it doesn't return anything and the rest of the program doesn't depend on it.
I'm not sure why you are using a event here, if the problem was just because you couldn't make the constructor "async" then just move the conect call to another method:
public class MainWindow
{
public MainWindow()
{
InitializeComponent();
Init();
}
public async void Init(){
_webService = new OAuthBasedWebService();
Uri uri=await _webService.Connect();
_webService_ShowAuthorizationPage(uri);
}
}
public class OAuthBasedWebService()
{
private OAuthWrapper _wrapper;
public async Task<Uri> Connect()
{
return await _wrapper.GetAuthorizationUri();
}
}

Categories

Resources