Writing an event based SignalR Notification Service using DBContext ChangeTracker - separation of concernsSeparation of concerns and n-tiered architecture in ASP.NET 5/ASP.NET Core 1EntityFrameworkCore quite a dbcontext or should Separating DbContext In .Net Core Like Bounded Context For Getting PerformanceAsp.net core separation of concern using service layerASP.NET Core event based background tasks with hosted servicesAzure SignalR Service Error - Message rate reaches limitHow to access SignalR connection from Azure Service Bus event handlerAzure SignalR Service with native Android app?Resolve scoped service from pooled DbContext in EF CoreIs it possible to write the contents of a Sqlite DbContext into a different file

Does an object count as "being moved" when placed in a Bag of Holding before its wielder moves, and then after moving they take the object out again?

Why can't an Airbus A330 dump fuel in an emergency?

Is refusing to concede in the face of an unstoppable Nexus combo punishable?

Three Singles in Three Clubs

Is there such a thing as too inconvenient?

How to refer to a regex group in awk regex?

If all stars rotate, why was there a theory developed, that requires non-rotating stars?

How to persuade recruiters to send me the Job Description?

Which household object drew this pattern?

Check in to 2 hotels at same location

Why were movies shot on film shot at 24 frames per second?

Is “I am getting married with my sister” ambiguous?

Script that helps people make better choices

What does it mean to have a subnet mask /32?

Can you help me understand Modes from the aspect of chord changes?

Do AT motherboards (286, 386, 486) really need -5V (besides redirecting it to ISA connectors)?

Why is 日本 read as "nihon" but not "nitsuhon"?

How is "sein" conjugated in this sub-sentence?

Was Tuvok bluffing when he said that Voyager's transporters rendered the Kazon weapons useless?

How should I face my manager if I make a mistake because a senior coworker explained something incorrectly to me?

What is the hex versus octal timeline?

Is it insecure to have an ansible user with passwordless sudo?

Shouldn't the "credit score" prevent Americans from going deeper and deeper into personal debt?

Why is Boris Johnson visiting only Paris & Berlin if every member of the EU needs to agree on a withdrawal deal?



Writing an event based SignalR Notification Service using DBContext ChangeTracker - separation of concerns


Separation of concerns and n-tiered architecture in ASP.NET 5/ASP.NET Core 1EntityFrameworkCore quite a dbcontext or should Separating DbContext In .Net Core Like Bounded Context For Getting PerformanceAsp.net core separation of concern using service layerASP.NET Core event based background tasks with hosted servicesAzure SignalR Service Error - Message rate reaches limitHow to access SignalR connection from Azure Service Bus event handlerAzure SignalR Service with native Android app?Resolve scoped service from pooled DbContext in EF CoreIs it possible to write the contents of a Sqlite DbContext into a different file






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








0















I have a controller that modifies appointments in a calendar. I want to use my SignalR hub to notify users à la "User X changed appointmentTitle: List: Property OriginalValue NewValue"



I'm a beginner in C# (Syntax-wise it's ok, but OOP concepts are new); I'm trying to use events to achieve the above.
Below are the handlers and arguments, an extract from the controller and a summary of my questions.



Code is abbreviated!



EventArgs



 public class AppointmentChangeEventArgs : EventArgs

public EntityState AppointmentState = EntityState.Unchanged;
public EntityEntry Entity = null;
public ScheduleData Appointment = null;



EventHandler



 // maybe this could be just one, and let the consumer decide based on EntityState?
public EventHandler<AppointmentChangeEventArgs> AppointmentChanged;
public EventHandler<AppointmentChangeEventArgs> AppointmentAdded;
public EventHandler<AppointmentChangeEventArgs> AppointmentRemoved;

protected virtual void OnAppointment(AppointmentChangeEventArgs appointmentChangeEventArgs)

switch (appointmentChangeEventArgs.AppointmentState)

case EntityState.Added:
AppointmentAdded?.Invoke(this, appointmentChangeEventArgs);
break;
case EntityState.Deleted:
AppointmentRemoved?.Invoke(this, appointmentChangeEventArgs);
break;
case EntityState.Modified:
AppointmentChanged?.Invoke(this, appointmentChangeEventArgs);
break;
default:
break;




Controller



public async Task<IActionResult> Batch([FromBody] ScheduleEditParameters param)
switch (param.Action)
case "insert":
await _dbContext.Appointments.AddAsync(appointment);
break;
case "update":
// .. get Appointment from DB
appointment.Subject = value.Subject;
appointment.StartTime = value.StartTime;
// ...
case "remove":
// .. get Appointment from DB
_dbContext.Appointments.Remove(appointment);

var modifiedEntries = _dbContext.ChangeTracker
.Entries()
.Where(x => x.State != EntityState.Unchanged && x.State != EntityState.Detached)
.Select(x => new AppointmentChangeEventArgs() Entity = (EntityEntry) x.Entity, AppointmentState = x.State, Appointment = appointment )
.ToList();

if (modifiedEntries.Any())

var notificationService = new NotificationService(signalRHub, notificationLogger);
AppointmentAdded += notificationService.OnAppointmentChanged;
AppointmentChanged += notificationService.OnAppointmentChanged;
AppointmentRemoved += notificationService.OnAppointmentChanged;

await _dbContext.SaveChangesAsync();


Questions



  • Is it ok to use EntityEntry and EntityState in event arguments?

  • for each modified Entry, I can obtain _dbContext.Entry(modifiedEntry).Properties.Where(x => x.IsModified).ToList(); - but does this belong in the NotificationService class? In order to do that, I'd also need to pass the DbContext over to NotificationService.

  • Might there be a simpler way to achieve this? Adding and Removing handlers are easy ("User X has added|removed ... appointment Title"), but in order to figure out the exact changes I'll have to look at the modified properties.

I'd be grateful if you could provide an insight into how you would structure & handle this task. Thank you.










share|improve this question
























  • Just wondering: Where exactly does SignalR come into play here?

    – poke
    Mar 27 at 16:09











  • You got me, @poke: SignalR is part of the NotificationService, which I have omitted for the question. It obtains a HubContext and sends messages out to the user. The question is more about on how and where exactly these messages should be constructed.

    – ExternalUse
    Mar 27 at 16:12

















0















I have a controller that modifies appointments in a calendar. I want to use my SignalR hub to notify users à la "User X changed appointmentTitle: List: Property OriginalValue NewValue"



I'm a beginner in C# (Syntax-wise it's ok, but OOP concepts are new); I'm trying to use events to achieve the above.
Below are the handlers and arguments, an extract from the controller and a summary of my questions.



Code is abbreviated!



EventArgs



 public class AppointmentChangeEventArgs : EventArgs

public EntityState AppointmentState = EntityState.Unchanged;
public EntityEntry Entity = null;
public ScheduleData Appointment = null;



EventHandler



 // maybe this could be just one, and let the consumer decide based on EntityState?
public EventHandler<AppointmentChangeEventArgs> AppointmentChanged;
public EventHandler<AppointmentChangeEventArgs> AppointmentAdded;
public EventHandler<AppointmentChangeEventArgs> AppointmentRemoved;

protected virtual void OnAppointment(AppointmentChangeEventArgs appointmentChangeEventArgs)

switch (appointmentChangeEventArgs.AppointmentState)

case EntityState.Added:
AppointmentAdded?.Invoke(this, appointmentChangeEventArgs);
break;
case EntityState.Deleted:
AppointmentRemoved?.Invoke(this, appointmentChangeEventArgs);
break;
case EntityState.Modified:
AppointmentChanged?.Invoke(this, appointmentChangeEventArgs);
break;
default:
break;




Controller



public async Task<IActionResult> Batch([FromBody] ScheduleEditParameters param)
switch (param.Action)
case "insert":
await _dbContext.Appointments.AddAsync(appointment);
break;
case "update":
// .. get Appointment from DB
appointment.Subject = value.Subject;
appointment.StartTime = value.StartTime;
// ...
case "remove":
// .. get Appointment from DB
_dbContext.Appointments.Remove(appointment);

var modifiedEntries = _dbContext.ChangeTracker
.Entries()
.Where(x => x.State != EntityState.Unchanged && x.State != EntityState.Detached)
.Select(x => new AppointmentChangeEventArgs() Entity = (EntityEntry) x.Entity, AppointmentState = x.State, Appointment = appointment )
.ToList();

if (modifiedEntries.Any())

var notificationService = new NotificationService(signalRHub, notificationLogger);
AppointmentAdded += notificationService.OnAppointmentChanged;
AppointmentChanged += notificationService.OnAppointmentChanged;
AppointmentRemoved += notificationService.OnAppointmentChanged;

await _dbContext.SaveChangesAsync();


Questions



  • Is it ok to use EntityEntry and EntityState in event arguments?

  • for each modified Entry, I can obtain _dbContext.Entry(modifiedEntry).Properties.Where(x => x.IsModified).ToList(); - but does this belong in the NotificationService class? In order to do that, I'd also need to pass the DbContext over to NotificationService.

  • Might there be a simpler way to achieve this? Adding and Removing handlers are easy ("User X has added|removed ... appointment Title"), but in order to figure out the exact changes I'll have to look at the modified properties.

I'd be grateful if you could provide an insight into how you would structure & handle this task. Thank you.










share|improve this question
























  • Just wondering: Where exactly does SignalR come into play here?

    – poke
    Mar 27 at 16:09











  • You got me, @poke: SignalR is part of the NotificationService, which I have omitted for the question. It obtains a HubContext and sends messages out to the user. The question is more about on how and where exactly these messages should be constructed.

    – ExternalUse
    Mar 27 at 16:12













0












0








0








I have a controller that modifies appointments in a calendar. I want to use my SignalR hub to notify users à la "User X changed appointmentTitle: List: Property OriginalValue NewValue"



I'm a beginner in C# (Syntax-wise it's ok, but OOP concepts are new); I'm trying to use events to achieve the above.
Below are the handlers and arguments, an extract from the controller and a summary of my questions.



Code is abbreviated!



EventArgs



 public class AppointmentChangeEventArgs : EventArgs

public EntityState AppointmentState = EntityState.Unchanged;
public EntityEntry Entity = null;
public ScheduleData Appointment = null;



EventHandler



 // maybe this could be just one, and let the consumer decide based on EntityState?
public EventHandler<AppointmentChangeEventArgs> AppointmentChanged;
public EventHandler<AppointmentChangeEventArgs> AppointmentAdded;
public EventHandler<AppointmentChangeEventArgs> AppointmentRemoved;

protected virtual void OnAppointment(AppointmentChangeEventArgs appointmentChangeEventArgs)

switch (appointmentChangeEventArgs.AppointmentState)

case EntityState.Added:
AppointmentAdded?.Invoke(this, appointmentChangeEventArgs);
break;
case EntityState.Deleted:
AppointmentRemoved?.Invoke(this, appointmentChangeEventArgs);
break;
case EntityState.Modified:
AppointmentChanged?.Invoke(this, appointmentChangeEventArgs);
break;
default:
break;




Controller



public async Task<IActionResult> Batch([FromBody] ScheduleEditParameters param)
switch (param.Action)
case "insert":
await _dbContext.Appointments.AddAsync(appointment);
break;
case "update":
// .. get Appointment from DB
appointment.Subject = value.Subject;
appointment.StartTime = value.StartTime;
// ...
case "remove":
// .. get Appointment from DB
_dbContext.Appointments.Remove(appointment);

var modifiedEntries = _dbContext.ChangeTracker
.Entries()
.Where(x => x.State != EntityState.Unchanged && x.State != EntityState.Detached)
.Select(x => new AppointmentChangeEventArgs() Entity = (EntityEntry) x.Entity, AppointmentState = x.State, Appointment = appointment )
.ToList();

if (modifiedEntries.Any())

var notificationService = new NotificationService(signalRHub, notificationLogger);
AppointmentAdded += notificationService.OnAppointmentChanged;
AppointmentChanged += notificationService.OnAppointmentChanged;
AppointmentRemoved += notificationService.OnAppointmentChanged;

await _dbContext.SaveChangesAsync();


Questions



  • Is it ok to use EntityEntry and EntityState in event arguments?

  • for each modified Entry, I can obtain _dbContext.Entry(modifiedEntry).Properties.Where(x => x.IsModified).ToList(); - but does this belong in the NotificationService class? In order to do that, I'd also need to pass the DbContext over to NotificationService.

  • Might there be a simpler way to achieve this? Adding and Removing handlers are easy ("User X has added|removed ... appointment Title"), but in order to figure out the exact changes I'll have to look at the modified properties.

I'd be grateful if you could provide an insight into how you would structure & handle this task. Thank you.










share|improve this question














I have a controller that modifies appointments in a calendar. I want to use my SignalR hub to notify users à la "User X changed appointmentTitle: List: Property OriginalValue NewValue"



I'm a beginner in C# (Syntax-wise it's ok, but OOP concepts are new); I'm trying to use events to achieve the above.
Below are the handlers and arguments, an extract from the controller and a summary of my questions.



Code is abbreviated!



EventArgs



 public class AppointmentChangeEventArgs : EventArgs

public EntityState AppointmentState = EntityState.Unchanged;
public EntityEntry Entity = null;
public ScheduleData Appointment = null;



EventHandler



 // maybe this could be just one, and let the consumer decide based on EntityState?
public EventHandler<AppointmentChangeEventArgs> AppointmentChanged;
public EventHandler<AppointmentChangeEventArgs> AppointmentAdded;
public EventHandler<AppointmentChangeEventArgs> AppointmentRemoved;

protected virtual void OnAppointment(AppointmentChangeEventArgs appointmentChangeEventArgs)

switch (appointmentChangeEventArgs.AppointmentState)

case EntityState.Added:
AppointmentAdded?.Invoke(this, appointmentChangeEventArgs);
break;
case EntityState.Deleted:
AppointmentRemoved?.Invoke(this, appointmentChangeEventArgs);
break;
case EntityState.Modified:
AppointmentChanged?.Invoke(this, appointmentChangeEventArgs);
break;
default:
break;




Controller



public async Task<IActionResult> Batch([FromBody] ScheduleEditParameters param)
switch (param.Action)
case "insert":
await _dbContext.Appointments.AddAsync(appointment);
break;
case "update":
// .. get Appointment from DB
appointment.Subject = value.Subject;
appointment.StartTime = value.StartTime;
// ...
case "remove":
// .. get Appointment from DB
_dbContext.Appointments.Remove(appointment);

var modifiedEntries = _dbContext.ChangeTracker
.Entries()
.Where(x => x.State != EntityState.Unchanged && x.State != EntityState.Detached)
.Select(x => new AppointmentChangeEventArgs() Entity = (EntityEntry) x.Entity, AppointmentState = x.State, Appointment = appointment )
.ToList();

if (modifiedEntries.Any())

var notificationService = new NotificationService(signalRHub, notificationLogger);
AppointmentAdded += notificationService.OnAppointmentChanged;
AppointmentChanged += notificationService.OnAppointmentChanged;
AppointmentRemoved += notificationService.OnAppointmentChanged;

await _dbContext.SaveChangesAsync();


Questions



  • Is it ok to use EntityEntry and EntityState in event arguments?

  • for each modified Entry, I can obtain _dbContext.Entry(modifiedEntry).Properties.Where(x => x.IsModified).ToList(); - but does this belong in the NotificationService class? In order to do that, I'd also need to pass the DbContext over to NotificationService.

  • Might there be a simpler way to achieve this? Adding and Removing handlers are easy ("User X has added|removed ... appointment Title"), but in order to figure out the exact changes I'll have to look at the modified properties.

I'd be grateful if you could provide an insight into how you would structure & handle this task. Thank you.







asp.net-core entity-framework-core asp.net-core-signalr






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Mar 27 at 16:06









ExternalUseExternalUse

1,5901 gold badge16 silver badges28 bronze badges




1,5901 gold badge16 silver badges28 bronze badges















  • Just wondering: Where exactly does SignalR come into play here?

    – poke
    Mar 27 at 16:09











  • You got me, @poke: SignalR is part of the NotificationService, which I have omitted for the question. It obtains a HubContext and sends messages out to the user. The question is more about on how and where exactly these messages should be constructed.

    – ExternalUse
    Mar 27 at 16:12

















  • Just wondering: Where exactly does SignalR come into play here?

    – poke
    Mar 27 at 16:09











  • You got me, @poke: SignalR is part of the NotificationService, which I have omitted for the question. It obtains a HubContext and sends messages out to the user. The question is more about on how and where exactly these messages should be constructed.

    – ExternalUse
    Mar 27 at 16:12
















Just wondering: Where exactly does SignalR come into play here?

– poke
Mar 27 at 16:09





Just wondering: Where exactly does SignalR come into play here?

– poke
Mar 27 at 16:09













You got me, @poke: SignalR is part of the NotificationService, which I have omitted for the question. It obtains a HubContext and sends messages out to the user. The question is more about on how and where exactly these messages should be constructed.

– ExternalUse
Mar 27 at 16:12





You got me, @poke: SignalR is part of the NotificationService, which I have omitted for the question. It obtains a HubContext and sends messages out to the user. The question is more about on how and where exactly these messages should be constructed.

– ExternalUse
Mar 27 at 16:12












1 Answer
1






active

oldest

votes


















1













To start off, I would generally recommend you not to use events here. Events are something that may sound very useful but due to the way they work (synchronously), they aren’t really the best way to achieve this in a web context, especially in a primarily asynchronous framework like ASP.NET Core.



Instead, I would recommend you to simply declare your own type, e.g. IAppointmentChangeHandler like this:



public interface IAppointmentChangeHandler

Task AddAppointment(ScheduleData appointment);
Task UpdateAppointment(ScheduleData appointment);
Task RemoveAppointment(ScheduleData appointment);



Your NotificationService can just implement that interface to be able to handle those events (obviously just send whatever you need to send there):



public class NotificationService : IAppointmentChangeHandler

private readonly IHubContext _hubContext;

public NotificationService(IHubContext hubContext)

_hubContext = hubContext;


public AddAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("AddAppointment", appointment);


public UpdateAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("UpdateAppointment", appointment);


public RemoveAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("RemoveAppointment", appointment);




And inside of your controller, you just inject that IAppointmentChangeHandler then and call the actual method on it. That way you have both the controller and the notification service completely decoupled: The controller does not need to construct the type first and you also do not need to subscribe to some events (which you would also have to unsubscribe from at some point again btw). And you can leave the instantiation completely to the DI container.




To answer your individual questions:




Is it ok to use EntityEntry and EntityState in event arguments?




I would avoid using it in a context outside of your database. Both are an implementation detail of your database setup, since you are using Entity Framework here. Not only would this couple your event handlers strongly with Entity Framework (meaning that everyone that wanted to be an event handler would need to reference EF even if they didn’t do anything with it), you are also leaking possibly internal state that may change later (you don’t own the EntityEntry so who knows what EF does with it afterwards).




for each modified Entry, I can obtain _dbContext.Entry(modifiedEntry).Properties.Where(x => x.IsModified).ToList();




If you look at your code, you are first calling Add, Update or Remove on your database set; and then you are using some logic to look at some internal EF stuff to figure out the exact same thing really. You could make this a lot less complex if you constructed the AppointmentChangeEventArgs within those three switch cases directly.




but does this belong in the NotificationService class? In order to do that, I'd also need to pass the DbContext over to NotificationService.




Does a notification service have anything to do with a database? I would say no; unless you are persisting those notifications into the database. When I think about a notification service, then I expect to be able to call something on it to actively trigger a notification, instead of having some logic within the service to figure out what notifications it could possibly trigger.




Might there be a simpler way to achieve this? Adding and Removing handlers are easy ("User X has added|removed ... appointment Title"), but in order to figure out the exact changes I'll have to look at the modified properties.




Think about it in the simplest way first: Where do you update the values of the database entity? Within that update case. So at that point, where you are copying over values from the passed object, you can also just check which properties you are actually changing. And with that, you can record easily which properties you need to notify about.



Decouple this completely from EF and you will be a lot more flexible in the long run.






share|improve this answer

























  • Wow, thanks a lot for taking the time to come up with this. I've got a lot to learn! I'll with this and will report back asap. Please bear with me a moment before I accept the answer.

    – ExternalUse
    Mar 27 at 16:41











  • Could you elaborate slightly on "And inside of your controller, you just inject that IAppointmentChangeHandler then and call the actual method on it." - should I register <IAppointmentChangeHandler, NotificationService>() as a scoped service to use it?

    – ExternalUse
    Mar 27 at 16:46






  • 1





    Yeah, exactly, you can register it like that and then inject the handler interface to use it. It doesn’t need to be scoped since you don’t use the database here though.

    – poke
    Mar 27 at 17:56











  • Sorry it took awhile to get back on the question. I've got one more question that I can't figure out with this approach. By not using Events I'm not able to add multiple subscribers easily - so say I'd like to add additional Notification services later, I'd have to go back and change the NotificationService, right? Is there a way to inject multiple instances or sth similar?

    – ExternalUse
    Apr 11 at 11:29






  • 1





    @ExternalUse You could register multiple types as IAppointmentChangeHandler and then instead of injecting just one handler, inject an IEnumerable<IAppointmentChangeHandler> to get a list of all registered handlers. And then just loop through those and call the method on each of them.

    – poke
    Apr 11 at 13:04










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55381737%2fwriting-an-event-based-signalr-notification-service-using-dbcontext-changetracke%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1













To start off, I would generally recommend you not to use events here. Events are something that may sound very useful but due to the way they work (synchronously), they aren’t really the best way to achieve this in a web context, especially in a primarily asynchronous framework like ASP.NET Core.



Instead, I would recommend you to simply declare your own type, e.g. IAppointmentChangeHandler like this:



public interface IAppointmentChangeHandler

Task AddAppointment(ScheduleData appointment);
Task UpdateAppointment(ScheduleData appointment);
Task RemoveAppointment(ScheduleData appointment);



Your NotificationService can just implement that interface to be able to handle those events (obviously just send whatever you need to send there):



public class NotificationService : IAppointmentChangeHandler

private readonly IHubContext _hubContext;

public NotificationService(IHubContext hubContext)

_hubContext = hubContext;


public AddAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("AddAppointment", appointment);


public UpdateAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("UpdateAppointment", appointment);


public RemoveAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("RemoveAppointment", appointment);




And inside of your controller, you just inject that IAppointmentChangeHandler then and call the actual method on it. That way you have both the controller and the notification service completely decoupled: The controller does not need to construct the type first and you also do not need to subscribe to some events (which you would also have to unsubscribe from at some point again btw). And you can leave the instantiation completely to the DI container.




To answer your individual questions:




Is it ok to use EntityEntry and EntityState in event arguments?




I would avoid using it in a context outside of your database. Both are an implementation detail of your database setup, since you are using Entity Framework here. Not only would this couple your event handlers strongly with Entity Framework (meaning that everyone that wanted to be an event handler would need to reference EF even if they didn’t do anything with it), you are also leaking possibly internal state that may change later (you don’t own the EntityEntry so who knows what EF does with it afterwards).




for each modified Entry, I can obtain _dbContext.Entry(modifiedEntry).Properties.Where(x => x.IsModified).ToList();




If you look at your code, you are first calling Add, Update or Remove on your database set; and then you are using some logic to look at some internal EF stuff to figure out the exact same thing really. You could make this a lot less complex if you constructed the AppointmentChangeEventArgs within those three switch cases directly.




but does this belong in the NotificationService class? In order to do that, I'd also need to pass the DbContext over to NotificationService.




Does a notification service have anything to do with a database? I would say no; unless you are persisting those notifications into the database. When I think about a notification service, then I expect to be able to call something on it to actively trigger a notification, instead of having some logic within the service to figure out what notifications it could possibly trigger.




Might there be a simpler way to achieve this? Adding and Removing handlers are easy ("User X has added|removed ... appointment Title"), but in order to figure out the exact changes I'll have to look at the modified properties.




Think about it in the simplest way first: Where do you update the values of the database entity? Within that update case. So at that point, where you are copying over values from the passed object, you can also just check which properties you are actually changing. And with that, you can record easily which properties you need to notify about.



Decouple this completely from EF and you will be a lot more flexible in the long run.






share|improve this answer

























  • Wow, thanks a lot for taking the time to come up with this. I've got a lot to learn! I'll with this and will report back asap. Please bear with me a moment before I accept the answer.

    – ExternalUse
    Mar 27 at 16:41











  • Could you elaborate slightly on "And inside of your controller, you just inject that IAppointmentChangeHandler then and call the actual method on it." - should I register <IAppointmentChangeHandler, NotificationService>() as a scoped service to use it?

    – ExternalUse
    Mar 27 at 16:46






  • 1





    Yeah, exactly, you can register it like that and then inject the handler interface to use it. It doesn’t need to be scoped since you don’t use the database here though.

    – poke
    Mar 27 at 17:56











  • Sorry it took awhile to get back on the question. I've got one more question that I can't figure out with this approach. By not using Events I'm not able to add multiple subscribers easily - so say I'd like to add additional Notification services later, I'd have to go back and change the NotificationService, right? Is there a way to inject multiple instances or sth similar?

    – ExternalUse
    Apr 11 at 11:29






  • 1





    @ExternalUse You could register multiple types as IAppointmentChangeHandler and then instead of injecting just one handler, inject an IEnumerable<IAppointmentChangeHandler> to get a list of all registered handlers. And then just loop through those and call the method on each of them.

    – poke
    Apr 11 at 13:04















1













To start off, I would generally recommend you not to use events here. Events are something that may sound very useful but due to the way they work (synchronously), they aren’t really the best way to achieve this in a web context, especially in a primarily asynchronous framework like ASP.NET Core.



Instead, I would recommend you to simply declare your own type, e.g. IAppointmentChangeHandler like this:



public interface IAppointmentChangeHandler

Task AddAppointment(ScheduleData appointment);
Task UpdateAppointment(ScheduleData appointment);
Task RemoveAppointment(ScheduleData appointment);



Your NotificationService can just implement that interface to be able to handle those events (obviously just send whatever you need to send there):



public class NotificationService : IAppointmentChangeHandler

private readonly IHubContext _hubContext;

public NotificationService(IHubContext hubContext)

_hubContext = hubContext;


public AddAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("AddAppointment", appointment);


public UpdateAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("UpdateAppointment", appointment);


public RemoveAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("RemoveAppointment", appointment);




And inside of your controller, you just inject that IAppointmentChangeHandler then and call the actual method on it. That way you have both the controller and the notification service completely decoupled: The controller does not need to construct the type first and you also do not need to subscribe to some events (which you would also have to unsubscribe from at some point again btw). And you can leave the instantiation completely to the DI container.




To answer your individual questions:




Is it ok to use EntityEntry and EntityState in event arguments?




I would avoid using it in a context outside of your database. Both are an implementation detail of your database setup, since you are using Entity Framework here. Not only would this couple your event handlers strongly with Entity Framework (meaning that everyone that wanted to be an event handler would need to reference EF even if they didn’t do anything with it), you are also leaking possibly internal state that may change later (you don’t own the EntityEntry so who knows what EF does with it afterwards).




for each modified Entry, I can obtain _dbContext.Entry(modifiedEntry).Properties.Where(x => x.IsModified).ToList();




If you look at your code, you are first calling Add, Update or Remove on your database set; and then you are using some logic to look at some internal EF stuff to figure out the exact same thing really. You could make this a lot less complex if you constructed the AppointmentChangeEventArgs within those three switch cases directly.




but does this belong in the NotificationService class? In order to do that, I'd also need to pass the DbContext over to NotificationService.




Does a notification service have anything to do with a database? I would say no; unless you are persisting those notifications into the database. When I think about a notification service, then I expect to be able to call something on it to actively trigger a notification, instead of having some logic within the service to figure out what notifications it could possibly trigger.




Might there be a simpler way to achieve this? Adding and Removing handlers are easy ("User X has added|removed ... appointment Title"), but in order to figure out the exact changes I'll have to look at the modified properties.




Think about it in the simplest way first: Where do you update the values of the database entity? Within that update case. So at that point, where you are copying over values from the passed object, you can also just check which properties you are actually changing. And with that, you can record easily which properties you need to notify about.



Decouple this completely from EF and you will be a lot more flexible in the long run.






share|improve this answer

























  • Wow, thanks a lot for taking the time to come up with this. I've got a lot to learn! I'll with this and will report back asap. Please bear with me a moment before I accept the answer.

    – ExternalUse
    Mar 27 at 16:41











  • Could you elaborate slightly on "And inside of your controller, you just inject that IAppointmentChangeHandler then and call the actual method on it." - should I register <IAppointmentChangeHandler, NotificationService>() as a scoped service to use it?

    – ExternalUse
    Mar 27 at 16:46






  • 1





    Yeah, exactly, you can register it like that and then inject the handler interface to use it. It doesn’t need to be scoped since you don’t use the database here though.

    – poke
    Mar 27 at 17:56











  • Sorry it took awhile to get back on the question. I've got one more question that I can't figure out with this approach. By not using Events I'm not able to add multiple subscribers easily - so say I'd like to add additional Notification services later, I'd have to go back and change the NotificationService, right? Is there a way to inject multiple instances or sth similar?

    – ExternalUse
    Apr 11 at 11:29






  • 1





    @ExternalUse You could register multiple types as IAppointmentChangeHandler and then instead of injecting just one handler, inject an IEnumerable<IAppointmentChangeHandler> to get a list of all registered handlers. And then just loop through those and call the method on each of them.

    – poke
    Apr 11 at 13:04













1












1








1







To start off, I would generally recommend you not to use events here. Events are something that may sound very useful but due to the way they work (synchronously), they aren’t really the best way to achieve this in a web context, especially in a primarily asynchronous framework like ASP.NET Core.



Instead, I would recommend you to simply declare your own type, e.g. IAppointmentChangeHandler like this:



public interface IAppointmentChangeHandler

Task AddAppointment(ScheduleData appointment);
Task UpdateAppointment(ScheduleData appointment);
Task RemoveAppointment(ScheduleData appointment);



Your NotificationService can just implement that interface to be able to handle those events (obviously just send whatever you need to send there):



public class NotificationService : IAppointmentChangeHandler

private readonly IHubContext _hubContext;

public NotificationService(IHubContext hubContext)

_hubContext = hubContext;


public AddAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("AddAppointment", appointment);


public UpdateAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("UpdateAppointment", appointment);


public RemoveAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("RemoveAppointment", appointment);




And inside of your controller, you just inject that IAppointmentChangeHandler then and call the actual method on it. That way you have both the controller and the notification service completely decoupled: The controller does not need to construct the type first and you also do not need to subscribe to some events (which you would also have to unsubscribe from at some point again btw). And you can leave the instantiation completely to the DI container.




To answer your individual questions:




Is it ok to use EntityEntry and EntityState in event arguments?




I would avoid using it in a context outside of your database. Both are an implementation detail of your database setup, since you are using Entity Framework here. Not only would this couple your event handlers strongly with Entity Framework (meaning that everyone that wanted to be an event handler would need to reference EF even if they didn’t do anything with it), you are also leaking possibly internal state that may change later (you don’t own the EntityEntry so who knows what EF does with it afterwards).




for each modified Entry, I can obtain _dbContext.Entry(modifiedEntry).Properties.Where(x => x.IsModified).ToList();




If you look at your code, you are first calling Add, Update or Remove on your database set; and then you are using some logic to look at some internal EF stuff to figure out the exact same thing really. You could make this a lot less complex if you constructed the AppointmentChangeEventArgs within those three switch cases directly.




but does this belong in the NotificationService class? In order to do that, I'd also need to pass the DbContext over to NotificationService.




Does a notification service have anything to do with a database? I would say no; unless you are persisting those notifications into the database. When I think about a notification service, then I expect to be able to call something on it to actively trigger a notification, instead of having some logic within the service to figure out what notifications it could possibly trigger.




Might there be a simpler way to achieve this? Adding and Removing handlers are easy ("User X has added|removed ... appointment Title"), but in order to figure out the exact changes I'll have to look at the modified properties.




Think about it in the simplest way first: Where do you update the values of the database entity? Within that update case. So at that point, where you are copying over values from the passed object, you can also just check which properties you are actually changing. And with that, you can record easily which properties you need to notify about.



Decouple this completely from EF and you will be a lot more flexible in the long run.






share|improve this answer













To start off, I would generally recommend you not to use events here. Events are something that may sound very useful but due to the way they work (synchronously), they aren’t really the best way to achieve this in a web context, especially in a primarily asynchronous framework like ASP.NET Core.



Instead, I would recommend you to simply declare your own type, e.g. IAppointmentChangeHandler like this:



public interface IAppointmentChangeHandler

Task AddAppointment(ScheduleData appointment);
Task UpdateAppointment(ScheduleData appointment);
Task RemoveAppointment(ScheduleData appointment);



Your NotificationService can just implement that interface to be able to handle those events (obviously just send whatever you need to send there):



public class NotificationService : IAppointmentChangeHandler

private readonly IHubContext _hubContext;

public NotificationService(IHubContext hubContext)

_hubContext = hubContext;


public AddAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("AddAppointment", appointment);


public UpdateAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("UpdateAppointment", appointment);


public RemoveAppointment(ScheduleData appointment)

await _hubContext.Clients.InvokeAsync("RemoveAppointment", appointment);




And inside of your controller, you just inject that IAppointmentChangeHandler then and call the actual method on it. That way you have both the controller and the notification service completely decoupled: The controller does not need to construct the type first and you also do not need to subscribe to some events (which you would also have to unsubscribe from at some point again btw). And you can leave the instantiation completely to the DI container.




To answer your individual questions:




Is it ok to use EntityEntry and EntityState in event arguments?




I would avoid using it in a context outside of your database. Both are an implementation detail of your database setup, since you are using Entity Framework here. Not only would this couple your event handlers strongly with Entity Framework (meaning that everyone that wanted to be an event handler would need to reference EF even if they didn’t do anything with it), you are also leaking possibly internal state that may change later (you don’t own the EntityEntry so who knows what EF does with it afterwards).




for each modified Entry, I can obtain _dbContext.Entry(modifiedEntry).Properties.Where(x => x.IsModified).ToList();




If you look at your code, you are first calling Add, Update or Remove on your database set; and then you are using some logic to look at some internal EF stuff to figure out the exact same thing really. You could make this a lot less complex if you constructed the AppointmentChangeEventArgs within those three switch cases directly.




but does this belong in the NotificationService class? In order to do that, I'd also need to pass the DbContext over to NotificationService.




Does a notification service have anything to do with a database? I would say no; unless you are persisting those notifications into the database. When I think about a notification service, then I expect to be able to call something on it to actively trigger a notification, instead of having some logic within the service to figure out what notifications it could possibly trigger.




Might there be a simpler way to achieve this? Adding and Removing handlers are easy ("User X has added|removed ... appointment Title"), but in order to figure out the exact changes I'll have to look at the modified properties.




Think about it in the simplest way first: Where do you update the values of the database entity? Within that update case. So at that point, where you are copying over values from the passed object, you can also just check which properties you are actually changing. And with that, you can record easily which properties you need to notify about.



Decouple this completely from EF and you will be a lot more flexible in the long run.







share|improve this answer












share|improve this answer



share|improve this answer










answered Mar 27 at 16:29









pokepoke

231k50 gold badges359 silver badges425 bronze badges




231k50 gold badges359 silver badges425 bronze badges















  • Wow, thanks a lot for taking the time to come up with this. I've got a lot to learn! I'll with this and will report back asap. Please bear with me a moment before I accept the answer.

    – ExternalUse
    Mar 27 at 16:41











  • Could you elaborate slightly on "And inside of your controller, you just inject that IAppointmentChangeHandler then and call the actual method on it." - should I register <IAppointmentChangeHandler, NotificationService>() as a scoped service to use it?

    – ExternalUse
    Mar 27 at 16:46






  • 1





    Yeah, exactly, you can register it like that and then inject the handler interface to use it. It doesn’t need to be scoped since you don’t use the database here though.

    – poke
    Mar 27 at 17:56











  • Sorry it took awhile to get back on the question. I've got one more question that I can't figure out with this approach. By not using Events I'm not able to add multiple subscribers easily - so say I'd like to add additional Notification services later, I'd have to go back and change the NotificationService, right? Is there a way to inject multiple instances or sth similar?

    – ExternalUse
    Apr 11 at 11:29






  • 1





    @ExternalUse You could register multiple types as IAppointmentChangeHandler and then instead of injecting just one handler, inject an IEnumerable<IAppointmentChangeHandler> to get a list of all registered handlers. And then just loop through those and call the method on each of them.

    – poke
    Apr 11 at 13:04

















  • Wow, thanks a lot for taking the time to come up with this. I've got a lot to learn! I'll with this and will report back asap. Please bear with me a moment before I accept the answer.

    – ExternalUse
    Mar 27 at 16:41











  • Could you elaborate slightly on "And inside of your controller, you just inject that IAppointmentChangeHandler then and call the actual method on it." - should I register <IAppointmentChangeHandler, NotificationService>() as a scoped service to use it?

    – ExternalUse
    Mar 27 at 16:46






  • 1





    Yeah, exactly, you can register it like that and then inject the handler interface to use it. It doesn’t need to be scoped since you don’t use the database here though.

    – poke
    Mar 27 at 17:56











  • Sorry it took awhile to get back on the question. I've got one more question that I can't figure out with this approach. By not using Events I'm not able to add multiple subscribers easily - so say I'd like to add additional Notification services later, I'd have to go back and change the NotificationService, right? Is there a way to inject multiple instances or sth similar?

    – ExternalUse
    Apr 11 at 11:29






  • 1





    @ExternalUse You could register multiple types as IAppointmentChangeHandler and then instead of injecting just one handler, inject an IEnumerable<IAppointmentChangeHandler> to get a list of all registered handlers. And then just loop through those and call the method on each of them.

    – poke
    Apr 11 at 13:04
















Wow, thanks a lot for taking the time to come up with this. I've got a lot to learn! I'll with this and will report back asap. Please bear with me a moment before I accept the answer.

– ExternalUse
Mar 27 at 16:41





Wow, thanks a lot for taking the time to come up with this. I've got a lot to learn! I'll with this and will report back asap. Please bear with me a moment before I accept the answer.

– ExternalUse
Mar 27 at 16:41













Could you elaborate slightly on "And inside of your controller, you just inject that IAppointmentChangeHandler then and call the actual method on it." - should I register <IAppointmentChangeHandler, NotificationService>() as a scoped service to use it?

– ExternalUse
Mar 27 at 16:46





Could you elaborate slightly on "And inside of your controller, you just inject that IAppointmentChangeHandler then and call the actual method on it." - should I register <IAppointmentChangeHandler, NotificationService>() as a scoped service to use it?

– ExternalUse
Mar 27 at 16:46




1




1





Yeah, exactly, you can register it like that and then inject the handler interface to use it. It doesn’t need to be scoped since you don’t use the database here though.

– poke
Mar 27 at 17:56





Yeah, exactly, you can register it like that and then inject the handler interface to use it. It doesn’t need to be scoped since you don’t use the database here though.

– poke
Mar 27 at 17:56













Sorry it took awhile to get back on the question. I've got one more question that I can't figure out with this approach. By not using Events I'm not able to add multiple subscribers easily - so say I'd like to add additional Notification services later, I'd have to go back and change the NotificationService, right? Is there a way to inject multiple instances or sth similar?

– ExternalUse
Apr 11 at 11:29





Sorry it took awhile to get back on the question. I've got one more question that I can't figure out with this approach. By not using Events I'm not able to add multiple subscribers easily - so say I'd like to add additional Notification services later, I'd have to go back and change the NotificationService, right? Is there a way to inject multiple instances or sth similar?

– ExternalUse
Apr 11 at 11:29




1




1





@ExternalUse You could register multiple types as IAppointmentChangeHandler and then instead of injecting just one handler, inject an IEnumerable<IAppointmentChangeHandler> to get a list of all registered handlers. And then just loop through those and call the method on each of them.

– poke
Apr 11 at 13:04





@ExternalUse You could register multiple types as IAppointmentChangeHandler and then instead of injecting just one handler, inject an IEnumerable<IAppointmentChangeHandler> to get a list of all registered handlers. And then just loop through those and call the method on each of them.

– poke
Apr 11 at 13:04






Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.







Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.



















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55381737%2fwriting-an-event-based-signalr-notification-service-using-dbcontext-changetracke%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript