I have a Xamarin project which consumes an Api. I have an entity CrProduct and on my database I store 1000 products but the limit I set on my Api per page is 50.
My Api Response returns 2 entities, Data and Meta.
Here's my Meta entity
public class Meta
{
public int TotalCount { get; set; }
public int PageSize { get; set; }
public int CurrentPage { get; set; }
public int TotalPages { get; set; }
public bool HasNextPage { get; set; }
public bool HasPreviousPage { get; set; }
public string NextPageUrl { get; set; }
public string PreviousPageUrl { get; set; }
}
And this is what I do on my Get method. I just send the pageSize but I want to do this properly, without guessing how many products there will be.
public async Task<BaseMetaEntity<CrProduct>> GetProductsByCompany(int company, int pageSize, string token)
{
string urlPagination = string.Concat(Constants.UrlProduct, "?IdCompany=", company, "&PageSize=", pageSize);
return await _apiService.HttpGetAsync<BaseMetaEntity<CrProduct>>(urlPagination, token);
}
Here's my BaseMetaEntity
public class BaseMetaEntity<T>
{
public List<T> Data { get; set; }
public Meta Metadata { get; set; }
}
When I consume my Api is there any way to get the total count and use it on the request?
Please help and thanks.
Related
We have asp.net core 6 get rest apis where we are returning the list wrap with content result class. I know we can stream data in asp.net core web apis with IAsyncEnuerable but I wanted to know how we can do that with the following class returned.
public class ContentResultList<T>
{
public bool IsSuccess { get; set; }
public string Message { get; set; }
public List<T> Data { get; set; }
public int TotalPages { get; set; } = 0;
public int CurrrentPage { get; set; } = 1;
public int PageSize { get; set; } = 10;
public int TotalNumberOfRecords { get; set; } = 0;
public int RecordsTotal { get; set; }
public int RecordsFiltered { get; set; }
public T Result { get; set; }
}
Here you see that we have List Data but here I want to have IAsyncEnumerable and stream that data in the API. Is this possible
Thanks in advance!
I am currently working on a personal project where I want to map the UserTransaction to GetAllTransactionRes and return all UserTransaction from my database when the API/transaction is hit. Each time I use the API/transaction endpoint I got this error
System.Collections.Generic.List`1[ProjectName.Modules.Transaction.Core.DTO.GetAllTransactionRes]
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles. Path: $.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.TransactionId.
This is the UserTransaction Entity
public class UserTransaction
{
public int TransactionId { get; set; }
public DateTime Date { get; set; }
public virtual ICollection<OrderedProduct> OrderedProducts { get; set; }
}
This is the Ordered Product Entity
public class OrderedProduct
{
public int Id { get; set; }
public string Product { get; set; }
public int ProductId { get; set; }
public int Quantity { get; set; }
public bool Returned { get; set; }
public int TransactionId { get; set; }
public virtual UserTransaction UserTransaction { get; set; }
}
This is my mapper. GetAllTransactionRes and AllOrderedProductDTO is the exact copy of UserTransaction and OrderedProduct Entity.
CreateMap<UserTransaction, GetAllTransactionRes>().ForMember(s => s.OrderedProducts, c => c.MapFrom(m => m.OrderedProducts));
CreateMap<OrderedProduct, AllOrderedProductDTO>();
Since I am using MediatR. This is my handler for my GetAllTransactionQuery
public async Task<ICollection<GetAllTransactionRes>> Handle(GetAllTransactionQuery request, CancellationToken cancellationToken)
{
var Transactions = await _context.UserTransactions.Include(ut => ut.OrderedProducts).ToListAsync();
var mapped = _mapper.Map<ICollection<UserTransaction>, ICollection<GetAllTransactionRes>>(Transactions);
return mapped;
}
Before using automapper I used the .include method from efcore which gives me the same error I searched for answers and a person commented in a StackOverflow question that i should not return DB entities directly in my API. This is the question where the said comment is posted
What am I doing wrong? Thanks
The issue is that your AllOrderedProductDTO and your GetAllTransactionRes data transfer objects have a circular reference - transactions contains products which contain the transaction which contains the products...
Here are the DTO classes I would recommend to break out of the cycle:
public class GetAllTransactionRes
{
public int TransactionId { get; set; }
public DateTime Date { get; set; }
// be sure to use the products DTO here and not the entity because the entity has the loop
public virtual ICollection<AllOrderedProductDTO> OrderedProducts { get; set; }
}
public class AllOrderedProductDTO
{
public int Id { get; set; }
public string Product { get; set; }
public int ProductId { get; set; }
public int Quantity { get; set; }
public bool Returned { get; set; }
public int TransactionId { get; set; }
// do not include the transaction entity or DTO here so that we avoid the loop
//public virtual UserTransaction UserTransaction { get; set; }
}
I have a similar issue. I solve this problem by adding decoration.
Reference documents:https://learn.microsoft.com/en-us/ef/core/querying/related-data/serialization
public class OrderedProduct
{
public int Id { get; set; }
public string Product { get; set; }
public int ProductId { get; set; }
public int Quantity { get; set; }
public bool Returned { get; set; }
public int TransactionId { get; set; }
[JsonIgnore]
public virtual UserTransaction UserTransaction { get; set; }
}
I have just started with web API and got my first Get method successfully implemented. I was able to retrieve the data and show it to the client. Now I have to retrieve data from two tables through a single Get method which I am not able too. Here's my code for retrieving data from a single table.
public HttpResponsemessage Get(string Login, string Password)
{
using (Accord_BMHEntities entities = new Accord_BMHEntities())
{
Login = Login.Trim();
EncryptDecrypt EncryptDecryptObj = new EncryptDecrypt();
string EncryptedPassword =
EncryptDeccrypt.Encrypt(Login.Trim().ToUpper(), Password);
var userLogin = entities.ITPLUsers.firstOrDefault(e => e.Login == Login
& e.Password == EncryptedPassword
if (UserLogin == null)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound)
}
else
{
return Request.CreateResponse(HttpStatusCode.OK , UserLogin)
}
}
}
EmpMaster.cs
public partial class EmpMaster
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", n
CA2212:DoNotCallOverridableMethodsInConstructors")]
Public EmpMaster()
{
this.EmpPersonal = new HashSet<EmpPersonal>();
}
Public int EmployeeID { get; set; }
Public int DivisionId { get; set; }
Public int ResumeId { get; set; }
Public int GroupId { get; set; }
Public int DepartmentId { get; set; }
Public int WorkplaceId { get; set; }
Public int DesignationId { get; set; }
Public int Code { get; set; }
Public int DesignationId { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", n
CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICOllection<EmpPersonal> EmpPersonals { get; set; }
}
EmpPersonal.cs
Public partial class EmpPersonal
{
Public int EmployeeID { get; set; }
Public int DivisionID { get; set; }
Public short Gender { get; set; }
Public short BloodGroup { get; set; }
Public string FlatNo { get; set; }
Public string Premises { get; set; }
Public string Street { get; set; }
Public string Area { get; set; }
Public string City { get; set; }
Public string StateId { get; set; }
Public string CountryId { get; set; }
Public virtual EmpMaster EmpMaster { get; set; }
}
Please note : there are many more properties in both the class. Just to save time i have mentioned some of it.
If you have modeled the relation between the entities, you could use the Entity Framweork Include method (for eager loading) or Load method (for lazy loading).
Docs here: Entity Framework Loading Related Entities
Otherwise you could return an anonymous type:
var userLogin = entities.ITPLUsers.firstOrDefault(e => e.Login == Login
& e.Password == EncryptedPassword;
var empPersonal = entities.EmpPersonal.Where(....your condition...);
if (UserLogin == null)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound)
}
else
{
return Request.CreateResponse(HttpStatusCode.OK,new {userlogin = UserLogin, empPersonal = empPersonal});
}
I assume you want user address from Address entity along with user data. You have 2 options here. You can either use linq and join to get all related data with one query or you can get user and address datas one by one. In the end, you need to consolidate the data and return one result set since you want to return all of them in a single response.
You obviously need a resultModel for your endpoint.
Like;
public class UserResultModel
{
//Properties from User entity
public int Id { get; set; }
public string Username { get; set; }
//Properties from Address entity
public string City { get; set; }
}
You need to fill this resultModel and return it.
Irrelevant suggestion: I suggest not to check user's authentication like that. MVC has a really nice feature called Filters(Authorization Filters for more detailed)
Try Linq with joins by matching keys. You will get an example from msdn site.Msdn site
I am trying to post data to a web api with this structure:
Ledger Header and a list of ledger details. This is my class in the web api for the two:
public class PropertyLedgerDetail
{
[Key]
public int LedgerDetailID { get; set; }
public int LedgerID { get; set; }
public int? TransactionID { get; set; }
public int? TransactionTypeID { get; set; }
public double? Amount { get; set; }
public double? PaymentAmount { get; set; }
public int Month { get; set; }
public int Year { get; set; }
[StringLength(1000)]
public string Remarks { get; set; }
public bool Voided { get; set; }
public DateTime? PostingDateTime { get; set; }
}
public class PropertyLeger
{
[Key]
public int LedgerID { get; set; }
public int CollectingAgentID { get; set; }
public int UnitID { get; set; }
public int PaymentTypeID { get; set; }
[StringLength(15)]
public string ORNumber { get; set; }
public int? VoidedLedgerID { get; set; }
public bool? Voided { get; set; }
[StringLength(100)]
public string Remarks { get; set; }
public DateTime? TransactionDateTime { get; set; }
public DateTime? PostingDateTime { get; set; }
}
and this is to combine the two classes so I can receive it from my frontend:
public class AddLedger
{
public PropertyLeger PropertyLedger { get; set; }
public List<PropertyLedgerDetail> PropertyLedgerDetails { get; set; }
}
In my Angular front end, this is how I set up the properties to send:
Get values from 2 forms
add() {
const PropertyLedgerModel: any = {
CollectingAgentID: this.CollectingAgentID.value,
UnitID: this.unitId,
PaymentTypeID: this.PaymentTypeID.value,
ORNumber: this.ORNumber.value,
VoidedLedgerID: this.VoidedLedgerID.value,
Voided: this.Voided.value,
Remarks: this.Remarks0.value
}
const PropertyLedgerDetailsModel: any[] = this.dataSource;
const model: any = {
PropertyLedger: PropertyLedgerModel,
PropertyLedgerDetails: PropertyLedgerDetailsModel
}
this.pps.addLedger(model)
.subscribe((data: any) => {
debugger;
if (data.StatusCode === 200) {
this.ts.success(data.ReasonPhrase);
} else {
this.ts.error(data.ReasonPhrase);
}
},
err => {
this.ts.error('An error has occured in saving payment(s): ' +err);
})
}
To actually send this to the web api
addLedger(model: any) {
debugger;
const ep = this.rootUrl + '/api/newpropertyledger';
const PropertyLedgerModel: any = model.PropertyLedger;
const PropertyLedgerDetailsModel: any [] = model.PropertyLedgerDetails;
const Model: any = {
PropertyLedger: PropertyLedgerModel,
PropertyLedgerDetails: PropertyLedgerDetailsModel
};
return this.http.post(ep, Model);
}
I created a debug point on the part that will receive the data:
but the data from the front end doesn't reach the web api. I just get this error:
Message:"No HTTP resource was found that matches the request URI 'http://localhost:15232/api/newpropertyledger'."
MessageDetail:"No type was found that matches the controller named 'newpropertyledger'."
Please show me how to do it right. Thank you so much.
Assuming your api routing is correct i.e any of the api methods are getting hit, this should help..
addLedger(model: any) {
debugger;
const ep = this.rootUrl + '/api/newpropertyledger';
const PropertyLedgerModel: any = model.PropertyLedger;
const PropertyLedgerDetailsModel: any [] = model.PropertyLedgerDetails;
const Model: any = {
PropertyLedger: PropertyLedgerModel,
PropertyLedgerDetails: PropertyLedgerDetailsModel
};
return this.http.post(ep, JSON.stringify(ledger));
}
public HttpResponseMessage NewPropertyLedger(string data)
{
AddLedger ledger = JsonConvert.DeserializeObject<AddLedger>(data);
}
Here is an example snippet of the json data that the API returns:
{
"realm":{"name":"Molten Core","slug":"molten-core"},
"auctions":{"auctions":[
{"auc":1880591075,"item":109128,"owner":"Leagra","ownerRealm":"Azjol-Nerub","bid":858600,"buyout":900000,"quantity":100,"timeLeft":"VERY_LONG","rand":0,"seed":0,"context":0},
{"auc":1879726534,"item":43115,"owner":"Nêwt","ownerRealm":"Azjol-Nerub","bid":5120000,"buyout":5120000,"quantity":16,"timeLeft":"VERY_LONG","rand":0,"seed":835268864,"context":0}]}
}
(Though obviously with real data there's thousands of auctions.)
I'm looking to deserialise this, ignoring the realm data and just putting the auctions into a nice clean List<WowAuction> object, with WowAuction being:
public class WowAuction
{
public long auc { get; set; }
public long item { get; set; }
public long bid { get; set; }
public long buyout { get; set; }
}
I'm having trouble wrapping my head around how I would do this, the json the API returns seems rather messy to me (though admittedly I haven't worked with json before).
As far as I can tell, there's a collection called "auctions", inside of that is a single field also called "auctions" which is a table, that table then contains rows of auction data. How would I deserialise this?
There are many ways you could do that but the simple way is to create a domain object with the same structure as your JSON:
public class WoWAuctionResponse {
public WoWRealmInfo Realm {get; set;}
public WoWAuctionsBody Auctions {get; set;}
}
public class WoWAuctionsBody {
public List<WoWAuction> Auctions {get; set;}
}
// ...
JsonConvert.DeserializeObject<WoWAuctionResponse>(json);
To extend #slvnperron's answer.
First, build your classes. I recommend to use a tool like json2csharp.
public class Realm
{
public string name { get; set; }
public string slug { get; set; }
}
public class Auction
{
public int auc { get; set; }
public int item { get; set; }
public string owner { get; set; }
public string ownerRealm { get; set; }
public int bid { get; set; }
public int buyout { get; set; }
public int quantity { get; set; }
public string timeLeft { get; set; }
public int rand { get; set; }
public int seed { get; set; }
public int context { get; set; }
}
public class Auctions
{
public List<Auction> auctions { get; set; }
}
public class RootObject
{
public Realm realm { get; set; }
public Auctions auctions { get; set; }
}
Second, parse your json. i recommend to use a tool like Json.net. You can install it with nuget.
public static void Main()
{
string json = #"{here your json}";
RootObject m = JsonConvert.DeserializeObject<RootObject>(json);
Console.WriteLine(m.realm.name.Trim());
}
here our output will be :
Molten Core
Working example on dotnetfiddle.
Have your domain model this way and deserialize your data.
internal class WowAuction
{
[JsonProperty("realm")]
public Realm Realm { get; set; }
[JsonProperty("auctions")]
public Auctions Auctions { get; set; }
}
internal class Realm
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("slug")]
public string Slug { get; set; }
}
internal class Auctions
{
[JsonProperty("auctions")]
public Auction[] Auctions { get; set; }
}
internal class Auction
{
[JsonProperty("auc")]
public int Auc { get; set; }
[JsonProperty("item")]
public int Item { get; set; }
[JsonProperty("owner")]
public string Owner { get; set; }
[JsonProperty("ownerRealm")]
public string OwnerRealm { get; set; }
[JsonProperty("bid")]
public int Bid { get; set; }
[JsonProperty("buyout")]
public int Buyout { get; set; }
[JsonProperty("quantity")]
public int Quantity { get; set; }
[JsonProperty("timeLeft")]
public string TimeLeft { get; set; }
[JsonProperty("rand")]
public int Rand { get; set; }
[JsonProperty("seed")]
public int Seed { get; set; }
[JsonProperty("context")]
public int Context { get; set; }
}
Later you can have following statement to deserialize your data
JsonConvert.DeserializeObject<WowAuction>(data);
Things have changed a bit since this question was originally asked. The World of Warcraft APIs now include Game Data and Profile APIs. As the other answers here describe, you can create model classes and use Json.NET or a similar library to handle the deserialization. There are also NuGet packages like the Argent Pony Warcraft Client or the BattleMuffin Blizzard API Client that have already defined model classes and handle the deserialization for you.
An example with the ArgentPonyWarcraftClient NuGet package follows. It displays a subset of the information available for each auction.
string clientId = "CLIENT-ID-GOES-HERE";
string clientSecret = "CLIENT-SECRET-GOES-HERE";
int connectedRealmId = 1146;
IAuctionHouseApi warcraftClient = new WarcraftClient(
clientId: clientId,
clientSecret: clientSecret,
region: Region.US,
locale: Locale.en_US);
RequestResult<AuctionsIndex> result = await warcraftClient.GetAuctionsAsync(connectedRealmId, "dynamic-us");
if (result.Success)
{
AuctionsIndex auctions = result.Value;
foreach(Auction auction in auctions.Auctions)
{
Console.WriteLine($"{auction.Id}: Item ID: {auction.Item.Id} Quantity: {auction.Quantity}");
}
}