list view is unable to display data from cloud firestore - xamarin.forms

Here is my code behind
IIdentifiable is a interface that has Id as property.
I am getting a nullrefrence exceptions while extracting data.
public abstract class SalonService<T> : ISalonService<T> where T : IIdentifiable
{
public Task<T> GetSalonAsync(string id)
{
var tcs = new TaskCompletionSource<T>();
FirebaseFirestore.Instance
.Collection("salons")
.Document(id)
.Get()
.AddOnCompleteListener(new OnDocumentCompleteListener<T>(tcs));
return tcs.Task;
}
public Task<IList<T>> GetSalonsAsync()
{
var tcs = new TaskCompletionSource<IList<T>>();
var list = new List<T>();
FirebaseFirestore.Instance
.Collection("salons")
.Get()
.AddOnCompleteListener(new OnCollectionCompleteListener<T>(tcs));
return tcs.Task;
}
}
And the service listeners for collection of data
public class OnCollectionCompleteListener<T> : Java.Lang.Object, IOnCompleteListener
where T : IIdentifiable
{
private System.Threading.Tasks.TaskCompletionSource<IList<T>> _tcs;
public OnCollectionCompleteListener(System.Threading.Tasks.TaskCompletionSource<IList<T>> tcs)
{
_tcs = tcs;
}
public void OnComplete(Task task)
{
if (task.IsSuccessful)
{
var docsObj = task.Result;
if (docsObj is QuerySnapshot docs)
{
_tcs.TrySetResult(docs.Convert<T>());
}
}
}
}
Service listener to display document
public class OnDocumentCompleteListener<T> : Java.Lang.Object, IOnCompleteListener
where T : IIdentifiable
{
private TaskCompletionSource<T> _tcs;
public OnDocumentCompleteListener(TaskCompletionSource<T> tcs)
{
_tcs = tcs;
}
public void OnComplete(Task task)
{
if (task.IsSuccessful)
{
var docObj = task.Result;
if (docObj is DocumentSnapshot docRef)
{
_tcs.TrySetResult(docRef.Convert<T>());
return;
}
}
// something went wrong
_tcs.TrySetResult(default);
}
}
The Document extension as well
public static class DocumentReferenceExtensions
{
public static T Convert<T>(this DocumentSnapshot doc) where T : IIdentifiable
{
try
{
var jsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(doc.Data.ToDictionary());
var item = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(jsonStr);
item.Id = doc.Id;
return item;
}
catch (Exception)
{
System.Diagnostics.Debug.WriteLine("EXCEPTION THROWN");
}
return default;
}
public static List<T> Convert<T>(this QuerySnapshot docs) where T : IIdentifiable
{
var list = new List<T>();
foreach (var doc in docs.Documents)
{
list.Add(doc.Convert<T>());
}
return list;
}
}
Please let me know what am I missing? I am stuck here

Related

Blazor SignalR Call Wrong JSRuntime

I create Event Maped Seat reservation and using SignalR creates a realtime seat update status view
My BroadcastHub
public class BroadcastHub : Hub
{
public async Task AddToGroup(string groupName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
}
public async Task RemoveFromGroup(string groupName)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
}
public async Task SeatUpdate(long SectinId, string groupName, long SeatId, SeatStatus seatStatus)
{
await Clients.OthersInGroup(groupName).SendAsync("ReceiveSeatUpdate", SectinId, SeatId, seatStatus);
}
}
Component
<div class="col-md-12 mb-3">
#((MarkupString)#SectionData.Salon.SalonMap)
</div>
...Seat Selection Murkup....
#code {
private HubConnection hubConnection;
public bool IsConnected => hubConnection.State == HubConnectionState.Connected;
Task SeatUpdate(long SectinId, string EventId, long SeatId, SeatStatus seatStatus) => hubConnection.SendAsync("SeatUpdate", SectinId, EventId, SeatId, seatStatus);
protected override async Task OnInitializedAsync()
{
SectionData.OnChange += StateHasChanged;
SectionData.Salon = await DataService.GetSalon();
action = GetSection;
foreach (var item in salon.Sections)
{
SectionData.Salon.SalonMap =salon.SalonMap.Replace(item.Action,$"onclick='app.GetSectionCallerJS({item.Id})'");
}
#region Hub
hubConnection = new HubConnectionBuilder().WithUrl(NavigationManager.ToAbsoluteUri("/broadcastHub")).Build();
hubConnection.On("ReceiveSeatUpdate", async (long SectinId, long SeatId, SeatStatus seatStatus) =>
{
if (SectionData.Section.Id == SectinId)
{
var Seat = SectionData.Section.Seats.Values.Where(x => x.Id == SeatId).FirstOrDefault();
Seat.SeatStatus = seatStatus;
}
StateHasChanged();
});
await hubConnection.StartAsync();
await hubConnection.SendAsync("AddToGroup", EventSansUniqueId);
#endregion Hub
}
#region GetSection
private static Action<long> action;
private void GetSection(long SectionId)
{
var section= salon.Sections.Where(x => x.Id == SectionId).FirstOrDefault();
SectionData.SetSection(section);
SectionData.Section.Seats = DataService.GetSection(SectionId);
StateHasChanged();
}
[JSInvokable]
public static void GetSectionCaller(long SectionId)
{
action.Invoke(SectionId);
}
#endregion GetSection
public void Dispose()
{
SectionData.OnChange -= StateHasChanged;
if (IsConnected) hubConnection.SendAsync("RemoveFromGroup", EventSansUniqueId);
}
}
JavaScript Is
window.app = {
GetSectionCallerJS: (id) => {
DotNet.invokeMethodAsync('KishApp.TRMS.Salon', 'GetSectionCaller', id);
}
};
The problem is when the hub registers for the second, third, and... time DotNet.invokeMethodAsync Call Last registered page, not the one actually calling the method and causing the wrong page update
tanks to #MisterMango I found that problem GetSectionCaller is a static method and I must have created new DotNetObjectReference every time page initial so
DotNetObjectReference<Salon> ObjectReference;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
ObjectReference = DotNetObjectReference.Create<Salon>(this);
await JSRuntime.InvokeVoidAsync("app.setObjectReference", ObjectReference);
}
}
[JSInvokable("GetSectionCaller")]
public void GetSectionCaller(long SectionId)
{
GetSection(SectionId);
}
JavaScript
window.app = {
GetSectionCallerJS: (id) => {
dotNetObject.invokeMethodAsync('GetSectionCaller', id);
},
setObjectReference: (ObjectReference) => {
this.dotNetObject = ObjectReference;
}};

Can I replace Document DB Generic Repository with Cosmos DB SDK 3.0?

I have created generic repository for CRUD(Create,Read,Update and Delete) operations with Document DB assembly. I want to replace this with Cosmos DB SDK 3.0 SQL API.
Here is my cosmos db generic repository:
public class CosmosDBRepository<T> : ICosmosDBRepository<T> where T : class
{
private readonly DocumentClient _client;
private readonly string DatabaseId = "FleetHub";
public static string CollectionId = GetAttributeCosmoDbCollection<T>(typeof(T));
public CosmosDBRepository()
{
var endpoint = CloudConfigurationManager.GetSetting("CosmoDbEndpoint");
var authkey = CloudConfigurationManager.GetSetting("CosmoDbAuthKey");
try
{
if (endpoint == null || authkey == null)
{
throw new ArgumentNullException("CosmoDbEndpoint or CosmoDbAuthKey could not be found in the config file, check your settings.");
}
if (_client == null)
{
_client = new DocumentClient(new Uri(endpoint), authkey, connectionPolicy: new ConnectionPolicy { EnableEndpointDiscovery = false });
}
CreateDatabaseIfNotExistsAsync().Wait();
CreateCollectionIfNotExistsAsync().Wait();
}
catch (Exception e)
{
}
}
public async Task<T> GetItemAsync<T>(string id, string partitionkey) where T : class
{
try
{
Document document = await _client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id), new RequestOptions { PartitionKey = new PartitionKey(partitionkey) });
return (T)(dynamic)document;
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
else
{
throw;
}
}
}
public async Task<Document> CreateItemAsync<T>(T item) where T : class
{
return await _client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), item);
}
public async Task<IEnumerable<T>> GetItemsAsync<T>(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByDesc, int takeCount = -1)
where T : class
{
var criteria = _client.CreateDocumentQuery<T>(
UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), new FeedOptions { EnableCrossPartitionQuery = true })
.Where(predicate)
.OrderByDescending(orderByDesc)
.AsDocumentQuery();
IDocumentQuery<T> query = criteria;
List<T> results = new List<T>();
while (query.HasMoreResults)
{
if (takeCount > -1 && results.Count >= takeCount)
{
break;
}
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
}
public async Task<Document> UpdateItemAsync<T>(string id, T item) where T : class
{
return await _client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id), item);
}
private async Task CreateDatabaseIfNotExistsAsync()
{
try
{
await _client.ReadDatabaseAsync(UriFactory.CreateDatabaseUri(DatabaseId));
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
await _client.CreateDatabaseAsync(new Database { Id = DatabaseId });
}
else
{
throw;
}
}
}
private async Task CreateCollectionIfNotExistsAsync()
{
try
{
await _client.ReadDocumentCollectionAsync(
UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId));
}
catch (DocumentClientException e)
{
}
}
private string GetPartitionKeyAttributeCosmoDbCollection(Type t)
{
// Get instance of the attribute.
CosmoDBCollection attribute =
(CosmoDBCollection)Attribute.GetCustomAttribute(t, typeof(CosmoDBCollection));
if (attribute == null)
{
throw new Exception("The attribute CosmoDbCollection was not found.");
}
return attribute.PartitionKey;
}
private static string GetAttributeCosmoDbCollection<T>(Type t) where T : class
{
CosmoDBCollection attribute =
(CosmoDBCollection)Attribute.GetCustomAttribute(t, typeof(CosmoDBCollection));
return attribute.Name;
}
}
Can I Create generic repository with Cosmos DB SDK 3.0 SQL? Or I need to use Document DB assembly only for to create generic repository.
Any Thoughts?
Yes,you can.Please refer to these documents:
Quickstart: Build a .NET console app to manage Azure Cosmos DB SQL API resources
Azure Cosmos DB.NET V3 SDK (Microsoft.Azure.Cosmos) examples for the SQL API

Not displaying items from Cosmos db

I have issuse with my display method. I have been following tutorial on MSToDo items for xamarin. https://github.com/Azure-Samples/azure-cosmos-db-sql-xamarin-getting-started
I am able to insert in the database so i know it works but cant get anything out of the database. Can you help me please?
this is my get method
static DocumentClient docClient = null;
static readonly string databaseName = "xxxxx";
static readonly string collectionName = "xxxxx";
static bool Initialize() //connection
{
if (docClient != null)
return true;
try
{
docClient = new DocumentClient(new Uri(AppConstants.CosmosEndpointUrl), AppConstants.CosmosAuthKey);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
docClient = null;
return false;
}
return true;
}
public async static Task<List<Post>> GetPosts()
{
var posts = new List<Post>();
if (! Initialize())
return posts;
var postQuery = docClient.CreateDocumentQuery<Post>(
UriFactory.CreateDocumentCollectionUri(databaseName, collectionName),
new FeedOptions { MaxItemCount = 1, EnableCrossPartitionQuery = true })
.OrderBy(i => i.Date)
.AsDocumentQuery();
while (postQuery.HasMoreResults)
{
var queryResults = await postQuery.ExecuteNextAsync<Post>();
posts.AddRange(queryResults);
}
return posts;
}
public class PostViewModel : BaseViewModel
{
List<Post> posts;
public PostViewModel()
{
Posts = new List<Post>();
RefreshCommand = new Command(async () => await ExecuteRefreshCommand());
}
private PostViewModel _selectedAd;
//private ObservableCollection<Post> _posts;
public List<Post> Posts { get => posts; set { posts = value; OnPropertyChanged(); } }
public ICommand RefreshCommand { get; }
async Task ExecuteRefreshCommand()
{
if (IsBusy) return;
IsBusy = true;
try
{
Posts = await AdService.GetPosts();
}
finally
{
IsBusy = false;
}
}
}
HOmePage
PostViewModel postViewModel;
public HomePage()
{
InitializeComponent();
postViewModel = new PostViewModel();
BindingContext = postViewModel;
}
protected override void OnAppearing()
{
base.OnAppearing();
postViewModel.RefreshCommand.Execute(null);
}
And my xaml
<ListView
ItemsSource="{Binding Posts}" x:Name="AdLogListView"
ItemTemplate="{StaticResource HomePageTemplate}"
SelectionMode="Single" Margin="12,0">
The Binding Source Path should be Posts and not Post. Your modified xaml would be:-
<ListView
ItemsSource="{Binding Posts}" x:Name="AdLogListView"
ItemTemplate="{StaticResource HomePageTemplate}"
SelectionMode="Single" Margin="12,0">

Issue getting NullReferenceException using Http with jwt Xamarin Forms Android

So my code works in PostMan querying the api to populate a listview locally in my Android app. But when I run it from within the app, I get NullReferenceException on the line "Items.Clear() in ShipViewModel.cs
I tried hardcoding the address rather than using my APIQueriable path, I tried generating new JWT, and I tried manually cleaning my /bin /obj folders to rule out code not compiling correctly.
ShipsViewModel.cs Xamarin.Forms/ViewModels
{
private GallogClient _gallogClient;
public ObservableCollection<ShipCatalog> Items { get; set; }
public Command LoadItemsCommand { get; }
public ShipsViewModel()
{
Title = "Ships";
_gallogClient = new GallogClient("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9hcGkuZ2FsbG9nLmNvIiwiYXVkIjoiaHR0cDpcL1wvYXBpLmdhbGxvZy5jbyIsImlhdCI6MTM1Njk5OTUyNCwibmJmIjoxMzU3MDAwMDAwLCJkYXRhIjp7ImlkIjo1NywidXNlcm5hbWUiOiJQYXJhIiwiaGFuZGxlIjoiUGFyYSIsImVtYWlsIjoicGFyYWJvbGE5NDlAZ21haWwuY29tIn19.bRpI9hVy-Spky5pbZhJCkyN-MT9RA6ap_yD9ezRxCxo");
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand(), () => !IsBusy);
}
async Task ExecuteLoadItemsCommand()
{
if (IsBusy)
return;
IsBusy = true;
try
{
LoadItemsCommand.ChangeCanExecute();
Items.Clear();
var items = await _gallogClient.GetItemsAsync<ShipList>();
foreach (var item in items.ships.ToList())
{
Items.Add(item);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
}
}
GallogClient.cs Gallog.API
{
internal readonly HttpClient Client = new HttpClient { BaseAddress = new Uri("https://api.gallog.co/api/") };
public string Jwt { get; set; }
public GallogClient()
{
}
public GallogClient(string jwt)
{
Jwt = jwt;
}
private StringContent JwtContent
{
get {
return new StringContent(JsonConvert.SerializeObject(new
{
jwt = Jwt
}), Encoding.UTF8, "application/json");
}
}
//...
public async Task<T> GetItemAsync<T>(string name) where T : ApiQueryable
{
return await PostAsync<T>($"{GetPath<T>()}/{name}");
}
public async Task<T> GetItemsAsync<T>() where T : ApiQueryable
{
return await PostAsync<T>($"{GetPath<T>()}");
}
internal string GetPath<T>()
{
if (typeof(T).GetCustomAttributes(
typeof(ApiPathAttribute), true
).FirstOrDefault() is ApiPathAttribute at)
{
return at.Path;
}
return null;
}
public async Task<T> PostAsync<T>(string path) where T : ApiQueryable
{
var response = await Client.PostAsync(path, JwtContent);
return JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
}
public async Task<T> PostAsync<T>(object body, string path) where T : ApiQueryable
{
var response = await Client.PostAsync(path,
new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"));
return JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
}
}
}
ShipList.cs Xamarin.Forms/Models
{
[ApiPath("ships")]
public class ShipList : ApiQueryable
{
public ShipCatalog[] ships { get; set; }
}
public class ShipCatalog
{
public int id { get; set; }
public string name { get; set; }
// ...etc etc
}
}
Items is null because you declared it but have never initialized it
public ShipsViewModel()
{
...
Items = new ObservableCollection<ShipCatalog>();
...
}

Couchbase async data

I have written code to get async data from Couchbase views:
This is the Implementation Class
AsyncViewResult viewResult =
offerCouchDao.findViewResultAsync(DDN, VIEWNAME).toBlocking().single();
if (viewResult.success()) {
Observable<JsonArray> JAoffer =
offerCouchDao.getAsyncJsonObject(viewResult.rows());
Object response = offerCouchDao.getData(JAoffer);
System.out.println("Data is "+response);
return new OfferResponse(true,"Offer Data",response).toJson();
}
This is OfferCouchDao:
public Observable<AsyncViewResult> findViewResultAsync(String ddn, String viewname) {
ViewQuery allResult = ViewQuery.from(ddn, viewname);
return couchbaseManager.getMobikwikBucket().async().query(allResult);
}
public Observable<JsonArray> getAsyncJsonObject(Observable<AsyncViewRow> viewResult) {
return viewResult.
//extract the document from the row and carve a result object using its content and id
flatMap(new Func1<AsyncViewRow, Observable<JsonObject>>() {
#Override
public Observable<JsonObject> call(AsyncViewRow row) {
return row.document().map(new Func1<JsonDocument, JsonObject>() {
#Override
public JsonObject call(JsonDocument jsonDocument) {
return JsonObject.create()
.put("id", jsonDocument.id())
;
}
})
;
}
}).filter(new Func1<JsonObject, Boolean>() {
#Override
public Boolean call(JsonObject jsonObject) {
String name = jsonObject.getString("name");
return name != null ;
}
})
.collect(new Func0<JsonArray>() { //this creates the array (once)
#Override
public JsonArray call() {
return JsonArray.empty();
}
}, new Action2<JsonArray, JsonObject>() { //this populates the array (each item)
#Override
public void call(JsonArray objects, JsonObject jsonObject) {
objects.add(jsonObject);
}
});
}
public Object getData(Observable<JsonArray> jsonArraay) {
return jsonArraay
.map(new Func1<JsonArray, JsonArray>() {
#Override
public JsonArray call(JsonArray objects) {
return objects;
}
})
.onErrorReturn(new Func1<Throwable, JsonArray>() {
#Override
public JsonArray call(Throwable throwable) {
return null;
}
})
.toBlocking().single();
}
The issue I have is Data returned is null
Here are the logs:
Data is []
Data is null
Also when doing via sync call which is:
else {
JsonArray keys = JsonArray.create();
Iterator<ViewRow> iter = viewResult.rows();
while (iter.hasNext()) {
ViewRow row = iter.next();
JsonObject beer = JsonObject.create();
beer.put("name", row.key());
beer.put("id", row.id());
keys.add(beer);
}
}
I am getting the expected response.
Can Someone help me?

Resources