Authorization Set
services.AddAuthorization(options =>
{
options.AddPolicy("MustNutritionist", policy =>
policy.RequireClaim("nutritionistId"));
});
Controller
NutritionistUpdateModel have id field.
[Authorize(Policy = "MustNutritionist")]
public BaseResponseModel PostEdit([FromForm] NutritionistUpdateModel nutritionistUpdateModel)
{
try
{
var result = nutritionistService.EditNutritionist(nutritionistUpdateModel);
if (result)
{
return new SuccessResponseModel<bool>(result);
}
else
{
return new BaseResponseModel(ReadOnlyValues.NutritionistNotFound);
}
}
catch (Exception ex)
{
return new BaseResponseModel(ex.Message);
}
}
Token Generation Claim
claims.Add(new Claim("nutritionistId", nutritionistId.ToString()));
Problem
I want to check equation of NutritionistUpdateModel.Id and Claims.nutritionistId. I can check with below code.But i must write lots of if else statement.Is there any easy way ?
private bool ChechNutritionistAuthorize(int nutritionistId)
{
var currentUser = HttpContext.User;
var nutritionistIdClaim=Int32.Parse(currentUser.Claims.FirstOrDefault(c => c.Type == "NutritionistId").Value);
if (nutritionistIdClaim == nutritionistId)
{
return true;
}
else
{
return false;
}
}
Using extension method like this
public static class IdentityExtensions
{
public static bool ValidateNutritionistId(this ClaimsPrincipal principal, int nutritionistId)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
int.TryParse(principal.Claims.FirstOrDefault(c => c.Type == "NutritionistId").Value, out int nutritionistIdClaim);
return nutritionistIdClaim == nutritionistId;
}
}
and you can use like this
HttpContext.User.ValidateNutritionistId(your id here )
and you also need to add using statement and reuse same method in all of your Controllers
public bool IsUserGroupMember(string user, string unit)
{
bool member = false;
try
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
string[] groups = unit.Split(',');
foreach (string word in groups)
{
GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, word);
if (grp != null)
{
foreach (Principal p in grp.GetMembers(true))
{
if (p.SamAccountName == user)
{
member = true;
grp.Dispose();
ctx.Dispose();
return member;
}
}
}
else
{
grp.Dispose();
ctx.Dispose();
return member;
}
}
}
catch (COMException)
{
return member;
}
return member;
}
I'm using the method above to find if a user is member of a group in Active Directory, recursively. It works well..although sometimes I get a weird exception.
Specified method is not supported.
foreach (Principal p in grp.GetMembers(true)) is red (sorry I can't upload a picture of the exception). The weirdest thing is that it seems to be thrown randomly, and if I refresh the page it works well..
I tried to find a solution on the Internet but no happy news for now..
You should do this the other way around: get the user and then the authorization groups that this user is a member of - this call (.GetAuthorizationGroups on the UserPrincipal) already is searching the groups recursively for you!
public bool IsUserGroupMember(string user, string unit)
{
bool isMember = false;
try
{
// put the PrincipalContext in a using(..) block - then it's
// automatically, safely and properly disposed of at the end
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// get the user
UserPrincipal up = UserPrincipal.FindByIdentity(ctx, user);
if(up != null)
{
// get the authorization groups for the user
// this call is *RECURSIVELY* enumerating all groups
// that this user is a member of
var authGroups = up.GetAuthorizationGroups();
// now that you have the groups - just determine if the user
// is a member of the group you're looking for......
}
}
}
catch (COMException comEx)
{
isMember = false;
}
return isMember;
}
I finally ended up with a solution!
I just had to add my domain name, as follow:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "MyDomain");
It solved the problem right away!
And about the slowness..I used cookies, following this link.
I am working on a new app and am using ASP.NET Identity and was wondering if there was a way to enforce a specific claim type be present on the ClaimsIdentity. Here is what I have so far.. It works but it seems there this is something that would / should be built in and maybe I am just not finding it.
public void SignIn(IUserIdentity user, string authenticationType, bool isPersistent)
{
if (user == null)
{
string msg = "UserIdentity or UserIdentity is null";
_logger.Error(msg);
throw new NullReferenceException(msg);
}
List<Claim> claims = _claimService.GetClaims(user.UserId);
var identity = new ClaimsIdentity(claims, authenticationType, ClaimTypes.Name, ClaimTypes.Role);
if (claims.Any() && claims.Single(c => c.Type == ClaimTypes.Name).Value != null)
{
_owinContext.Authentication.SignIn(new AuthenticationProperties
{
IsPersistent = isPersistent
}, identity);
}
else
{
throw new SecurityException("Invalid or null Name Claim");
}
}
I am not aware of any built-in way to assert that a claim exist.
Edit:
You are right. My original solution is over-engineered. I think your solution is the only way to go.
The validation is incorrect though for two reasons:
an exception is throw if the claim isn't found since .Single is used
Claim's value can never be null since it's constructor prevents it
It should be:
List<Claim> claims = _claimService.GetClaims(user.UserId);
if (claims.Any(i => i.Type == ClaimTypes.Name)
{
var identity = new ClaimsIdentity(claims, authenticationType, ClaimTypes.Name, ClaimTypes.Role);
Or
var claims = _claimService.GetClaims(user.UserId);
var identity = new ClaimsIdentity(claims, authenticationType, ClaimTypes.Name, ClaimTypes.Role);
if (identity.Name != null)
{
Original:
How I would do it is to separate authentication and authorization.
Authentication - verifies the user
Authorization - verifies what the user is authorized to do.
public class ClaimsAuthorizeAttribute : AuthorizeAttribute
{
public string[] ClaimTypes { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null) { throw new ArgumentNullException("httpContext"); }
var principal = httpContext.User as ClaimsPrincipal;
return principal != null && HasAllClaimTypes(principal) && base.AuthorizeCore(httpContext);
}
private bool HasAllClaimTypes(ClaimsPrincipal principal)
{
return ClaimTypes == null || ClaimTypes.All(claimType => principal.HasClaim(claim => claim.Type == claimType));
}
}
Enforce claim types that all controllers require in global filters like so:
filters.Add(new ClaimsAuthorizeAttribute { ClaimTypes = new[]{ ClaimTypes.Name } });
When a claim type is not present, the user is redirected to the log in page. (you may want to change this behavior though)
See this article too http://leastprivilege.com/2012/10/26/using-claims-based-authorization-in-mvc-and-web-api/
First of all it might be worth looking at this question:
How can I cache objects in ASP.NET MVC?
There some pseudo code that almost does what i want:
public class CacheExtensions
{
public static T GetOrStore<T>(this Cache cache, string key, Func<T> generator)
{
var result = cache[key];
if(result == null)
{
result = generator();
cache[key] = result;
}
return (T)result;
}
}
However, what I'd really like to do, is auto-generate the "key" from the generator. I figure i need to change the method signature to:
public static T GetOrStore<T>(this Cache cache,
System.Linq.Expressions.Expression<Func<T>> generator)
I want to use the method name, but also any parameters and their values to generate the key. I can get the method body from the expression, and the paramter names (sort of), but I have no idea how to get the paramter values...?
Or am I going about this the wrong way? Any ideas much appreciated.
Here's how I did it:
public static class ICacheExtensions
{
public static T GetOrAdd<T>(this ICache cache, Expression<Func<T>> getterExp)
{
var key = BuildCacheKey<T>(getterExp);
return cache.GetOrAdd(key, () => getterExp.Compile().Invoke());
}
private static string BuildCacheKey<T>(Expression<Func<T>> getterExp)
{
var body = getterExp.Body;
var methodCall = body as MethodCallExpression;
if (methodCall == null)
{
throw new NotSupportedException("The getterExp must be a MethodCallExpression");
}
var typeName = methodCall.Method.DeclaringType.FullName;
var methodName = methodCall.Method.Name;
var arguments = methodCall.Arguments
.Select(a => ExpressionHelper.Evaluate(a))
.ToArray();
return String.Format("{0}_{1}_{2}",
typeName,
methodName,
String.Join("|", arguments));
}
}
with this helper to evaluate nodes of an expression tree:
internal static class ExpressionHelper
{
public static object Evaluate(Expression e)
{
Type type = e.Type;
if (e.NodeType == ExpressionType.Convert)
{
var u = (UnaryExpression)e;
if (TypeHelper.GetNonNullableType(u.Operand.Type) == TypeHelper.GetNonNullableType(type))
{
e = ((UnaryExpression)e).Operand;
}
}
if (e.NodeType == ExpressionType.Constant)
{
if (e.Type == type)
{
return ((ConstantExpression)e).Value;
}
else if (TypeHelper.GetNonNullableType(e.Type) == TypeHelper.GetNonNullableType(type))
{
return ((ConstantExpression)e).Value;
}
}
var me = e as MemberExpression;
if (me != null)
{
var ce = me.Expression as ConstantExpression;
if (ce != null)
{
return me.Member.GetValue(ce.Value);
}
}
if (type.IsValueType)
{
e = Expression.Convert(e, typeof(object));
}
Expression<Func<object>> lambda = Expression.Lambda<Func<object>>(e);
Func<object> fn = lambda.Compile();
return fn();
}
}
When calling a function that produces a collection i want to cache i pass all my function's parameters and function name to the cache function which creates a key from it.
All my classes implement an interface that has and ID field so i can use it in my cache keys.
I'm sure there's a nicer way but somehow i gotta sleep at times too.
I also pass 1 or more keywords that i can use to invalidate related collections.
private static void ConvertToUpper(object entity, Hashtable visited)
{
if (entity != null && !visited.ContainsKey(entity))
{
visited.Add(entity, entity);
foreach (PropertyInfo propertyInfo in entity.GetType().GetProperties())
{
if (!propertyInfo.CanRead || !propertyInfo.CanWrite)
continue;
object propertyValue = propertyInfo.GetValue(entity, null);
Type propertyType;
if ((propertyType = propertyInfo.PropertyType) == typeof(string))
{
if (propertyValue != null && !propertyInfo.Name.Contains("password"))
{
propertyInfo.SetValue(entity, ((string)propertyValue).ToUpper(), null);
}
continue;
}
if (!propertyType.IsValueType)
{
IEnumerable enumerable;
if ((enumerable = propertyValue as IEnumerable) != null)
{
foreach (object value in enumerable)
{
ConvertToUpper(value, visited);
}
}
else
{
ConvertToUpper(propertyValue, visited);
}
}
}
}
}
Right now it works fine for objects with lists that are relatively small, but once the list of objects get larger it takes forever. How would i optimize this and also set a limit for a max depth.
Thanks for any help
I didn't profile the following code, but it must be very performant on complex structures.
1) Uses dynamic code generation.
2) Uses type-based cache for generated dynamic delegates.
public class VisitorManager : HashSet<object>
{
delegate void Visitor(VisitorManager manager, object entity);
Dictionary<Type, Visitor> _visitors = new Dictionary<Type, Visitor>();
void ConvertToUpperEnum(IEnumerable entity)
{
// TODO: this can be parallelized, but then we should thread-safe lock the cache
foreach (var obj in entity)
ConvertToUpper(obj);
}
public void ConvertToUpper(object entity)
{
if (entity != null && !Contains(entity))
{
Add(entity);
var visitor = GetCachedVisitor(entity.GetType());
if (visitor != null)
visitor(this, entity);
}
}
Type _lastType;
Visitor _lastVisitor;
Visitor GetCachedVisitor(Type type)
{
if (type == _lastType)
return _lastVisitor;
_lastType = type;
return _lastVisitor = GetVisitor(type);
}
Visitor GetVisitor(Type type)
{
Visitor result;
if (!_visitors.TryGetValue(type, out result))
_visitors[type] = result = BuildVisitor(type);
return result;
}
static MethodInfo _toUpper = typeof(string).GetMethod("ToUpper", new Type[0]);
static MethodInfo _convertToUpper = typeof(VisitorManager).GetMethod("ConvertToUpper", BindingFlags.Instance | BindingFlags.Public);
static MethodInfo _convertToUpperEnum = typeof(VisitorManager).GetMethod("ConvertToUpperEnum", BindingFlags.Instance | BindingFlags.NonPublic);
Visitor BuildVisitor(Type type)
{
var visitorManager = Expression.Parameter(typeof(VisitorManager), "manager");
var entityParam = Expression.Parameter(typeof(object), "entity");
var entityVar = Expression.Variable(type, "e");
var cast = Expression.Assign(entityVar, Expression.Convert(entityParam, type)); // T e = (T)entity;
var statements = new List<Expression>() { cast };
foreach (var prop in type.GetProperties())
{
// if cannot read or cannot write - ignore property
if (!prop.CanRead || !prop.CanWrite) continue;
var propType = prop.PropertyType;
// if property is value type - ignore property
if (propType.IsValueType) continue;
var isString = propType == typeof(string);
// if string type but no password in property name - ignore property
if (isString && !prop.Name.Contains("password"))
continue;
#region e.Prop
var propAccess = Expression.Property(entityVar, prop); // e.Prop
#endregion
#region T value = e.Prop
var value = Expression.Variable(propType, "value");
var assignValue = Expression.Assign(value, propAccess);
#endregion
if (isString)
{
#region if (value != null) e.Prop = value.ToUpper();
var ifThen = Expression.IfThen(Expression.NotEqual(value, Expression.Constant(null, typeof(string))),
Expression.Assign(propAccess, Expression.Call(value, _toUpper)));
#endregion
statements.Add(Expression.Block(new[] { value }, assignValue, ifThen));
}
else
{
#region var i = value as IEnumerable;
var enumerable = Expression.Variable(typeof(IEnumerable), "i");
var assignEnum = Expression.Assign(enumerable, Expression.TypeAs(value, enumerable.Type));
#endregion
#region if (i != null) manager.ConvertToUpperEnum(i); else manager.ConvertToUpper(value);
var ifThenElse = Expression.IfThenElse(Expression.NotEqual(enumerable, Expression.Constant(null)),
Expression.Call(visitorManager, _convertToUpperEnum, enumerable),
Expression.Call(visitorManager, _convertToUpper, value));
#endregion
statements.Add(Expression.Block(new[] { value, enumerable }, assignValue, assignEnum, ifThenElse));
}
}
// no blocks
if (statements.Count <= 1)
return null;
return Expression.Lambda<Visitor>(Expression.Block(new[] { entityVar }, statements), visitorManager, entityParam).Compile();
}
}
It looks pretty lean to me. The only thing I can think of would be to parallelize this. If I get a chance I will try to work something out and edit my answer.
Here is how to limit the depth.
private static void ConvertToUpper(object entity, Hashtable visited, int depth)
{
if (depth > MAX_DEPTH) return;
// Omitted code for brevity.
// Example usage here.
ConvertToUppder(..., ..., depth + 1);
}
What you could do is have a Dictionary with a type as the key and relevant properties as the values. You would then only need to search through the properties once for the ones you are interested in (by the looks of things IEnumerable and string) - after all, the properties the types have aren't going to change (unless you're doing some funky Emit stuff but I'm not too familiar with that)
Once you have this you could simply iterate all the properties in the Dictionary using the objects type as the key.
Somehting like this (I haven't actually tested it but it does complile :) )
private static Dictionary<Type, List<PropertyInfo>> _properties = new Dictionary<Type, List<PropertyInfo>>();
private static void ExtractProperties(List<PropertyInfo> list, Type type)
{
if (type == null || type == typeof(object))
{
return; // We've reached the top
}
// Modify which properties you want here
// This is for Public, Protected, Private
const BindingFlags PropertyFlags = BindingFlags.DeclaredOnly |
BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public;
foreach (var property in type.GetProperties(PropertyFlags))
{
if (!property.CanRead || !property.CanWrite)
continue;
if ((property.PropertyType == typeof(string)) ||
(property.PropertyType.GetInterface("IEnumerable") != null))
{
if (!property.Name.Contains("password"))
{
list.Add(property);
}
}
}
// OPTIONAL: Navigate the base type
ExtractProperties(list, type.BaseType);
}
private static void ConvertToUpper(object entity, Hashtable visited)
{
if (entity != null && !visited.ContainsKey(entity))
{
visited.Add(entity, entity);
List<PropertyInfo> properties;
if (!_properties.TryGetValue(entity.GetType(), out properties))
{
properties = new List<PropertyInfo>();
ExtractProperties(properties, entity.GetType());
_properties.Add(entity.GetType(), properties);
}
foreach (PropertyInfo propertyInfo in properties)
{
object propertyValue = propertyInfo.GetValue(entity, null);
Type propertyType = propertyInfo.PropertyType;
if (propertyType == typeof(string))
{
propertyInfo.SetValue(entity, ((string)propertyValue).ToUpper(), null);
}
else // It's IEnumerable
{
foreach (object value in (IEnumerable)propertyValue)
{
ConvertToUpper(value, visited);
}
}
}
}
}
Here is a blog of code that should work to apply the Max Depth limit that Brian Gideon mentioned as well as parallel things a bit. It's not perfect and could be refined a bit since I broke the value types and non-value type properties into 2 linq queries.
private static void ConvertToUpper(object entity, Hashtable visited, int depth)
{
if (entity == null || visited.ContainsKey(entity) || depth > MAX_DEPTH)
{
return;
}
visited.Add(entity, entity);
var properties = from p in entity.GetType().GetProperties()
where p.CanRead &&
p.CanWrite &&
p.PropertyType == typeof(string) &&
!p.Name.Contains("password") &&
p.GetValue(entity, null) != null
select p;
Parallel.ForEach(properties, (p) =>
{
p.SetValue(entity, ((string)p.GetValue(entity, null)).ToUpper(), null);
});
var valProperties = from p in entity.GetType().GetProperties()
where p.CanRead &&
p.CanWrite &&
!p.PropertyType.IsValueType &&
!p.Name.Contains("password") &&
p.GetValue(entity, null) != null
select p;
Parallel.ForEach(valProperties, (p) =>
{
if (p.GetValue(entity, null) as IEnumerable != null)
{
foreach(var value in p.GetValue(entity, null) as IEnumerable)
ConvertToUpper(value, visted, depth +1);
}
else
{
ConvertToUpper(p, visited, depth +1);
}
});
}
There are a couple of immediate issues:
There is repeated evaluation of property information for what I am assuming are the same types.
Reflection is comparatively slow.
Issue 1. can be solved by memoizing property information about types and caching it so it does not have to be re-calculated for each recurring type we see.
Performance of issue 2. can be helped out by using IL code generation and dynamic methods. I grabbed code from here to implement dynamically (and also memoized from point 1.) generated and highly efficient calls for getting and setting property values. Basically IL code is dynamically generated to call set and get for a property and encapsulated in a method wrapper - this bypasses all the reflection steps (and some security checks...). Where the following code refers to "DynamicProperty" I have used the code from the previous link.
This method can also be parallelized as suggested by others, just ensure the "visited" cache and calculated properties cache are synchronized.
private static readonly Dictionary<Type, List<ProperyInfoWrapper>> _typePropertyCache = new Dictionary<Type, List<ProperyInfoWrapper>>();
private class ProperyInfoWrapper
{
public GenericSetter PropertySetter { get; set; }
public GenericGetter PropertyGetter { get; set; }
public bool IsString { get; set; }
public bool IsEnumerable { get; set; }
}
private static void ConvertToUpper(object entity, Hashtable visited)
{
if (entity != null && !visited.Contains(entity))
{
visited.Add(entity, entity);
foreach (ProperyInfoWrapper wrapper in GetMatchingProperties(entity))
{
object propertyValue = wrapper.PropertyGetter(entity);
if(propertyValue == null) continue;
if (wrapper.IsString)
{
wrapper.PropertySetter(entity, (((string)propertyValue).ToUpper()));
continue;
}
if (wrapper.IsEnumerable)
{
IEnumerable enumerable = (IEnumerable)propertyValue;
foreach (object value in enumerable)
{
ConvertToUpper(value, visited);
}
}
else
{
ConvertToUpper(propertyValue, visited);
}
}
}
}
private static IEnumerable<ProperyInfoWrapper> GetMatchingProperties(object entity)
{
List<ProperyInfoWrapper> matchingProperties;
if (!_typePropertyCache.TryGetValue(entity.GetType(), out matchingProperties))
{
matchingProperties = new List<ProperyInfoWrapper>();
foreach (PropertyInfo propertyInfo in entity.GetType().GetProperties())
{
if (!propertyInfo.CanRead || !propertyInfo.CanWrite)
continue;
if (propertyInfo.PropertyType == typeof(string))
{
if (!propertyInfo.Name.Contains("password"))
{
ProperyInfoWrapper wrapper = new ProperyInfoWrapper
{
PropertySetter = DynamicProperty.CreateSetMethod(propertyInfo),
PropertyGetter = DynamicProperty.CreateGetMethod(propertyInfo),
IsString = true,
IsEnumerable = false
};
matchingProperties.Add(wrapper);
continue;
}
}
if (!propertyInfo.PropertyType.IsValueType)
{
object propertyValue = propertyInfo.GetValue(entity, null);
bool isEnumerable = (propertyValue as IEnumerable) != null;
ProperyInfoWrapper wrapper = new ProperyInfoWrapper
{
PropertySetter = DynamicProperty.CreateSetMethod(propertyInfo),
PropertyGetter = DynamicProperty.CreateGetMethod(propertyInfo),
IsString = false,
IsEnumerable = isEnumerable
};
matchingProperties.Add(wrapper);
}
}
_typePropertyCache.Add(entity.GetType(), matchingProperties);
}
return matchingProperties;
}
While your question is about the performance of the code, there is another problem that others seem to miss: Maintainability.
While you might think this is not as important as the performance problem you are having, having code that is more readable and maintainable will make it easier to solve problems with it.
Here is an example of how your code might look like, after a few refactorings:
class HierarchyUpperCaseConverter
{
private HashSet<object> visited = new HashSet<object>();
public static void ConvertToUpper(object entity)
{
new HierarchyUpperCaseConverter_v1().ProcessEntity(entity);
}
private void ProcessEntity(object entity)
{
// Don't process null references.
if (entity == null)
{
return;
}
// Prevent processing types that already have been processed.
if (this.visited.Contains(entity))
{
return;
}
this.visited.Add(entity);
this.ProcessEntity(entity);
}
private void ProcessEntity(object entity)
{
var properties =
this.GetProcessableProperties(entity.GetType());
foreach (var property in properties)
{
this.ProcessEntityProperty(entity, property);
}
}
private IEnumerable<PropertyInfo> GetProcessableProperties(Type type)
{
var properties =
from property in type.GetProperties()
where property.CanRead && property.CanWrite
where !property.PropertyType.IsValueType
where !(property.Name.Contains("password") &&
property.PropertyType == typeof(string))
select property;
return properties;
}
private void ProcessEntityProperty(object entity, PropertyInfo property)
{
object value = property.GetValue(entity, null);
if (value != null)
{
if (value is IEnumerable)
{
this.ProcessCollectionProperty(value as IEnumerable);
}
else if (value is string)
{
this.ProcessStringProperty(entity, property, (string)value);
}
else
{
this.AlterHierarchyToUpper(value);
}
}
}
private void ProcessCollectionProperty(IEnumerable value)
{
foreach (object item in (IEnumerable)value)
{
// Make a recursive call.
this.AlterHierarchyToUpper(item);
}
}
private void ProcessStringProperty(object entity, PropertyInfo property, string value)
{
string upperCaseValue = ConvertToUpperCase(value);
property.SetValue(entity, upperCaseValue, null);
}
private string ConvertToUpperCase(string value)
{
// TODO: ToUpper is culture sensitive.
// Shouldn't we use ToUpperInvariant?
return value.ToUpper();
}
}
While this code is more than twice as long as your code snippet, it is more maintainable. In the process of refactoring your code I even found a possible bug in your code. This bug is a lot harder to spot in your code. In your code you try to convert all string values to upper case but you don't convert string values that are stored in object properties. Look for instance at the following code.
class A
{
public object Value { get; set; }
}
var a = new A() { Value = "Hello" };
Perhaps this is exactly what you wanted, but the string "Hello" is not converted to "HELLO" in your code.
Another thing I like to note is that while the only thing I tried to do is make your code more readable, my refactoring seems about 20% faster.
After I refactored the code I tried to improve performance of it, but I found out that it is particularly hard to improve it. While others try to parallelize the code I have to warn about this. Parallelizing the code isn't as easy as others might let you think. There is some synchronization going on between threads (in the form of the 'visited' collection). Don't forget that writing to a collection is not thread-safe. Using a thread-safe version or locking on it might degrade performance again. You will have to test this.
I also found out that the real performance bottleneck is all the reflection (especially the reading of all the property values). The only way to really speed this up is by hard coding the code operations for each and every type, or as others suggested lightweight code generation. However, this is pretty hard and it is questionable whether it is worth the trouble.
I hope you find my refactorings useful and wish you good luck with improving performance.