FakeItEasy: How check if param is changed when method is calling? - c#

I have following service method
public async Task<IResultList<IEnrichedContentEntity>> QueryAsync(Context context, string schemaIdOrName, Q q)
{
Guard.NotNull(context, nameof(context));
if (q == null)
{
return EmptyContents;
}
var schema = await GetSchemaOrThrowAsync(context, schemaIdOrName);
var permissionReadOwn = Permissions.ForApp(Permissions.AppContentReadOwn, context.App.Name, schemaIdOrName);
if (context.Permissions.Allows(permissionReadOwn))
{
q.CreatedBy = context.User.Token();
}
using (Profiler.TraceMethod<ContentQueryService>())
{
q = await queryParser.ParseAsync(context, q, schema);
var contents = await contentRepository.QueryAsync(context.App, schema, q, context.Scope());
if (q.Ids != null && q.Ids.Count > 0)
{
contents = contents.SortSet(x => x.Id, q.Ids);
}
return await TransformAsync(context, contents);
}
}
q.CreatedBy must set value if permission is correct.
How can I test if q.CreatedBy is not empty and has correct value.
I implemented following test, but no idea how check this params?
public async Task QueryAll_should_return_own_user_contents(int isFrontend, int unpublished, SearchScope scope)
{
var ctx = CreateContextWithOwnReadPermission(isFrontend: isFrontend == 1, allowSchema: true)
.WithUnpublished(unpublished == 1);
var content = CreateContent(contentId);
var q = Q.Empty.WithReference(DomainId.NewGuid());
A.CallTo(() => contentRepository.QueryAsync(ctx.App, schema, q, scope))
.Returns(ResultList.CreateFrom(5, content));
//A.CallTo(() => contentRepository.QueryAsync(ctx.App, schema, A<Q>.That.Matches(x => x.CreatedBy == null), scope))
// .MustHaveHappened();
//A.CallTo(() => contentRepository.QueryAsync(ctx.App, schema, A<Q>.That.Matches(x => x.CreatedBy == ctx.User.Token()), scope))
// .MustHaveHappened();
//q.CreatedBy = ctx.User.Token();
var result = await sut.QueryAsync(ctx, schemaId.Name, q);
Assert.Equal(contentData, result[0].Data);
Assert.Equal(contentId, result[0].Id);
Assert.Equal(5, result.Total);
}

Related

EF Core. Don't know how to handle concurrency conflicts

I've been trying to figure out why I can't add new records but I can update them properly. I am having no luck and have looked into this issue on other topics so I am asking specifically for my situation.
EntityConfig and Methods
public void Configure(EntityTypeBuilder<Story> builder)
{
builder.ToTable("Stories");
builder.HasKey(x => x.Id);
builder.HasOne(s => s.Author)
.WithMany(a => a.Stories)
.HasForeignKey(s => s.AuthorId);
builder.OwnsMany(x => x.Ratings, x =>
{
x.WithOwner().HasForeignKey(x => x.StoryId);
x.Property(x => x.Score);
x.HasKey(y => new { y.StoryId, y.UserId });
x.ToTable("Ratings");
});
builder.OwnsMany(x => x.Favorites, x =>
{
x.WithOwner().HasForeignKey(x => x.StoryId);
x.HasKey(y => new { y.StoryId, y.UserId });
x.ToTable("Favorites");
});
}
public void WriteRating(int userId, double newRating)
{
if (HasUserWrittenRating(userId))
{
Ratings.FirstOrDefault(c => c.UserId == userId && c.StoryId == this.Id).Score = newRating;
AverageRating = Ratings.Average(r => r.Score);
}
else
{
Ratings.Add(new Rating() { StoryId = this.Id, Score = newRating, UserId = userId });
AverageRating = ((AverageRating * NumberOfRatings - 1) + newRating) / NumberOfRatings;
}
}
private bool HasUserWrittenRating(int userId)
{
return Ratings.Any(rat => rat.UserId == userId);
}
public async Task WriteRatingForStory(int storyId, int userId, int score)
{
// Get the story that was rated
var story = await _dbContext.Stories.FirstOrDefaultAsync(story => story.Id == storyId);
// Updating thestory with the new rating
story.WriteRating(userId, score);
//_dbContext.Stories.Update(story);
// Save the updated story to the database
var saved = false;
while (!saved)
{
try
{
// Attempt to save changes to the database
_dbContext.SaveChanges();
saved = true;
}
catch (DbUpdateConcurrencyException ex)
{
foreach (var entry in ex.Entries)
{
if (entry.Entity is Story)
{
var proposedValues = entry.CurrentValues;
var databaseValues = entry.GetDatabaseValues();
foreach (var property in proposedValues.Properties)
{
var proposedValue = proposedValues[property];
var databaseValue = databaseValues[property];
// TODO: decide which value should be written to database
// proposedValues[property] = <value to be saved>;
}
// Refresh original values to bypass next concurrency check
entry.OriginalValues.SetValues(databaseValues);
}
else
{
throw new NotSupportedException(
"Don't know how to handle concurrency conflicts for "
+ entry.Metadata.Name);
}
}
}
}
}
Ratings DB Structure (UserId, StoryId are both Primary, Score as
float)
Stories DB Structure (Id as Primary, AuthorId, Title, Date, Score,
AverageRating, Url)

Paging with CosmosClient in CosmosDB

I'm trying to implement paging using the SDK v3 CosmosClient instead of the old DocumentClient.
Reason for this is it seems DocumentClient doesn't translate LINQ queries that contains spatial functions very well (ie: When using Within() I'll get an error from DocumentClient stating the methods is not implemented).
Paging works well with DocumentClient.CreateDocumentQuery<T> as such:
var query = DocumentClient.CreateDocumentQuery<T>(UriFactory.CreateDocumentCollectionUri("master", "features"), feedOptions)
.Where(t => t.Type == typeof(T).Name)
.Where(pred)
.AsDocumentQuery();
string queryContinuationToken = null;
var page = await query.ExecuteNextAsync<T>();
if (query.HasMoreResults)
queryContinuationToken = page.ResponseContinuation;
I'm at a little loss as to where to gather a continuation token using CosmosClient and its Container class:
QueryRequestOptions options = new QueryRequestOptions();
options.MaxItemCount = maxRecords;
FeedIterator<T> feed;
if (continuationToken == "")
feed = Container.GetItemLinqQueryable<T>(true, null, options).Where(x => x.Type == typeof(T).Name).Where(pred).ToFeedIterator();
else
feed = Container.GetItemLinqQueryable<T>(true, continuationToken, options).Where(x => x.Type == typeof(T).Name).Where(pred).ToFeedIterator();
FeedIterator seems to have some of the members IDocumentQuery has (like HasMoreResults) but I can't find a continuation token anywhere.
What am I missing?
Alright, here's a Where method I implemented. Seems to work at first glance.
If you do var f = feed.ReadNextAsync() you won't get an object that's of type FeedResponse, preventing you access to the token. You need to declare f explicitly of type FeedResponse<T>
public async Task<(IEnumerable<T> Results, string ContinuationToken)> Where<T>(Expression<Func<T, bool>> pred, int maxRecords = 0, string partitionKey = "", string continuationToken = "") where T : IDocumentModel
{
QueryRequestOptions options = new QueryRequestOptions();
if (partitionKey != "")
options.PartitionKey = new PartitionKey(partitionKey);
if (maxRecords == 0)
{
return (Container.GetItemLinqQueryable<T>(true, null, options).Where(x => x.Type == typeof(T).Name).Where(pred), "");
}
else
{
options.MaxItemCount = maxRecords;
string token = "";
FeedIterator<T> feed;
List<T> res = new List<T>();
if (continuationToken == "")
feed = Container.GetItemLinqQueryable<T>(true, null, options).Where(x => x.Type == typeof(T).Name).Where(pred).ToFeedIterator();
else
feed = Container.GetItemLinqQueryable<T>(true, continuationToken, options).Where(x => x.Type == typeof(T).Name).Where(pred).ToFeedIterator();
Microsoft.Azure.Cosmos.FeedResponse<T> f = await feed.ReadNextAsync();
token = f.ContinuationToken;
foreach (var item in f)
{
res.Add(item);
}
return (res, token);
}
}
With the version 3.12.0 of the Cosmos SDK the following works as expected as a pretty much in place replacement for the older DocumentQuery.
Original DocumentClient method for comparison:
IDocumentQuery<ToDoItem> query = client.CreateDocumentQuery<ToDoItem>(collectionUri)
.Where(t => t.Description.Contains(searchterm))
.AsDocumentQuery();
while (query.HasMoreResults)
{
foreach (ToDoItem result in await query.ExecuteNextAsync())
{
log.LogInformation(result.Description);
}
}
Using a CosmosClient this becomes:
var database = client.GetDatabase("ToDoItems");
var container = database.GetContainer("Items");
var query = container.GetItemLinqQueryable<ToDoItem>()
.Where(t => t.Description.Contains(searchTerm))
.ToFeedIterator();
while (query.HasMoreResults)
{
foreach (ToDoItem result in await query.ReadNextAsync())
{
log.LogInformation(result.Description);
}
}
So your query is now a FeedIterator, and you can call HasMoreResults and ReadNextAsync on it.
Admittedly this won't get you access to the diagnostics, request charge, etc. that comes on the FeedIterator, but it will page through the results cleanly.
IQueryable<returnVModel> query;
var requestOptions = new QueryRequestOptions
{
MaxItemCount = 20
};
if (Token == "" || Token == null)
{
query = Container.GetItemLinqQueryable<returnVModel>(false, null, requestOptions).Where(x => x.id == id);
}
else
{
query = Container.GetItemLinqQueryable<returnVModel>(false, Token, requestOptions).Where(x => x.id == id);
}
var ct = new CancellationTokenSource();
var totalCount = await query.CountAsync(ct.Token); //Total Count
var feedIterator = query.ToFeedIterator();
var queryResults = new List<returnVModel>();
FeedResponse<returnVModel> feedResults = await feedIterator.ReadNextAsync(ct.Token);
queryResults.AddRange(feedResults); // Output
var PaginationToken = feedResults.ContinuationToken //Token
First time we need to pass token as null, from next page onwards pass the token which we received in previous output.
Pagination was working fine in v3.

Run a controller as background worker

I am trying to convert a controller to async operation or run it as a background worker.
Solution 1:
I tried below method but it give me an error saying DBContext has been disposed.
public IHttpActionResult ChargebackAllOpenAR(int clientId)
{
HostingEnvironment.QueueBackgroundWorkItem(clt => _clientService.ChargebackAllOpenAR(clientId));
//_clientService.ChargebackAllOpenAR(clientId);
return Ok();
}
Solution 2: But it runs as a normal synchronous process
[HttpPost]
public async Task<IHttpActionResult> ChargebackAllOpenAR(int clientId)
{
await Task.Run(() => _clientService.ChargebackAllOpenAR(clientId));
//_clientService.ChargebackAllOpenAR(clientId);
return Ok();
}
Solution 3: I tried this but give same error DBContext has been disposed.
https://github.com/StephenCleary/AspNetBackgroundTasks
Main Code:
public class ClientService : IClientService
{
private IRepository<Client> _clientRepository;
private IRepository<Invoice> _invoiceRepository;
private IRepository<Advance> _advanceRepository;
private IRepository<FinancialAccount> _financialAccountRepository;
private IClientTableRepository _clientTableRepository;
private IRepository<Transaction> _transactionRepository;
private IRepository<AppCredit> _appCreditRepository;
private IInvoiceService _invoiceService;
private IUserProfileRepository _userProfileRepository;
private IRepository<Domain.Payment> _paymentRepository;
private ARUnitOfWork _unitOfWork;
public ClientService(IRepository<Client> clientRepository,
IRepository<Invoice> invoiceRepository,
IRepository<Advance> advanceRepository,
IRepository<FinancialAccount> financialAccountRepository,
IClientTableRepository clientTableRepository,
IRepository<Transaction> transactionRepository,
IRepository<AppCredit> appCreditRepository,
IInvoiceService invoiceService,
IUserProfileRepository userProfileRepository,
IRepository<Domain.Payment> paymentRepository,
ARUnitOfWork unitOfWork)
{
_clientRepository = clientRepository;
_invoiceRepository = invoiceRepository;
_advanceRepository = advanceRepository;
_financialAccountRepository = financialAccountRepository;
_clientTableRepository = clientTableRepository;
_transactionRepository = transactionRepository;
_appCreditRepository = appCreditRepository;
_invoiceService = invoiceService;
_userProfileRepository = userProfileRepository;
_paymentRepository = paymentRepository;
_unitOfWork = unitOfWork;
}
public void ChargebackAllOpenAR(int clientId)
{
var client = _clientRepository.Find(c => c.Id == clientId, i => i.FinancialAccounts).First();
var transaction = new Transaction(clientId, TransactionType.Buyout);
ChargebackInvoices(client, transaction);
ChargebackOpenCredits(client, transaction);
ChargebackAdvances(client, transaction);
transaction.LineItems = transaction.LineItems.Where(li => li != null).ToList();
_transactionRepository.Insert(transaction);
_unitOfWork.SaveChanges();
}
private void ChargebackInvoices(Client client, Transaction transaction)
{
var openARAccount = client.FinancialAccounts.First(fa => fa.AccountType == ClientAccountType.OpenAR);
var escrowReservesAccount = client.FinancialAccounts.First(fa => fa.AccountType == ClientAccountType.EscrowReserve);
var cashReservesAccount = client.FinancialAccounts.First(fa => fa.AccountType == ClientAccountType.CashReserve);
var factoringFeeRevenueAccount = _financialAccountRepository.GetSingle(fa => fa.Division_Id == openARAccount.Division_Id && fa.AccountType == (int)SystemAccountType.FactoringFeeRevenue);
IEnumerable<Invoice> invoices = _invoiceRepository.Find(i => i.Client_Id == client.Id
&& i.Asset_Type == AssetType.Invoice
&& i.IsDeleted == false
&& i.Status == InvoiceStatus.Purchased,
i => i.InvoicePurchase.Terms.CollectionsFees,
i => i.TransactionLineItems)
.Where(i => i.AmountOutstanding.Value != 0)
.ToList();
foreach (Invoice invoice in invoices)
{
invoice.StatusReason = InvoiceStatusReason.Buyout;
invoice.DateClosed = DateUtil.GetSystemNow();
//Credit Open A/R for amount outstanding
transaction.LineItems.Add(openARAccount.CreateTransaction(invoice.AmountOutstanding, AccountingTransactionType.CREDIT, TransactionLineItemType.Buyout, invoice));
//Credit Fee Revenue for collections fees
CollectionsFeeCharge collectionsFee = _invoiceService.CalculateCollectionsFeeForInvoiceBuyout(invoice);
transaction.LineItems.Add(factoringFeeRevenueAccount.CreateTransaction(collectionsFee.Amount, AccountingTransactionType.CREDIT, TransactionLineItemType.Buyout, invoice));
//Debit Escrow Reserves for remaining invoice escrow
IEnumerable<TransactionLineItem> transactionLineItems = invoice.TransactionLineItems.Where(tli => tli.FinancialAccount.AccountType == (int)ClientAccountType.EscrowReserve);
var escrowAmount = transactionLineItems.Sum(tli => tli.AccountingTransactionType == AccountingTransactionType.CREDIT ? tli.Amount : -tli.Amount);
transaction.LineItems.Add(escrowReservesAccount.CreateTransaction(escrowAmount, AccountingTransactionType.DEBIT, TransactionLineItemType.Buyout, invoice));
//Debit Cash Reserves for (Open AR - invoice escrow + collections fees)
transaction.LineItems.Add(cashReservesAccount.CreateTransaction(invoice.AmountOutstanding - escrowAmount + collectionsFee.Amount, AccountingTransactionType.DEBIT, TransactionLineItemType.Buyout, invoice));
_invoiceRepository.Update(invoice);
}
}
private void ChargebackOpenCredits(Client client, Transaction transaction)
{
var cashReservesAccount = client.FinancialAccounts.First(fa => fa.AccountType == ClientAccountType.CashReserve);
var openCreditsAccount = client.FinancialAccounts.FirstOrDefault(fa => fa.AccountType == ClientAccountType.OpenCredits);
int loggedInUserId = _userProfileRepository.GetLoggedInUserId();
IEnumerable<AppCredit> appCredits = _appCreditRepository.Find(ac => (ac.Status == AppCreditStatus.Posted || ac.Status == AppCreditStatus.Ready)
&& ac.Client_Id == client.Id
&& ac.Type == AppCreditType.OpenCredit);
var ids = appCredits.Select(ac => ac.Payment_Id).Distinct().Where(id => id != null).Cast<int>();
var payments = _paymentRepository.Find(p => ids.Contains(p.Id), p => p.AppCredits)
.ToDictionary(p => p.Id);
foreach (AppCredit appCredit in appCredits)
{
DateTime now = DateUtil.GetSystemNow();
// mark open credit as removed
appCredit.Status = AppCreditStatus.Removed;
appCredit.RemovedBy_Id = loggedInUserId;
appCredit.DateRemoved = now;
// add posted reserve app credit to the payment with same amount
AppCredit reserveAppCredit = new AppCredit()
{
Type = AppCreditType.Reserve,
Status = AppCreditStatus.Posted,
Amount = appCredit.Amount,
Client_Id = appCredit.Client_Id,
Payment_Id = appCredit.Payment_Id,
PostedBy_Id = loggedInUserId,
DatePosted = now
};
Domain.Payment payment = payments[appCredit.Payment_Id];
payment.AppCredits.Add(reserveAppCredit);
if (payment.Status == Payment.Domain.PaymentStatus.Reopened
&& payment.AmountRemaining.IsZero()
&& !payment.AppCredits.Any(ac => ac.Status == AppCreditStatus.Ready))
{
payment.Status = Payment.Domain.PaymentStatus.Posted;
}
// Debit Open Credits
transaction.LineItems.Add(openCreditsAccount.CreateTransaction(appCredit.Amount, AccountingTransactionType.DEBIT, TransactionLineItemType.Buyout));
// Credit Cash Reserves
transaction.LineItems.Add(cashReservesAccount.CreateTransaction(appCredit.Amount, AccountingTransactionType.CREDIT, TransactionLineItemType.Buyout));
payment?.Transactions.Add(transaction);
}
}
private void ChargebackAdvances(Client client, Transaction transaction)
{
var cashReservesAccount = client.FinancialAccounts.First(fa => fa.AccountType == ClientAccountType.CashReserve);
var fuelAdvancceARAccount = client.FinancialAccounts.FirstOrDefault(fa => fa.AccountType == ClientAccountType.FuelAdvanceAR);
IEnumerable<Advance> advances = _advanceRepository.Find(a => a.Client_Id == client.Id
&& a.Asset_Type == AssetType.Advance
&& a.IsDeleted == false
&& a.Status == InvoiceStatus.Purchased)
.Where(a => a.AmountOutstanding.Value != 0)
.ToList();
foreach (Advance advance in advances)
{
advance.StatusReason = InvoiceStatusReason.Buyout;
advance.DateClosed = DateUtil.GetSystemNow();
//Debit Cash Reserves
transaction.LineItems.Add(cashReservesAccount.CreateTransaction(advance.AmountOutstanding, AccountingTransactionType.DEBIT, TransactionLineItemType.Buyout, advance));
//Credit Fuel Advance A/R
transaction.LineItems.Add(fuelAdvancceARAccount.CreateTransaction(advance.AmountOutstanding, AccountingTransactionType.CREDIT, TransactionLineItemType.Buyout, advance));
}
}
Finally working..
[Route("chargeback-all-open-ar-async")]
[DeltaAuthorize(Roles.OPS_MANAGER + "," + RoleGroups.TREASURY)]
[HttpPost]
public IHttpActionResult ChargebackAllOpenARAsync(int clientId)
{
_clientService.ChargebackAllOpenAR(clientId);
return Ok();
}
[Route("chargeback-all-open-ar")]
[DeltaAuthorize(Roles.OPS_MANAGER + "," + RoleGroups.TREASURY)]
[HttpPost]
public IHttpActionResult ChargebackAllOpenAR(int clientId)
{
HostingEnvironment.QueueBackgroundWorkItem(clt => ChargebackAllOpenARTask(Request, clientId));
return Ok();
}
private async Task ChargebackAllOpenARTask(HttpRequestMessage request, int clientId)
{
//Calls ChargebackAllOpenARAsync method
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = request.Headers.Authorization;
var url = new Uri(request.RequestUri.AbsoluteUri + "-async", UriKind.Absolute);
await client.PostAsync(url, new StringContent(string.Empty));
}
}
[Route("chargeback-all-open-ar")]
[DeltaAuthorize(Roles.OPS_MANAGER + "," + RoleGroups.TREASURY)]
[FireAndForget]
[HttpPost]
public IHttpActionResult ChargebackAllOpenAR(int clientId, [FromBody]bool isFireAndForget)
{
_clientService.ChargebackAllOpenAR(clientId);
return Ok();
}
public class FireAndForgetAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var request = actionContext.Request;
bool isfireAndForget = (bool)actionContext.ActionArguments["isFireAndForget"];
if (isfireAndForget)
{
QueueBackgroundWorker(request);
actionContext.Response = new HttpResponseMessage(HttpStatusCode.OK);
return;
}
}
private void QueueBackgroundWorker(HttpRequestMessage request)
{
HostingEnvironment.QueueBackgroundWorkItem(clt => GetTask(request));
}
private async Task GetTask(HttpRequestMessage request)
{
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = request.Headers.Authorization;
var url = new Uri(request.RequestUri.AbsoluteUri, UriKind.Absolute);
var param = new Dictionary<string, string>
{
{ "isFireAndForget", "false" }
};
var req = new HttpRequestMessage(HttpMethod.Post, url) { Content = new FormUrlEncodedContent(param) };
await client.SendAsync(req);
}
}
}

C# ef second operation started before previous asynchronous operation completed

Just trying to do normal query on ef but getting below error message
"A second operation started on this context before a previous asynchronous operation completed"
I am using await for all aync call but not sure what could be causing this issue.
here' code
var sids = await context.Sites.Where(s => slist.Contains(s.JVSiteID)).ToListAsync();
var header = await context.GenericCsvHeaders.FirstOrDefaultAsync(x => x.Header == csvh) ?? new GenericCsvHeader { Header = csvh };
context.Entry<GenericCsvHeader>(header).State = (header.GenericCsvHeaderID == 0) ? EntityState.Added : EntityState.Unchanged;
var sa = await context.SAs.Where(x => x.StatusID == Data.Enum.Status.Active && mapkeys.Contains(x.SAName)).Select(x => new { x.SAName, x.SACode, x.SAID }).ToListAsync();
if (sa.Count > 0)
sasitelist = await context.Site_SA.Where(x => x.StatusID == Data.Enum.Status.Active && siteids.Contains(x.SiteID ?? 0)).ToListAsync();
var az = await context.Azimuths.Where(x => x.StatusID == Data.Enum.Status.Active && mapkeys.Contains(x.AzimuthName)).Select(x => new { x.AzimuthName, x.AzimuthID }).ToListAsync();
if (az.Count > 0)
azsitelist = await context.Site_Azimuth.Where(x => x.StatusID == Data.Enum.Status.Active && siteids.Contains(x.SiteID ?? 0)).ToListAsync();
var rows = new List<dynamic>(); //getting this list from csv file via csvHelper
foreach (var r in rows)
{
var s = sids.FirstOrDefault(x => x.JVSiteID == (((IDictionary<String, Object>)r)[siteid]).ToString()) ?? new Site();
UpdateSite(s, r, map);
}
private async void UpdateSite(Site site, dynamic csvSite, IDictionary<string, string> map)
{
context.Entry(site).State = (site.StateID == 0) ? EntityState.Added : EntityState.Modified;
site.SiteForAuditTrail = site;
if (map.ContainsKey("SiteName") && !String.IsNullOrWhiteSpace(GetStringOfDynamic(map,csvSite,"SiteName")))
site.SiteName = GetStringOfDynamic(map,csvSite, "SiteName");
if (map.ContainsKey("State") && !String.IsNullOrWhiteSpace(GetStringOfDynamic(map,csvSite, "State")))
{
//getting exception at below line
var state = (await GetRefTypeList<State>(x => x.StateCode == GetStringOfDynamic(map,csvSite, "State"))) ?? new State { StateCode = GetStringOfDynamic(map,csvSite, "State") };
context.Entry(state).State = (state.StateID == 0) ? EntityState.Added : EntityState.Unchanged;
site.State = state;
state.SiteForAuditTrail = site;
}
}
private async Task<T> GetRefTypeList<T>(Func<T, bool> expression) where T : EntityBase
{
if (!refTypes.ContainsKey(typeof(T).Name))
refTypes[typeof(T).Name] = (await context.Set<T>().Where(x => x.StatusID == Data.Enum.Status.Active).ToListAsync());
return (refTypes[typeof(T).Name] as List<T>)?.FirstOrDefault(expression);
}
private string GetStringOfDynamic(IDictionary<string, string> map,dynamic obj, string propertyName)
{
if (((IDictionary<String, Object>)obj).ContainsKey(map[propertyName]))
return (((IDictionary<String, Object>)obj)[map[propertyName]]??"").ToString();
return "";
}
found problem, was missing await when calling UpdateSite
foreach (var r in rows)
{
var s = sids.FirstOrDefault(x => x.JVSiteID == (((IDictionary<String, Object>)r)[siteid]).ToString()) ?? new Site();
**await** UpdateSite(s, r, map);
}
You are having a race condition here. While you are using await you have other code executing potentially before the variable sids, header, sa and az, have been returned.
You should refactor your code so that the remaining code is not executed until these variables are returned. You can do this by using a task and then using the extension WhenAll which will ensure each await has been completed before proceeding. Here is a link to MS docs on Task and WhenAll implementation

Automaper for collections of Expression<Func>

I am using Automapper in my application and I faced an issue while mapping Expression>.
I have:
var predicateDto = _mapper.Map<Expression<Func<InventoryApplicationDto, bool>>, Expression<Func<tblInventoryApplication, bool>>>(predicate);
var applications = await _repository.SearchActivePagedAsync(predicateDto, page, pageSize);
This code works fine when I have only one value in predicate but it returns exception when I have List<T> as a predicate.
-- EDIT 1
Service method:
public async Task<PagedResult<InventoryApplicationDto>> SearchActivePagedAsync(
Expression<Func<InventoryApplicationDto, bool>> predicate, int page, int pageSize)
{
try
{
var predicateDto = _mapper.Map<Expression<Func<InventoryApplicationDto, bool>>, Expression<Func<tblInventoryApplication, bool>>>(predicate);
var applications = await _repository.SearchActivePagedAsync(predicateDto, page, pageSize);
var result = new PagedResult<InventoryApplicationDto>
{
CurrentPage = applications.CurrentPage,
PageSize = applications.PageSize,
RowCount = applications.RowCount,
PageCount = applications.PageCount,
Results = _mapper.Map<IEnumerable<tblInventoryApplication>, IEnumerable<InventoryApplicationDto>>(applications.Results)
};
return result;
}
catch (Exception ex)
{
var exc = ex.Message;
throw;
}
}
Controller method:
public async Task<ActionResult> Filter(
List<InventoryRegionDto> regions,
List<InventorySystemDto> systems,
string phrase,
int page = 0, int pageSize = 0)
{
_applicationSearchParamter.Systems = systems;
_applicationSearchParamter.Regions = regions;
_applicationSearchParamter.Phrase = phrase;
var applicationsSearchBuilder = new ApplicationSearchBuilder(_applicationSearchParamter);
var currentPage = page == 0 ? _page : page;
var currentPageSize = pageSize == 0 ? _pageSize : pageSize;
var applications =
await _applicationService.SearchActivePagedAsync(applicationsSearchBuilder.Build(), currentPage, currentPageSize);
return PartialView("~/Views/Applications/_Applications.cshtml", applications);
}
Search builder method:
public Expression<Func<InventoryApplicationDto, bool>> Build()
{
var predicate = PredicateBuilder.New<InventoryApplicationDto>(true);
if (!string.IsNullOrEmpty(_inventoryApplicationSearchParamter.Phrase))
predicate.And(s =>
s.Name.Contains(_inventoryApplicationSearchParamter.Phrase) ||
s.Acronym.Contains(_inventoryApplicationSearchParamter.Phrase) ||
s.DetailedDescription.Contains(_inventoryApplicationSearchParamter.Phrase) ||
s.Comments.Contains(_inventoryApplicationSearchParamter.Phrase)
);
if (_inventoryApplicationSearchParamter.Regions != null &&
_inventoryApplicationSearchParamter.Regions.Any())
{
var predicateTemp = PredicateBuilder.New<InventoryApplicationDto>(true);
foreach (var region in _inventoryApplicationSearchParamter.Regions)
{
predicateTemp.Or(p => p.Region.Id == region.Id);
}
predicate.And(predicateTemp);
}
if (_inventoryApplicationSearchParamter.Systems != null &&
_inventoryApplicationSearchParamter.Systems.Any())
{
var predicateTemp = PredicateBuilder.New<InventoryApplicationDto>(true);
foreach (var system in _inventoryApplicationSearchParamter.Systems)
{
predicateTemp.Or(s => s.Systems.Any(i => i.Id == system.Id));
}
predicate.And(predicateTemp);
}
return predicate;
}
The Inner exception I am getting is :
ParameterExpression of type
'Infrastructure.Domain.tblInventoryApplication' cannot be used
for delegate parameter of type
'Infrastructure.Dto.InventoryApplicationDto'

Categories

Resources