Click here to Skip to main content
15,886,812 members
Articles / Programming Languages / C#
Tip/Trick

Tracking Changes in EntityFramework and Notifying these Changes to Client Apps using SignalR

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
17 Apr 2022CPOL2 min read 6.8K   172   7   3
Extending SignalR to push EF change notification to connected client applications
In my previous article, I had explained about using SignalR to make multiple WPF client applications interactive. Here, I would be extending the SignalR features to sync data between multiple client applications and tracking EF changes to push and synchronize data to the client apps.

Introduction

When creating a client server based WPF application which can have multiple clients connected to a single WebApi service, one primary problem we need to address is synchronizing data between the multiple client apps. We need a mechanism to update the thick client apps with the refreshed data when it's changed by a connected app. SignalR becomes very useful in these scenarios to push the notification. But another important aspect of it is to track the modifications done so that these update notifications can be sent to other connected apps.

Background

In my previous article on SignalR, I had explained how a WPF application can be made more interactive and deployment friendly by using SignalR to our advantage. Today is a step ahead where we are tracking DB changes using Entity Framework and pushing those change notification using SignalR to client applications.

Using the Code

Entity Framework being the current industry standard for data access, I have created a sample application using EF 6 and SignalR to demo the tracking of changes and notification using SignalR. We start by identification of changes via the BaseContext (base DbContext) class. This is the class which should be implemented by other databases/ context classes. We override the SaveChanges method. The changes are identified and tracked using the ProcessChnages method. For each addition or modification tracked, a new Audit event type of entity is created added to audit transaction.

C#
public void ProcessChanges()
        {
            foreach (var ent in context.ChangeTracker.Entries<IAuditable>()
                .Where(p => p.State == EntityState.Deleted || 
                p.State == EntityState.Modified || p.State == EntityState.Added))
            {
                //Set the update user/time
                SetAuditTimestamps(ent);

                if (ent.State == EntityState.Added)
                {
                    //Save for processing later, when the ID is generated
                    AdditionEntities.Add(ent);
                }
                else
                {
                    //Process now
                    ModifyEvents.Add(CreateAuditEvent(ent));
                }
            }
        }

        public void TrackModifications()
        {
            if (ModifyEvents.Count == 0 && AdditionEntities.Count == 0)
                return;
            this.auditTxn = new AuditTxn()
            {
                Date = DateTime.Now,
                ServerName = Environment.MachineName,
                AuditEvents = new List<AuditEvent>()
            };
            auditTxn.AuditEvents.AddRange(ModifyEvents);
            context.Set<AuditTxn>().Add(auditTxn);
        }

        public void TrackAdditions()
        {
            if (ModifyEvents.Count == 0 && AdditionEntities.Count == 0)
                return;
            auditTxn.AuditEvents.AddRange(AdditionEntities.Select
                                         (ae => CreateAuditEvent(ae, true)));
        }

The SignalRExtensions classes contains the SignalR methods to broadcast these audit events to connected clients. The class contains a ExcludeAuditEvents collection which can be used for scenarios when we do not want to send notification for modification made to certain domain classes.

C#
public static void BroadcastEntityUpdates<T>(this T ctx) where T : IAuditableContext
        {
            var auditTxns = ctx.AuditTxns.Local;            

            var auditTxn = auditTxns.FirstOrDefault();
            if (auditTxn == null)
            {
                return;
            }
            var context = GlobalHost.ConnectionManager.GetHubContext<BroadcastHub>();

            var notification = new EntityNotification()
            {
                AuditTxnId = auditTxn.AuditTxnId,
                Date = auditTxn.Date,
                ServerName = auditTxn.ServerName,
                EntityEvents = auditTxn.AuditEvents.Where
                               (a => !ExcludedAuditEvents.Contains(a.ObjectType)).Select
                               (e => new EntityEvent()
                {
                    AuditEventId = e.AuditEventId,
                    ObjectId = e.ObjectId,
                    ObjectType = e.ObjectType,
                    Payload = ctx.GetPayload(e),
                    EventType = e.EventType == AuditEventTypes.Added ? 
                    UpdateTypes.Added : e.EventType == AuditEventTypes.Deleted ? 
                    UpdateTypes.Deleted : UpdateTypes.Modified,
                }).ToList()
            };
            context.Clients.All.UpdateEntities(notification);
        }

Now the client application should work as explained in my previous article, Exploring Signal-R to make WPF Application Interactive, where the onmessage handler can be configured to reload the EF data using the ObjectId and ObjectType passed in the EntityNotification class.

History

  • 17th April, 2022: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Infosys Limited
India India
Since my first handshake with coding in 1996, I knew its a world for me. Started the professional deep dive in 2006 and never felt like leaving the pool since.

Comments and Discussions

 
SuggestionC++? Pin
Jeff Bowman18-Apr-22 23:58
professionalJeff Bowman18-Apr-22 23:58 
GeneralRe: C++? Pin
Pusparag Subudhi19-Apr-22 10:21
professionalPusparag Subudhi19-Apr-22 10:21 
GeneralRe: C++? Pin
Jeff Bowman19-Apr-22 10:39
professionalJeff Bowman19-Apr-22 10:39 
SuggestionMessage Closed Pin
17-Apr-22 23:32
Webotapp Academy17-Apr-22 23:32 
GeneralMessage Closed Pin
17-Apr-22 20:57
Rakesh parkinn17-Apr-22 20:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.