How to Get Cosmos Db Data in Azure Mobile App Service - c#

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.

Related

Error while reading data from database in c#

I have an error in this code. I deserialize a JSON file and stored that data in the database now I want to show that data from my database.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web.Helpers;
using System.Web.Mvc;
using ReadingFromDb.Dto;
namespace ReadingFromDb.Controller
{
public class StudentController
{
[HttpGet]
[AllowAnonymous]
public async Task<JsonResult> GetStudents()
{
using (var context = new UNIEntities1())
{
var query = #"Select ";
var dbQuery = context.Database.SqlQuery<StudentDto>(query);
var list = await dbQuery.ToListAsync();
return Json(list,JsonRequestBehavior.AllowGet);
}
}
}
}
Error is:
JSON can not be used like method.
What should I do?
Your contoller must be extend the base class Controller in which the Json() virtual method is available:
public class StudentController : Controller
{
// your code
}
To resolve this error you can try as below
public class StudentController : Controller
{
// your code
}
[HttpGet]
[AllowAnonymous]
public async Task<JsonResult> GetStudents()
{
using (var context = new UNIEntities1())
{
var list = await context.StudentDto.ToListAsync();
return Json(list,JsonRequestBehavior.AllowGet);
}
}
What you need to do is to extend your StudentCotroller with Controller then put your code under that.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web.Helpers;
using System.Web.Mvc;
using ReadingFromDb.Dto;
namespace ReadingFromDb.Controller
{
public class StudentController:Controller
{
[HttpGet]
[AllowAnonymous]
public async Task<JsonResult> GetStudents()
{
using (var context = new UNIEntities1())
{
var query = #"Select ";
var dbQuery = context.Database.SqlQuery<StudentDto>(query);
var list = await dbQuery.ToListAsync();
return Json(list,JsonRequestBehavior.AllowGet);
}
}
}
}

ASP.Net MVC C#: Failed to acquire token silently as no token was found in the cache. Call method AcquireToken

I am attempting to retrieve Azure AD user profile data via the Microsoft Graph API. I have set up a small Visual Studio MVC app using code examples from various sources, primarily Microsoft. In my ignorance, I thought this would be a fairly simple process.
I have browsed other similar cases on SO and have attempted to make use of suggestions from others but to no avail. I have been troubleshooting this issue for four days and would greatly appreciate any assistance.
// UserProfileController.cs
-- contains the calling method: var graphToken = await AuthenticationHelper.GetGraphAccessToken();
//
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Security.Claims;
using System.Web;
using System.Web.Mvc;
using System.Threading.Tasks;
using Microsoft.Graph;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using SSO_Test.Models;
using SSO_Test.Utils;
using System.Net.Http.Headers;
namespace SSO_Test.Controllers
{
[Authorize]
public class UserProfileController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
private string clientId = ConfigurationManager.AppSettings["ClientId"];
private string appKey = ConfigurationManager.AppSettings["ClientSecret"];
private string aadInstance = ConfigurationManager.AppSettings["AADInstance"];
private string graphResourceID = "https://graph.microsoft.com";
// GET: UserProfile
public async Task<ActionResult> Index()
{
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
try
{
var graphToken = await AuthenticationHelper.GetGraphAccessToken();
var authenticationProvider = new DelegateAuthenticationProvider(
(requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", graphToken);
return Task.FromResult(0);
});
var graphClient = new GraphServiceClient(authenticationProvider);
var user = await graphClient.Me.Request().GetAsync();
return View(user);
}
catch (AdalException ex)
{
// Return to error page.
ViewBag.Message = ex.Message;
return View("Error");
}
// if the above failed, the user needs to explicitly re-authenticate for the app to obtain the required token
catch (Exception)
{
return View("Relogin");
}
}
public void RefreshSession()
{
HttpContext.GetOwinContext().Authentication.Challenge(
new AuthenticationProperties { RedirectUri = "/Home" },
OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
}
}
//AuthenticationHelper.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using SSO_Test.Models;
namespace SSO_Test.Utils
{
public static class AuthenticationHelper
{
public static async Task<string> GetGraphAccessToken()
{
var signInUserId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
var userObjectId = ClaimsPrincipal.Current.FindFirst(SettingsHelper.ClaimTypeObjectIdentifier).Value;
var clientCredential = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.ClientSecret);
var userIdentifier = new UserIdentifier(userObjectId, UserIdentifierType.UniqueId);
// create auth context
AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.AzureAdAuthority, new ADALTokenCache(signInUserId));
//added check point for verification purposes
System.Diagnostics.Debug.WriteLine("Check point #1");
//GOOD TO THIS POINT
var result = await authContext.AcquireTokenSilentAsync(SettingsHelper.AzureAdGraphResourceURL, clientCredential, userIdentifier);
//ERROR MESSAGE: "Failed to acquire token silently as no token was found in the cache. Call method AcquireToken"
System.Diagnostics.Debug.WriteLine("Check point #2");
//app never reaches the second check point
return result.AccessToken;
}
}
}
//ADALTokenCache.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Security;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
namespace SSO_Test.Models
{
public class ADALTokenCache : TokenCache
{
private ApplicationDbContext db = new ApplicationDbContext();
private string userId;
private UserTokenCache Cache;
public ADALTokenCache(string signedInUserId)
{
// associate the cache to the current user of the web app
userId = signedInUserId;
this.BeforeAccess = BeforeAccessNotification;
this.AfterAccess = AfterAccessNotification;
this.BeforeWrite = BeforeWriteNotification;
// look up the entry in the database
Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
// place the entry in memory
this.DeserializeAdalV3((Cache == null) ? null : MachineKey.Unprotect(Cache.cacheBits, "ADALCache"));
}
// clean up the database
public override void Clear()
{
base.Clear();
var cacheEntry = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
db.UserTokenCacheList.Remove(cacheEntry);
db.SaveChanges();
}
// Notification raised before ADAL accesses the cache.
// This is your chance to update the in-memory copy from the DB, if the in-memory version is stale
void BeforeAccessNotification(TokenCacheNotificationArgs args)
{
if (Cache == null)
{
// first time access
Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
}
else
{
// retrieve last write from the DB
var status = from e in db.UserTokenCacheList
where (e.webUserUniqueId == userId)
select new
{
LastWrite = e.LastWrite
};
// if the in-memory copy is older than the persistent copy
if (status.First().LastWrite > Cache.LastWrite)
{
// read from from storage, update in-memory copy
Cache = db.UserTokenCacheList.FirstOrDefault(c => c.webUserUniqueId == userId);
}
}
this.DeserializeAdalV3((Cache == null) ? null : MachineKey.Unprotect(Cache.cacheBits, "ADALCache"));
}
// Notification raised after ADAL accessed the cache.
// If the HasStateChanged flag is set, ADAL changed the content of the cache
void AfterAccessNotification(TokenCacheNotificationArgs args)
{
// if state changed
if (this.HasStateChanged)
{
Cache = new UserTokenCache
{
webUserUniqueId = userId,
//cacheBits = MachineKey.Protect(this.Serialize(), "ADALCache"),
cacheBits = MachineKey.Protect(this.SerializeAdalV3(), "ADALCache"),
LastWrite = DateTime.Now
};
// update the DB and the lastwrite
db.Entry(Cache).State = Cache.UserTokenCacheId == 0 ? EntityState.Added : EntityState.Modified;
db.SaveChanges();
this.HasStateChanged = false;
}
}
void BeforeWriteNotification(TokenCacheNotificationArgs args)
{
// if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry
}
public override void DeleteItem(TokenCacheItem item)
{
base.DeleteItem(item);
}
}
}
//ApplicationDbContext.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace SSO_Test.Models
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public DbSet<UserTokenCache> UserTokenCacheList { get; set; }
}
public class UserTokenCache
{
[Key]
public int UserTokenCacheId { get; set; }
public string webUserUniqueId { get; set; }
public byte[] cacheBits { get; set; }
public DateTime LastWrite { get; set; }
}
}
As you can see, I have noted in the GetGraphAccessToken() method the error message:
"Failed to acquire token silently as no token was found in the cache.
Call method AcquireToken".
I was able to isolate the AcquireTokenSilentAsync() method as the culprit by bracketing it with a pair of Debug.Writeline statements, the first which ran successfully and the second which did not. This was verified by reviewing the contents of the VS Output window, as follows:
Check point #1
Exception thrown:
'Microsoft.IdentityModel.Clients.ActiveDirectory.AdalSilentTokenAcquisitionException'
in mscorlib.dll
The program '[13980] iisexpress.exe' has exited with code -1
(0xffffffff).
I really want this thing to work and I would much prefer utilizing the Graph SDK approach as opposed to using a REST API.
Again, I have been banging my head against the wall for four-plus days. My head is okay but the wall is in bad shape.
Thanks in advance.
If AcquireTokenSilent fails, it means that there is no token in the cache so you have to go get one via AcquireToken as in this.
You've tagged the question with "B2C" but is looks like you are using Azure AD?
There are a full set of Authentication Providers for the standard set of OAuth flows that are now available so you don't have to use the DelegatedAuthenticationProvider any more. https://github.com/microsoftgraph/msgraph-sdk-dotnet-auth There are docs about how to chose the right Auth provider based on scenario here https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS

Why does Redis C# client method .getById() return null?

I'm building a simple blog application in Asp.Net MVC and I want to use a Redis database.
I have created a repository for my Users class that contains a few methods (create, getbyid and update). The probelm is the GetById(long id) method.
using System;
using System.Collections.Generic;
using System.Text;
using ServiceStack.Redis;
using Domain.Entities;
using RedisDataLayer.AbstractRepository;
using System.Linq;
namespace RedisDataLayer.ConcreteRepository
{
public class UserRepository : IUserRepository
{
private readonly IRedisClient _redisClient;
public UserRepository(IRedisClient redisClient)
{
_redisClient = redisClient;
}
public User Create(User user)
{
var redisUsers = _redisClient.As<User>();
user.UserId = redisUsers.GetNextSequence();
redisUsers.Store(user);
return user;
}
public User GetById(long id)
{
var redisUsers = _redisClient.As<User>();
User returnUser;
returnUser = redisUsers.GetById(id);
return returnUser;
}
public User Update(User user)
{
var redisUsers = _redisClient.As<User>();
User savedUser = redisUsers.GetById(user.UserId);
savedUser.Username = user.Username;
savedUser.Password = user.Password;
savedUser.UserId = user.UserId;
foreach (var blogId in user.BlogIds)
{
savedUser.BlogIds.Add(blogId);
}
redisUsers.Store(savedUser);
return savedUser;
}
}
}
Why does this method returnUser = redisUsers.GetById(id); always return null? I've been trying to find an answer on StackOverflow and other places but I couldn't.
The GetById() API (and all other ServiceStack.Redis Typed Client APIs) expect the POCOs to have a unique Id in an Id property.
So you should change your User model to use Id instead of UserId.

How can I complete this REST implementation?

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.

C# Web Api GetAsync + MVC 3.0 Async Controller

I just want everyones feedback about the following Async Controller using the Web Api HttpClient. This looks very messy is there a way to make it cleaner? Does anyone have a good wrapper around chaining multiple async tasks together?
public class HomeController : AsyncController
{
public void IndexAsync()
{
var uri = "http://localhost:3018/service";
var httpClient = new HttpClient(uri);
AsyncManager.OutstandingOperations.Increment(2);
httpClient.GetAsync(uri).ContinueWith(r =>
{
r.Result.Content.ReadAsAsync<List<string>>().ContinueWith(b =>
{
AsyncManager.Parameters["items"] = b.Result;
AsyncManager.OutstandingOperations.Decrement();
});
AsyncManager.OutstandingOperations.Decrement();
});
}
public ActionResult IndexCompleted(List<string> items)
{
return View(items);
}
}
You seem to be using a bit to many async calls and AsyncManager.OutstandingOperations.Decrement(). The following code is enough to load the Flickr photo information asynchronously using YQL.
public class HomeController : AsyncController
{
public void IndexAsync()
{
var uri = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20flickr.photos.recent";
var httpClient = new HttpClient(uri);
AsyncManager.OutstandingOperations.Increment();
httpClient.GetAsync("").ContinueWith(r =>
{
var xml = XElement.Load(r.Result.Content.ContentReadStream);
var owners = from el in xml.Descendants("photo")
select (string)el.Attribute("owner");
AsyncManager.Parameters["owners"] = owners;
AsyncManager.OutstandingOperations.Decrement();
});
}
public ActionResult IndexCompleted(IEnumerable<string> owners)
{
return View(owners);
}
}
You may take a look at http://pfelix.wordpress.com/2011/08/05/wcf-web-api-handling-requests-asynchronously/.
It contains an example based on the task iterator technique ( http://blogs.msdn.com/b/pfxteam/archive/2009/06/30/9809774.aspx ) for chaining async operations.

Categories

Resources