我正在尝试将控制器转换为异步操作或将其作为后台工作者运行。
解决方案1: 我尝试了下面的方法,但是它给我一个错误,说DBContext已被处置。
public IHttpActionResult ChargebackAllOpenAR(int clientId)
{
HostingEnvironment.QueueBackgroundWorkItem(clt => _clientService.ChargebackAllOpenAR(clientId));
//_clientService.ChargebackAllOpenAR(clientId);
return Ok();
}
解决方案2:但是它作为正常的同步过程运行
[HttpPost]
public async Task<IHttpActionResult> ChargebackAllOpenAR(int clientId)
{
await Task.Run(() => _clientService.ChargebackAllOpenAR(clientId));
//_clientService.ChargebackAllOpenAR(clientId);
return Ok();
}
解决方案3:我尝试过此操作,但给出了相同的错误,DBContext已被处置。
https://github.com/StephenCleary/AspNetBackgroundTasks
主要代码:
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));
}
}
答案 0 :(得分:0)
最后工作。
[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));
}
}
答案 1 :(得分:0)
[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);
}
}
}