In lightswitch when the integrated security was used, all the entities in the database would get the following properties:
Created (datetime)
Createdby (nvarchar)
Modified (datetime)
ModifiedBy (datetime)
The system would automatically date stamp and record the username in these properties when a record was created or updated.
Is there a best practice for this in Radzen or am I missing something where this may be implemented automatically? I have created the properties on my entities, I'd just like to implement the code in one location across all entities rather than having to handle each one.
We were able to implement this with custom partial classes that implement a custom interface class IEntityAudit and override the context SaveChanges as per link (1) above.
We were able to implement this with custom partial classes that implement a custom interface class IEntityAudit and override the context SaveChanges as per link (1) above.
Thank you. I kinda get how this will be implemented and hope to see the example from Atanas to clarify it.
I do have another question though. If you override the SaveChanges function on the context and update the data source by inferring from schema again, will it overwrite any code you implement on the context?
Thanks Atanas, my basic implementation of what I've learnt today seems to fail to expose the username.
I have implemented the partial class for overriding the Saving function and can access the properties to update the modified and creation dates but I can't seem to figure how to expose the username for the CreatedBy and ModifiedBy properties.
Yeah I'd seen that but in the SaveChanges function I can't seem to figure out how to access the ```
HttpContext. I can see how that would work from the controller but I was trying to handle all this from that override function.
You are right. There is no easy way to get that in the EF context class at the moment. Will have to inject it during code generation. Right now you can get it only from the Controller classes. This would allow you to set the CreatedBy/UpdatedBy fields but you will have to create a partial class for every controller which is less than ideal. We just have to release a new Radzen version that takes care of this.
The actual logging is done in the Audit method. You can rename the properties that the sample is using to match your existing DB schema, perform additional logging etc:
public static void Audit(EntityEntry entityEntry, string userName)
{
var type = entityEntry.Entity.GetType();
if (entityEntry.State == EntityState.Added)
{
SetProperty(type, entityEntry, "CreatedBy", userName);
SetProperty(type, entityEntry, "CreatedAt", DateTime.UtcNow);
}
else if (entityEntry.State == EntityState.Modified)
{
SetProperty(type, entityEntry, "UpdatedBy", userName);
SetProperty(type, entityEntry, "UpdatedAt", DateTime.UtcNow);
}
}
I can see that it's failing to get the logged in userName. Diving into the identity I can see it looks like the logged in user isn't authenticated(?), I think. I've logged the user out and logged it back in and still can't get it to find the username.
I have been looking at implementing this today in my Blazor sample application and I seem to be running into a problem because the httpAccessor isn't injected into the DbContext when the project is built. I have implemented security I can see by looking at the DbContext that the httpAccessor doesn't exist.
Would it be an issue to implement this in the Blazor projects too?
To my MyContext.Audit.cs class file. and in the SaveChanges() method changed:
var userName = httpAccessor.HttpContext.User.FindFirst(ClaimTypes.Name).Value;
to:
var userName = security.User.UserName;
The application builds and starts but I get this error in chrome just as the pages were about to load:
InvalidOperationException: No authentication handler is registered for the scheme 'Bearer'. The registered schemes are: Identity.Application, Identity.External, Identity.TwoFactorRememberMe, Identity.TwoFactorUserId. Did you forget to call AddAuthentication().Add[SomeAuthHandler]("Bearer",...)?