/// <summary> /// Returns a filter contexualised to the logged on user and entity. /// </summary> private static Expression <Func <TEntity, bool> > GetFilter <TEntity>(out GetActionTypes actionType) where TEntity : BaseModel { Logger.InstanceVerbose.LogFunctionEntry(typeof(RepositoryFactory).Name, String.Format("GetFilter<{0}>", typeof(TEntity).Name)); Expression <Func <TEntity, bool> > filters; if (Thread.CurrentPrincipal.Identity as TEIdentityBase == null) { // Disallow access completely actionType = GetActionTypes.ThrowsUnauthorizedException; return(t => false); //throw new UnauthorizedException("A repository can not be created for an anon user"); } // Based on the appliesWhen outcome, concat all applicable filters and return var applicableFilters = RepositoryFactory.filters[typeof(TEntity)].Where(t => t.AppliesWhen(Thread.CurrentPrincipal.Identity as TEIdentityBase)).ToList(); actionType = GetActionTypes.ReturnsNull; if (applicableFilters.Any()) { if (applicableFilters.Any(t => t.Action == GetActionTypes.ThrowsUnauthorizedException)) { actionType = GetActionTypes.ThrowsUnauthorizedException; } filters = applicableFilters.Select(t => t.FilterExpression as Expression <Func <TEntity, bool> >).Aggregate((a, b) => a.And(b)); } else { filters = null; } // Log outcome var message = "Applicable Filters Found? = " + (filters != null); if (filters != null) { message += "(" + actionType + ")"; } Logger.InstanceVerbose.Info(typeof(RepositoryFactory).Name, String.Format("GetFilter<{0}>", typeof(TEntity).Name), message); Logger.InstanceVerbose.LogFunctionExit(typeof(RepositoryFactory).Name, String.Format("GetFilter<{0}>", typeof(TEntity).Name)); return(filters); }
/// <summary> /// This will register the given filter in the repository. Until Reset() is called, this filter will /// always be applied when "appliesWhen" is true. /// </summary> /// <typeparam name="TEntity">The entity to apply the filter too. Note that this does not affect navigation properties (at this time)</typeparam> /// <param name="filter">The filter expression. Will be used in the LINQ to SQL query</param> /// <param name="appliesWhen">The filter is applied when this is true. This need not be convertable to SQL.</param> /// <param name="action">Dictates the behaviour that any get by ID methods undertake</param> /// <remarks>For both functions above, you should not save state between threads and users. /// Additionaly, the appliesWhen should be consistent per authenticated user(TEIdentityBase) and will be called at least once, but maybe only once (with outcome cached). /// </remarks> public static void RegisterFilter <TEntity, TIdentity>(Expression <Func <TEntity, bool> > filter, Func <TIdentity, bool> appliesWhen = null, GetActionTypes action = GetActionTypes.ThrowsUnauthorizedException) where TEntity : BaseModel where TIdentity : TEIdentityBase { Logger.InstanceVerbose.LogFunctionEntry(typeof(RepositoryFactory).Name, String.Format("RegisterFilter<{0}>", typeof(TEntity).Name)); Logger.InstanceVerbose.Debug(typeof(RepositoryFactory).Name, String.Format("RegisterFilter<{0}>", typeof(TEntity).Name), "Registering a filter for type " + typeof(TEntity) + " with action " + action); lock (syncRoot) { var appliesWhenToUse = appliesWhen ?? AppliesToAllFunc; if (!filters.ContainsKey(typeof(TEntity))) { var list = new List <Filter> { new Filter { FilterExpression = filter, AppliesWhen = t => t is TIdentity && appliesWhenToUse(t as TIdentity), Action = action } }; filters.Add(typeof(TEntity), list); } else { var list = filters[typeof(TEntity)]; // Yes - this is a reference check on the delegate so we can concat the filters properly var match = list.SingleOrDefault(d => d.AppliesWhen == appliesWhenToUse && d.Action == action); // We need to add it to the list as there is a different appliesWhen property if (match == null) { list.Add(new Filter { FilterExpression = filter, AppliesWhen = t => t is TIdentity && appliesWhenToUse(t as TIdentity), Action = action }); } else { // Concat it to the previous expression var expression = (Expression <Func <TEntity, bool> >)match.FilterExpression; match.FilterExpression = expression.And(filter); } } } Logger.InstanceVerbose.LogFunctionExit(typeof(RepositoryFactory).Name, String.Format("RegisterFilter<{0}>", typeof(TEntity).Name)); }