EntityFramework-Plus
EntityFramework-Plus copied to clipboard
AuditConfiguration.Format doesn't work together with AuditDisplay
If I have the following entity class:
public class Sample
{
[Key]
public int Id { get; set; }
[AuditDisplay("Display Name")]
public string Name { get; set; }
}
...and the following configuration line:
audit.Configuration.Format<Sample>(s => s.Name, v => "Test: " + v);
... then the Format is ignored.
If I remove the AuditDisplay then the Format works perfectly.
I suspect that the Format code is looking for the property name after the AuditDisplay has already changed it, causing it to not match. If that's the case, could the Format be changed to detect the AuditDisplay and adjust its matching accordingly, or alternately could the AuditDisplay be applied after the Format instead of before?
If it helps fix this bug, I just created the following AddFormat extension which checks for the AuditDisplay attribute and adds to EntityValueFormatters directly if found, and calls down to the built-in Format if not:
internal static class AuditExtensions
{
internal static AuditConfiguration AddFormat<T>(this AuditConfiguration config, Expression<Func<T, object>> propertySelector, Func<object, object> formatter)
where T : class
{
var propertyName = propertySelector.AuditDisplay();
if (String.IsNullOrEmpty(propertyName)) return config.Format<T>(propertySelector, formatter);
config.EntityValueFormatters.Add((x, s, v) => x is T && s == propertyName ? formatter : null);
return config;
}
public static string AuditDisplay<T, V>(this Expression<Func<T, V>> expression)
{
var memberExpression = expression.GetMemberExpression();
if (memberExpression == null) throw new InvalidOperationException("Expression must be a member expression");
return memberExpression.Member.GetAttribute<AuditDisplayAttribute>()?.Name;
}
public static T GetAttribute<T>(this ICustomAttributeProvider provider)
where T : Attribute
{
var attributes = provider.GetCustomAttributes(typeof(T), true);
return attributes.Length > 0 ? attributes[0] as T : null;
}
private static MemberExpression GetMemberExpression<T,V>(this Expression<Func<T, V>> expr)
{
var asMember = expr.Body as MemberExpression;
var asUnary = expr.Body as UnaryExpression;
var memberExp = asMember ?? asUnary?.Operand as MemberExpression;
return memberExp;
}
}
It works for the above sample. I haven't tested it with advanced scenarios since I don't use them in my project.
Hello @sjbuck ,
Thank you for reporting.
We are currently re-writing this feature in Entity Framework Classic, once it's completed, we will import back some code here to add some more functionalities.
Unless I'm wrong, I believe this issue is already fixed. I will add a task to my developer to test is in EF Classic if that's working.
As said, once it's stable on EF Classic, we will import some part of the code here.
Best Regards,
Jonathan
Thanks for the quick response. I'll look into maybe just using EF Classic instead when possible in the future.
On Fri, Oct 26, 2018 at 12:48 AM Jonathan Magnan [email protected] wrote:
Hello @sjbuck https://github.com/sjbuck ,
Thank you for reporting.
We are currently re-writing this feature in Entity Framework Classic https://entityframework-classic.net/, once it's completed, we will import back some code here to add some more functionalities.
Unless I'm wrong, I believe this issue is already fixed. I will add a task to my developer to test is in EF Classic if that's working.
As said, once it's stable on EF Classic, we will import some part of the code here.
Best Regards,
Jonathan
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/zzzprojects/EntityFramework-Plus/issues/425#issuecomment-433285262, or mute the thread https://github.com/notifications/unsubscribe-auth/AUVJ5bhsKGc1fQ6U0jmZhEfXB3yjK12jks5uopQbgaJpZM4X6cda .