My app deals with saving orders received from an external system. The order contains child items like line items, address, fulfillments, refunds > refund items etc.
Currently, I use an ugly looking code to detect what has changed in each entity by its External Id. Can someone recommend me a better way? :)
Following is a simplified entity model of Order
public class Order
{
public long Id { get; set; }
public string ExternalOrderId { get; set; }
public List<LineItem> LineItems { get; set; }
public List<Fulfillment> Fulfillments { get; set; }
public ShippingAddress ShippingAddress { get; set; }
public List<Refund> Refunds { get; set; }
public string FinancialStatus { get; set; }
public string FulfillmentStatus { get; set; }
}
public class LineItem
{
public long Id { get; set; }
public string ExternalLineItemId { get; set; }
public string SKU { get; set; }
public int Quantity { get; set; }
public long OrderId { get; set; }
}
public class Fulfillment
{
public long Id { get; set; }
public string ExternalFulfillmentId { get; set; }
public string Status { get; set; }
public string TrackingUrl { get; set; }
public long OrderId { get; set; }
}
public class ShippingAddress
{
public long Id { get; set; }
public string ExternalShippingAddressrId { get; set; }
public string Addres { get; set; }
public long OrderId { get; set; }
}
public class Refund
{
public long Id { get; set; }
public string ExternalRefundId { get; set; }
public List<RefundedItem> LineItems { get; set; }
public string CancelledReason { get; set; }
public long OrderId { get; set; }
}
public class RefundedItem
{
public long Id { get; set; }
public string ExternalRefundedItemId { get; set; }
public string SKU { get; set; }
public int Quantity { get; set; }
}
My sample code:
private async Task ManageFulfillments(long orderId, Order order)
{
if (order.Fulfillments == null || !order.Fulfillments.Any()) return;
var newFulfillmentIds = order.Fulfillments.Select(c => c.ExternalFulfillmentId).ToList();
var dbFulfillments = await _fulfillmentRepository.GetAll().IgnoreQueryFilters()
.Where(c => c.OrderId == orderId)
.Select(c => new { c.Id, c.ExternalFulfillmentId }).ToListAsync();
var dbFulfillmentIds = dbFulfillments.Select(c => c.ExternalFulfillmentId).ToList();
// Delete Fulfillments that are not present in new Fulfillments list
var deletedFulfillments = dbFulfillmentIds.Except(newFulfillmentIds).ToList();
if (deletedFulfillments.Any())
{
await _fulfillmentRepository.DeleteAsync(c =>
deletedFulfillments.Contains(c.ExternalFulfillmentId) && c.ExternalOrderId == orderId);
}
// Update existing Fulfillments ids
order.Fulfillments
.Where(c => dbFulfillmentIds.Contains(c.ExternalFulfillmentId))
.ToList()
.ForEach(async c =>
{
c.Id = dbFulfillments.Where(p => p.ExternalFulfillmentId == c.ExternalFulfillmentId)
.Select(p => p.Id).FirstOrDefault();
await _fulfillmentRepository.UpdateAsync(c);
});
// New Fulfillments will automatically be added by EF
}
I have similar code in place to update other entites as well and I'm not proud of it!
What is your product version? 7.2.3 What is your product type (Angular or MVC)? Angular What is product framework type (.net framework or .net core)? .net core
log4net.config
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender" >
<file value="App_Data/Logs/Logs.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10000KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %date [%-5.5thread] %-40.40logger - %message%newline" />
</layout>
</appender>
<root>
<appender-ref ref="RollingFileAppender" />
<level value="DEBUG" />
</root>
</log4net>
Example usage of Logger:
Logger.Log(LogSeverity.Info, $"Storage Cost is already calculated for {Clock.Now.ToShortDateString()}");
Sample Snippet from Logs.txt
DEBUG 2019-10-21 14:37:13,537 [1 ] nnel.SCONotificationWorker - Start background worker: Castle.Proxies.SCONotificationWorkerProxy
DEBUG 2019-10-21 14:37:13,707 [1 ] kActivatorService.WAWorker - Start background worker: Castle.Proxies.WAWorkerProxy
DEBUG 2019-10-21 14:37:13,885 [1 ] ker.SCICheckerWorker - Start background worker: Castle.Proxies.SCICheckerWorkerProxy
INFO 2019-10-21 14:37:25,980 [4 ] kActivatorService.WAWorker - Running WAWorker job
DEBUG 2019-10-21 14:37:26,200 [1 ] dNotifications.DelayedNotificationWorker - Start background worker: Castle.Proxies.DelayedNotificationWorkerProxy
DEBUG 2019-10-21 14:37:26,233 [1 ] Providers.ECNotifierWorker - Start background worker: Castle.Proxies.ECNotifierWorkerProxy
DEBUG 2019-10-21 14:37:26,269 [1 ] onSync.SCISyncWorker - Start background worker: Castle.Proxies.SCISyncWorkerProxy
DEBUG 2019-10-21 14:37:26,303 [1 ] ync.SCIPollingWorker - Start background worker: Castle.Proxies.SCIPollingWorkerProxy
DEBUG 2019-10-21 14:37:26,332 [1 ] SCIFastPollingWorker - Start background worker: Castle.Proxies.SCIFastPollingWorkerProxy
DEBUG 2019-10-21 14:37:26,675 [1 ] .Technology.Common.OldDataShredderWorker - Start background worker: Castle.Proxies.OldDataShredderWorkerProxy
DEBUG 2019-10-21 14:37:26,705 [1 ] nology.Common.FrequentDataShredderWorker - Start background worker: Castle.Proxies.FrequentDataShredderWorkerProxy
DEBUG 2019-10-21 14:37:28,494 [1 ] .LPIBackgroundWorker - Start background worker: Castle.Proxies.LPIBackgroundWorkerProxy
DEBUG 2019-10-21 14:37:28,899 [1 ] .Rs.I.IRWorker - Start background worker: Castle.Proxies.IRWorkerProxy
DEBUG 2019-10-21 14:37:30,045 [1 ] eCosts.WCRBackgroundWorker - Start background worker: Castle.Proxies.WCRBackgroundWorkerProxy
DEBUG 2019-10-21 14:37:30,695 [1 ] s.LPOREmailSender - Start background worker: Castle.Proxies.LPOREmailSenderProxy
ERROR 2019-10-21 14:37:33,507 [4 ] kActivatorService.WAWorker - Failed to fix hooks for SCC with Id - 295
SSharp.SException: address: for this topic has already been taken
at SSharp.SService.CheckResponseExceptions(HttpResponseMessage response, String rawResponse)
at SSharp.SService.<>c__DisplayClass25_0`1.<<ExecuteRequestAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at SSharp.DefaultRequestExecutionPolicy.Run[T](CloneableRequestMessage request, ExecuteRequestAsync`1 executeRequestAsync)
at SSharp.SService.ExecuteRequestAsync[T](RequestUri uri, HttpMethod method, HttpContent content, String rootElement)
at SSharp.WebhookService.UpdateAsync(Int64 webhookId, Webhook webhook)
at PP.Technology.SCI.WAService.Channel.SWA.ActivateWebhooks(UserSC salesChannel) in D:\PP\PP.Service\src\PP.Technology.Core\SCI\WAService\Channel\SWA.cs:line 33
at PP.Technology.SCI.WAService.WAWorker.Execute() in D:\PP\PP.Service\src\PP.Technology.Core\SCI\WAService\WAWorker.cs:line 63
DEBUG 2019-10-21 14:37:40,448 [1 ] enancy.SubscriptionExpirationCheckWorker - Start background worker: PP.Technology.MultiTenancy.SubscriptionExpirationCheckWorker
DEBUG 2019-10-21 14:37:40,451 [1 ] cy.SubscriptionExpireEmailNotifierWorker - Start background worker: PP.Technology.MultiTenancy.SubscriptionExpireEmailNotifierWorker
INFO 2019-10-21 14:37:42,015 [1 ] fire.SqlServer.SqlServerObjectsInstaller - Start installing Hangfire SQL objects...
Here I logged the following lines which are actually useful to me and I would like to log them in separate files:
INFO 2019-10-21 14:37:25,980 [4 ] kActivatorService.WAWorker - Running WAWorker job
ERROR 2019-10-21 14:37:33,507 [4 ] kActivatorService.WAWorker - Failed to fix hooks for SCC with Id - 295
SSharp.SException: address: for this topic has already been taken
at SSharp.SService.CheckResponseExceptions(HttpResponseMessage response, String rawResponse)
at SSharp.SService.<>c__DisplayClass25_0`1.<<ExecuteRequestAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at SSharp.DefaultRequestExecutionPolicy.Run[T](CloneableRequestMessage request, ExecuteRequestAsync`1 executeRequestAsync)
at SSharp.SService.ExecuteRequestAsync[T](RequestUri uri, HttpMethod method, HttpContent content, String rootElement)
at SSharp.WebhookService.UpdateAsync(Int64 webhookId, Webhook webhook)
at PP.Technology.SCI.WAService.Channel.SWA.ActivateWebhooks(UserSC salesChannel) in D:\PP\PP.Service\src\PP.Technology.Core\SCI\WAService\Channel\SWA.cs:line 33
at PP.Technology.SCI.WAService.WAWorker.Execute() in D:\PP\PP.Service\src\PP.Technology.Core\SCI\WAService\WAWorker.cs:line 63
Hi,
Is it possible to seperate application logs (auditing logs) and logs added manually by Logger.Log
? This would be super useful as it is very hard to find manual logs with the current setup.
Thanks maliming. It worked after clearing cache
@maliming, I used the following SQL:
Update AbpSettings Set Value = 'en' where Name = 'Abp.Localization.DefaultLanguageName'
But this does not seem to work. The language is still different. Can you provide me the sql?
Hi,
On disabling a language from host admin, the language selection dropdown gets hidden for tenants which are using the disabled language. How can I set en as a default language for all the existing tenants?
Hi @maliming,
I updated the hangfire packages. Seems to be working fine now. Thanks :)
Hi,
How can I disable Audit logs for some AppServices in my code?
Specifically, disable logs for all AppServices containg HookAppService
in their name.
Hi,
I have released te project in Release
mode on Azure but I still see developer error pages while logging in on API.
I also set ASPNETCORE_ENVIRONMENT
to Production
. Can someone help what am I missing?