I have a service, which works with external resource (Microsoft Graph):
public class Office365DomainService : IOffice365DomainService
{
private GraphServiceClient _graphClient;
public async Task AddDomainAsync(string domain)
{
await _graphClient.Domains.Request().AddAsync(new Microsoft.Graph.Domain { Id = domain });
}
public async Task<string> GetMxRecordForDomainAsync(string domain)
{
var collection = await _graphClient.Domains[domain].ServiceConfigurationRecords.Request().GetAsync();
return String.Empty;
}
public async Task<string> GetVerificationRecordForDomainAsync(string domain)
{
var records = (await _graphClient.Domains[domain].VerificationDnsRecords.Request().GetAsync());
string verificationText = String.Empty;
foreach (var record in records)
{
if (record.RecordType == "Txt")
{
verificationText = ((Microsoft.Graph.DomainDnsTxtRecord)record).Text;
break;
}
}
return verificationText;
}
public async Task VerifyDomainAsync(string domain)
{
await _graphClient.Domains[domain].Verify().Request().PostAsync();
}
}
_graphClient should be init with access_token, but I want to have lazy loading, therefore I don't want to add it to constructor.
Ok, one solution is add a property:
public string AccessToken { set => _graphClient = (new GraphSdkHelper()).GetAuthenticatedClient(value); }
It works fine, if we remember to set AccessToken before calling any method. But if we forget to do it? The best way it is to call getting access_token by another service if this _graphClient is not init. How to do it carefully?
Why not use Lazy Initialization ?
Please take a look at the docs here
Related
I'm trying to write Api's using xamarion and do crud Operation in firebase real time database, But this is my first time to deal with it now i want to test this api's without need to write xaml code and create form for example, How can I do it ? in node js and web development we use postman, here what we can do ?
this is my code for example :
public async Task<bool> Save(Specalist specalist)
{
var data = await firebaseClient.Child(nameof(Specalist)).PostAsync(JsonConvert.SerializeObject(specalist));
if (string.IsNullOrEmpty(data.Key))
{
return true;
}
return false;
}
public async Task<List<Specalist>> GetAll()
{
return (await firebaseClient.Child(nameof(Specalist)).OnceAsync<Specalist>()).Select(item => new Specalist
{
Email = item.Object.Email,
Name = item.Object.Name,
ID = item.Object.ID
}).ToList();
}
public async Task<bool> Update(Specalist specalist)
{
await firebaseClient.Child(nameof(Specalist)+"/"+specalist.ID).PatchAsync(JsonConvert.SerializeObject(specalist));
return true;
}
public async Task<bool> Delete(string id)
{
await firebaseClient.Child(nameof(Specalist)+"/"+id).DeleteAsync();
return true;
}
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*/)
I have a WebApi controller which calls a third party API in asynchronous mode.
All works ok and now I want to sort the result in a separate action method.
Now, when I call the API, the callback with the result never happens after running "await client.GetAsycn(...)" in the DAL. What am I missing?
This is my API controller:
// GET api/lookup
[ResponseType(typeof(RestaurantModel))]
public async Task<IHttpActionResult> Get(string outcode)
{
if (string.IsNullOrEmpty(outcode)) throw new ArgumentNullException(nameof(outcode));
var result = await _repository.GetRestaurantsByOutcode(outcode);
return Ok(new RestaurantModel()
{
Result = result
});
}
// GET api/sorted
[System.Web.Http.Route("~/api/sorted")]
public List<Restaurant> GetSorted(string outcode)
{
if (string.IsNullOrEmpty(outcode)) throw new ArgumentNullException(nameof(outcode));
return _repository.GetSortedRestaurantsByOutcode(outcode);
}
This is my repository with a new method to sort the result:
public class RestaurantRepository : IRestaurantRepository
{
private readonly IContext _context;
public RestaurantRepository(IContext context)
{
_context = context;
}
public Task<ApiResult> GetRestaurantsByOutcode(string outcode)
{
return _context.GetRestaurantsByOutcode(outcode);
}
public List<Restaurant> GetSortedRestaurantsByOutcode(string outcode)
{
return _context.GetRestaurantsByOutcode(outcode).Result.Restaurants
.OrderBy(x => x.Name).ToList();
}
}
This is my DAL to call the third party API:
public async Task<ApiResult> GetRestaurantsByOutcode(string outcode)
{
using (var client = new HttpClient())
{
ConfigureHttpClient(client);
var response = await client.GetAsync(
$"restaurants?q={WebUtility.UrlEncode(outcode)}");
return response.IsSuccessStatusCode
? await response.Content.ReadAsAsync<ApiResult>()
: null;
}
}
You have a mix-match of sometimes you use async/await and other times you don't. Async / await (can and does by default) ensures that the call resumes on the calling thread so the context is resulted. You need to allign your code so you make use of the async/await in the whole stack. Otherwise you are creating a deadlock for your self.
[System.Web.Http.Route("~/api/sorted")]
// missing async in signature (not good if you are calling it with await in your controller)
public async Task<List<Restaurant>> GetSorted(string outcode)
{
if (string.IsNullOrEmpty(outcode)) throw new ArgumentNullException(nameof(outcode));
// added await in call
return await _repository.GetSortedRestaurantsByOutcode(outcode);
}
DAL
public class RestaurantRepository : IRestaurantRepository
{
private readonly IContext _context;
public RestaurantRepository(IContext context)
{
_context = context;
}
// added async and await
public async Task<ApiResult> GetRestaurantsByOutcode(string outcode)
{
return await _context.GetRestaurantsByOutcode(outcode);
}
// added async and await
public async Task<List<Restaurant>> GetSortedRestaurantsByOutcode(string outcode)
{
// here you were not using await but then using result even though you were calling into a method marked as async which in turn used an await. this is where you deadlocked but this the fix.
return (await _context.GetRestaurantsByOutcode(outcode)).Restaurants
.OrderBy(x => x.Name).ToList();
}
}
My Question: How do I do this?
So, I hadn't touched anything .Net in about 6 years until this week. There's a lot that I've forgotten and even more that I never knew and while I love the idea of the async/await keywords, I'm having a slight problem implementing the following requirements for a client's API implementation:
The ServerAPI class has a method for each of the API methods, taking appropriate input parameters (e.g. the method Login takes in an id and a password, makes the API call and returns the result to the caller).
I want to abstract away the JSON so that my API methods return the actual object you're fetching (e.g. the Login method above returns a User object with your auth token, uid, etc.)
Some API methods return a 204 on success or no meaningful content (not meaningful in my usecase maybe I only care about success/failure), for these I'd like to return either a bool (true = success) or the status code.
I'd like to keep the async/await (or equivalent) design, because it seems to really work well so far.
For some methods, I might need to just return the HttpResponseMessage object and let the caller deal with it.
This is roughly what I have so far and I'm not sure how to make it compliant with the above OR whether I'm even doing this right. Any guidance is appreciated (flaming, however, is not).
// 200 (+User JSON) = success, otherwise APIError JSON
internal async Task<User> Login (string id, string password)
{
LoginPayload payload = new LoginPayload() { LoginId = id, Password = password};
var request = NewRequest(HttpMethod.Post, "login");
JsonPayload<LoginPayload>(payload, ref request);
return await Execute<Account>(request, false);
}
// 204: success, anything else failure
internal async Task<Boolean> LogOut ()
{
return await Execute<Boolean>(NewRequest(HttpMethod.Delete, "login"), true);
}
internal async Task<HttpResponseMessage> GetRawResponse ()
{
return await Execute<HttpResponseMessage>(NewRequest(HttpMethod.Get, "raw/something"), true);
}
internal async Task<Int32> GetMeStatusCode ()
{
return await Execute<Int32>(NewRequest(HttpMethod.Get, "some/intstatus"), true);
}
private async Task<RESULT> Execute<RESULT>(HttpRequestMessage request, bool authenticate)
{
if (authenticate)
AuthenticateRequest(ref request); // add auth token to request
var tcs = new TaskCompletionSource<RESULT>();
var response = await client.SendAsync(request);
// TODO: If the RESULT is just HTTPResponseMessage, the rest is unnecessary
if (response.IsSuccessStatusCode)
{
try
{
// TryParse needs to handle Boolean differently than other types
RESULT result = await TryParse<RESULT>(response);
tcs.SetResult(result);
}
catch (Exception e)
{
tcs.SetException(e);
}
}
else
{
try
{
APIError error = await TryParse<APIError>(response);
tcs.SetException(new APIException(error));
}
catch (Exception e)
{
tcs.SetException(new APIException("Unknown error"));
}
}
return tcs.Task.Result;
}
This is the APIError JSON structure (it's the status code + a custom error code).
{
"status": 404,
"code":216,
"msg":"User not found"
}
I would prefer to stay with System.Net, but that's mostly because I don't want to switch all my code over. If what I want is easier done in other ways then it's obviously worth the extra work.
Thanks.
Here is an example of how I've done it using MVC API 2 as backend. My backend returns a json result if the credentials are correct. UserCredentials class is the exact same model as the json result. You will have to use System.Net.Http.Formatting which can be found in the Microsoft.AspNet.WebApi.Client NugetPackage
public static async Task<UserCredentials> Login(string username, string password)
{
string baseAddress = "127.0.0.1/";
HttpClient client = new HttpClient();
var authorizationHeader = Convert.ToBase64String(Encoding.UTF8.GetBytes("xyz:secretKey"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authorizationHeader);
var form = new Dictionary<string, string>
{
{ "grant_type", "password" },
{ "username", username },
{ "password", password },
};
var Response = await client.PostAsync(baseAddress + "oauth/token", new FormUrlEncodedContent(form));
if (Response.StatusCode == HttpStatusCode.OK)
{
return await Response.Content.ReadAsAsync<UserCredentials>(new[] { new JsonMediaTypeFormatter() });
}
else
{
return null;
}
}
and you also need Newtonsoft.Json package.
public class UserCredentials
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
//more properties...
}
i would use a Deserializer.
HttpResponseMessage response = await client.GetAsync("your http here");
var responseString = await response.Content.ReadAsStringAsync();
[Your Class] object= JsonConvert.DeserializeObject<[Your Class]>(responseString.Body.ToString());
So, first to address the you need Newtonsoft.Json comments, I really haven't felt the need yet. I've found the built in support to work well so far (using the APIError Json in my original question:
[DataContract]
internal class APIError
{
[DataMember (Name = "status")]
public int StatusCode { get; set; }
[DataMember (Name = "code")]
public int ErrorCode { get; set; }
}
I have also defined a JsonHelper class to (de)serialize:
public class JsonHelper
{
public static T fromJson<T> (string json)
{
var bytes = Encoding.Unicode.GetBytes (json);
using (MemoryStream mst = new MemoryStream(bytes))
{
var serializer = new DataContractJsonSerializer (typeof (T));
return (T)serializer.ReadObject (mst);
}
}
public static string toJson (object instance)
{
using (MemoryStream mst = new MemoryStream())
{
var serializer = new DataContractJsonSerializer (instance.GetType());
serializer.WriteObject (mst, instance);
mst.Position = 0;
using (StreamReader r = new StreamReader(mst))
{
return r.ReadToEnd();
}
}
}
}
The above bits I already had working. As for a single method that would handle each request execution based on the type of result expected while it makes it easier to change how I handle things (like errors, etc), it also adds to the complexity and thus readability of my code. I ended up creating separate methods (all variants of the Execute method in the original question:
// execute and return response.StatusCode
private static async Task<HttpStatusCode> ExecuteForStatusCode (HttpRequestMessage request, bool authenticate = true)
// execute and return response without processing
private static async Task<HttpResponseMessage> ExecuteForRawResponse(HttpRequestMessage request, bool authenticate = true)
// execute and return response.IsSuccessStatusCode
private static async Task<Boolean> ExecuteForBoolean (HttpRequestMessage request, bool authenticate = true)
// execute and extract JSON payload from response content and convert to RESULT
private static async Task<RESULT> Execute<RESULT>(HttpRequestMessage request, bool authenticate = true)
I can move the unauthorized responses (which my current code isn't handling right now anyway) into a new method CheckResponse that will (for example) log the user out if a 401 is received.
I'm trying to make a very simple implementation of an IUserStore that would essentially:
use NHibernate
save users in a single table (no claims/logins)
store role names in the same table, in an nvarchar column (pipe ('|')
separated if multiple items).
When I run the following method:
[Fact]
public void Create_A_User()
{
// _session is a valid NHibernate ISession object
using (var userStore = new SimpleUserStore<SimpleIdentityUser>(_session))
using (var userManager = new UserManager<SimpleIdentityUser>(userStore))
{
var user = new SimpleIdentityUser
{
UserName = "kenny_mccormick",
RolesStr = "admin",
};
var createTask = userManager.CreateAsync(user, "the_password");
var result = createTask.Result; // this never finishes...
}
}
the last line would never finish executing.
The weird thing is that the UserManager never calls any of the functions in my SimpleUserStore; it gets stuck before that.
Here are the components I defined:
The user class:
public class SimpleIdentityUser : IUser
{
public virtual Guid UserId { get; set; }
public virtual string PasswordHash { get; set; }
public virtual string SecurityStamp { get; set; }
public virtual string RolesStr { get; set; }
public virtual string UserName { get; set; }
public virtual string Id
{
get { return UserId.ToString(); }
}
}
The User Store:
public class SimpleUserStore<TUser> :
IUserPasswordStore<TUser>,
IUserRoleStore<TUser>,
IUserSecurityStampStore<TUser>
where TUser : SimpleIdentityUser
{
// ReSharper disable once StaticFieldInGenericType
private static readonly Task EmptyTask = new Task(() => { });
private readonly ISession _session;
public SimpleUserStore(ISession session)
{
_session = session;
}
public Task<TUser> FindAsync(UserLoginInfo login)
{
return Task.FromResult((TUser) null);
}
public Task CreateAsync(TUser user)
{
_session.Save(user);
return EmptyTask;
}
public Task UpdateAsync(TUser user)
{
// updates will (hopefully) be saved automatically when the current session is committed
return EmptyTask;
}
public Task DeleteAsync(TUser user)
{
_session.Delete(user);
return EmptyTask;
}
public Task<TUser> FindByIdAsync(string userId)
{
TUser user = null;
Guid guidId;
if (Guid.TryParse(userId, out guidId))
user = _session.Get<TUser>(guidId);
return Task.FromResult(user);
}
public Task<TUser> FindByNameAsync(string userName)
{
TUser user = _session.Query<TUser>().SingleOrDefault(u => u.UserName == userName);
return Task.FromResult(user);
}
public Task SetPasswordHashAsync(TUser user, string passwordHash)
{
user.PasswordHash = passwordHash;
return EmptyTask;
}
public Task<string> GetPasswordHashAsync(TUser user)
{
return Task.FromResult(user.PasswordHash);
}
public Task<bool> HasPasswordAsync(TUser user)
{
return Task.FromResult(user.PasswordHash != null);
}
public void Dispose()
{
}
public Task AddToRoleAsync(TUser user, string role)
{
new SimpleRoleManager<TUser>(user).AddRole(role);
return EmptyTask;
}
public Task RemoveFromRoleAsync(TUser user, string role)
{
new SimpleRoleManager<TUser>(user).DeleteRole(role);
return EmptyTask;
}
public Task<IList<string>> GetRolesAsync(TUser user)
{
List<string> roles = new SimpleRoleManager<TUser>(user).GetRoles().ToList();
return Task.FromResult((IList<string>) roles);
}
public Task<bool> IsInRoleAsync(TUser user, string role)
{
return Task.FromResult(new SimpleRoleManager<TUser>(user).IsInRole(role));
}
public Task SetSecurityStampAsync(TUser user, string stamp)
{
user.SecurityStamp = stamp;
return EmptyTask;
}
public Task<string> GetSecurityStampAsync(TUser user)
{
return Task.FromResult(user.SecurityStamp);
}
}
How I manage roles
Probably not so important, but here it is anyway:
public class SimpleRoleManager<TUser> where TUser : SimpleIdentityUser
{
private const string Separator = "|";
private readonly TUser _user;
public SimpleRoleManager(TUser user)
{
_user = user;
}
public string[] GetRoles()
{
return (_user.RolesStr ?? String.Empty)
.Split(Separator.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
}
public bool IsInRole(string roleName)
{
return GetRoles().Contains(roleName);
}
public bool AddRole(string roleName)
{
var roles = GetRoles().ToList();
if (roles.Contains(roleName))
return false;
roles.Add(roleName);
SetRoles(roles);
return true;
}
public bool DeleteRole(string roleName)
{
List<string> roles = GetRoles().ToList();
if (!roles.Contains(roleName))
return false;
roles.Remove(roleName);
SetRoles(roles);
return true;
}
private void SetRoles(IEnumerable<string> roles)
{
_user.RolesStr = String.Join(Separator, roles);
}
}
I have been inspecting the UserManager<TUser> class with DotPeek, but found no obvious causes for this weird behavior.
What could be causing this?
Your approach to async is fundamentally broken at the moment, because you're returning the same task for all operations... and never starting it. I don't see any "infinite loop" here - I just see you blocking on a task which can never complete.
It's not clear what you hope to accomplish with your EmptyTask task, but it's definitely not helping you at the moment.
Furthermore, it's not clear that your code is really asynchronous in any aspect, unless _session.Save (etc) are really asynchronous.
You could improve things somewhat by just running extra tasks, e.g.
public Task CreateAsync(TUser user)
{
Action action = () => _session.Save(user);
return Task.Run(action);
}
... although the fact that you're then immediately blocking on the task in the calling code makes it pointless, too. (It's not even clear how this compiles at the moment, as Task doesn't have a Result property... only Task<T> does.)
As noted in comments, this will create a new task which will effectively run synchronously in a new thread - using more threads than you'd otherwise need, with the potential benefit of parallelism. It doesn't achieve the same goals as a properly asynchronous database call (where there wouldn't be any threads tied up for the save call - just a task which would complete when the relevant network response was returned).
If you don't really care about it being asynchronous, you can use:
public Task CreateAsync(TUser user)
{
_session.Save(user);
return Task.FromResult<object>(null);
}
This will synchronously save (just like your current code does) but then return a completed task (rather than the task which will never complete, as per your current code).