Register multiple instance based off of custom attribute with name list - structuremap

I have a single rule that can handle multiple rule calls so I have created a custom attribute that is placed on the rule class. This attribute lists the names it is allowed to process. In structuremap I would like to register this same rule as multiple names by reading the custom attribute.
[RuleIdentifer(new string[] { "RunAction1","RunAction2","RunAction3" })]
I have tried to use the MissingNamedInstanceIs class but run into Bi-Directional dependency error. The following has been placed in the creation of the container after the Scan:
_.For<Rules.IRule>().MissingNamedInstanceIs.ConstructedBy("Pull Rule by Name from Attribute",r =>
{
return r.GetAllInstances<Rules.IRule>().FirstOrDefault<Rules.IRule>(r1 =>
{
var dnAttribute = r1.GetType().GetCustomAttributes(typeof(RuleIdentifer), true).FirstOrDefault() as RuleIdentifer;
if (dnAttribute != null && dnAttribute.Names.Contains<string>(r.RequestedName)) return true;
return true;
});
});
Is there a better way to do this in the scan section NameBy call:
x.AddAllTypesOf<Rules.IRule>().NameBy(t => t.Name);

When ahead and created my own RegistrationConvention. Work as expected now.
public class RuleAttributeConvention : IRegistrationConvention
{
public void ScanTypes(TypeSet types, Registry registry)
{
// Only work on concrete types
types.FindTypes(TypeClassification.Concretes | TypeClassification.Closed).Where(typ => typeof(Rules.IRule).IsAssignableFrom(typ)).ToList().ForEach(t =>
{
var dnAttribute = t.GetCustomAttributes(typeof(RuleIdentifer), true).FirstOrDefault() as RuleIdentifer;
if (null == dnAttribute) return;
foreach (var nm in dnAttribute.Names)
{
registry.For<Rules.IRule>().Use(t.Name).Name = nm;
}
});
}
}

Related

Entity Framework Core 7 apply custom ValueConverter to Inserts and Updates

I am struggling to understand how to apply a custom ValueConverter to all the properties of all the models before every insert and update.
According to this resource it can be done:
https://learn.microsoft.com/en-us/ef/core/modeling/value-conversions?tabs=data-annotations
"Value converters allow property values to be converted when reading from or **writing ** to the database"
I was able to accomplish this, but only when reading from the database, overriding ConfigureConventions in the Context:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Properties<string>().HaveConversion<ToUpperConverter>();
}
Converter
public class ToUpperConverter : ValueConverter<string, string>
{
public ToUpperConverter() : base(v => v, v => v.Trim().ToUpper())
{
}
}
Tried also to override the method SaveChangesAsync in the Context, this works but obviously I don't want to go manually for every property and for every model considering they can change at every time.
Using reflection here can be an option, but I am not really a big fan of it.
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
{
foreach (var entry in ChangeTracker.Entries<Player>())
{
if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
{
entry.Entity.Name = entry.Entity.Name.ToUpper();
entry.Entity.MiddleName = entry.Entity.MiddleName?.ToUpper();
entry.Entity.Surname = entry.Entity.Surname.ToUpper();
}
}
return await base.SaveChangesAsync(cancellationToken);
}
Solved, after spending on this an entire day..
The first argument of the converter is the conversion happening to the database, the second argument is the conversion happening from the database.
public class ToUpperConverter : ValueConverter<string, string>
{
public ToUpperConverter() : base(
// writing to the database
v => v.Trim().ToUpper(),
// reading from the database
v => v.Trim().ToUpper())
{
}
}
Source: https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.metadata.builders.propertiesconfigurationbuilder.haveconversion?view=efcore-6.0
"The type to convert to and from or a type that inherits from ValueConverter."

How to check if user is member of group

My goal is to check if user is member of specific active directory group.
In .net mvc i was using this code inside my service
HttpContext.Current.Request.LogonUserIdentity.Groups
.Any(x => x.Translate(typeof(NTAccount)).Value == "some role"
and it worked well.
In .net core mvc 2.1.2 i pass IHttpContextAccessor into service constructor and try to use following
_httpAccessor.HttpContext.User.Identity.LogonUserIdentity.Groups
but there is an issue, because Identity does not contains LogonUserIdentity. I tried to find any solution but i was not successful, how can i get the list of user groups or check if user is member of specific one ?
Except using built-in function which check the permission by "Roles", if you want to check by specific AD Group, you can also use below codes :
public static class Security
{
public static bool IsInGroup(this ClaimsPrincipal User, string GroupName)
{
var groups = new List<string>();
var wi = (WindowsIdentity)User.Identity;
if (wi.Groups != null)
{
foreach (var group in wi.Groups)
{
try
{
groups.Add(group.Translate(typeof(NTAccount)).ToString());
}
catch (Exception)
{
// ignored
}
}
return groups.Contains(GroupName);
}
return false;
}
}
And using as:
if (User.IsInGroup("GroupName"))
{
}

Is it possible to prevent Delegate Factory creation in Autofac?

I am updating a library that uses Autofac so that, in addition to the original configuration file (registered via Autofac), it can optionally take a function to accomplish that same goal (again, registered via Autofac). The original is something like this:
public MyClass(ConfigFile config = null)
{
this._activatorLoader = a => {
// old config code here...
}
}
The updated version I'd like is:
public MyClass(
Func<Input, IList<Activator>> activatorLoader = null,
ConfigFile config = null)
{
if (activatorLoader != null)
{
this._activatorLoader = activatorLoader;
}
else
{
this._activatorLoader = a => {
// old config code here...
}
}
}
The problem is that Autofac is seeing my request for a list of something and always providing the function. I tried switching to a delegate and get the same problem:
public delegate IList<Activator> ActivatorLoader(Input input);
public MyClass(
ActivatorLoader activatorLoader = null,
ConfigFile config = null)
{
if (activatorLoader != null)
{
this._activatorLoader = activatorLoader;
}
else
{
this._activatorLoader = a => {
// old config code here...
}
}
}
The loading of the activators must still be delayed, I'd like the flexibility of registering any function based on the situation, and old code (without an activator loader registered) should still work. Is there any way to prevent Autofac from autogenerating the Func?
The class will be instantiated through dependency injection in another class. At a later time, the activator loading code will be triggered (if needed).
var myObject = conatiner.Resolve<MyClass>();
// time passes...
myObject.DoActivatorLoading();
The primary goal is to prevent Autofac from creating the Func<Input, IList<Activator>> if it is not explicitly set. Is this possible?
Perhaps, it will be easier to create a separate class for activator loading ?
public class ActivatorsLoader
{
public IList<Activator> Load(Input input)
{
///
}
}
///
public Class(
ActivatorsLoader activatorsLoader = null,
ConfigFile config = null)
{
///
}
But it would be good to see the use cases of your Class.

Attribute.IsDefined returns false, Attribute.GetCustomAttribute returns null for defined ActionNameAttribute

I'm trying to set up some unit tests to ensure that URLs will be mapped to the appropriate controllers and actions according to a route-table, and that the target action-method and controller exists within the relevant assembly.
The only remaining problem I'm having is testing the existence of an action-method where an ActionNameAttribute has been applied to enable dash-separated action-name mappings, e.g., a "Contact Us" form url: /contact-us maps to the ContactUs method on a Forms controller because the ContactUs method signature is defined thusly:
[ActionName("contact-us")]
public ActionResult ContactUs()
I've set up the following method, which I am running inside each test, and works for all cases where the action-method name is not redefined with ActionNameAttribute:
private static bool ActionIsDefinedOnController(string expectedActionName, string controllerName, string assemblyName)
{
var thisControllerType = Type.GetType(AssemblyQualifiedName(controllerName, assemblyName), false, true);
if (thisControllerType == null)
return false;
var allThisControllersActions = thisControllerType.GetMethods().Select(m => m.Name.ToLower());
if( allThisControllersActions.Contains(expectedActionName.ToLower()))
return true;
var methods = thisControllerType.GetMethods();
//If we've so far failed to find the method, look for methods with ActionName attributes, and check in those values:
foreach (var method in methods)
{
if (Attribute.IsDefined(method, typeof(ActionNameAttribute))
{
var a = (ActionNameAttribute) Attribute.GetCustomAttribute(method, typeof (ActionNameAttribute));
if (a.Name == expectedActionName)
return true;
}
}
return false;
}
...but whenever a method's name is redifined with ActionNameAttribute, the check Attribute.IsDefined(method, typeof(ActionNameAttribute) is failing (returns false), even when I can see the attribute in the list of custom-attributes in my debugging session:
Why is this check failing, when it should be passing?
I've been able to construct a different check:
UPDATE I had pasted in the wrong code here initially, here's the revised:
List<string> customAttributes = method.GetCustomAttributes(false).Select(a => a.ToString()).ToList();
if (customAttributes.Contains("System.Web.Mvc.ActionNameAttribute"))
{
var a = (ActionNameAttribute) Attribute.GetCustomAttribute(method, typeof (ActionNameAttribute));
if (a.Name == expectedActionName)
return true;
}
...and now my condition is catching the cases where ActionNameAttribute is applied, but now Attribute.GetCustomAttribute() returns null. So I can't check the value of the action name to compare against the expected value... arrrrgh!
I would just have:
//If we've so far failed to find the method, look for methods with ActionName attributes, and check in those values:
foreach (var method in methods)
{
var attr = method.GetCustomAttribute<System.Web.Mvc.ActionNameAttribute>();
if (attr!=null && attr.Name == expectedActionName)
{
return true;
}
}
As I said in comment, I suspect that you're picking up the wrong ActionNameAttribute in your typeof calls, so I've been explicit

Windsor Interceptor Exception

I have a Windsor container that I'm using an InterceptorSelector and a LazyComponentLoader with.
My InterceptorSelector returns an InterceptorReference to my InterceptorAdapter class that looks like this
public class InterceptorAdapter<T> : Castle.DynamicProxy.IInterceptor, IOnBehalfAware where T : IMyType
{
private readonly T interceptor;
public InterceptorAdapter(T interceptor)
{
this.interceptor = interceptor;
}
....
}
so the InterceptorSelector does
public InterceptorReference[] SelectInterceptors(ComponentModel model, InterceptorReference[] interceptors)
{
var results = new List<InterceptorReference>();
....
foreach (var interceptorType in someInterceptorTypes)
{
Type interceptorAdapterType = typeof(InterceptorAdapter<>).MakeGenericType(interceptorType);
if (kernel.GetHandler(interceptorAdapterType) == null)
{
// need to do this or Castle complains it can't create my
// interceptor...I guess LazyComponentLoaders don't work for InterceptorReferences?...
// I suspect the problem may be here...
kernel.Register(lazyComponentLoader.Load(null, interceptorAdapterType, null));
}
results.Add(InterceptorReference.ForType(interceptorAdapterType));
}
return results.ToArray();
}
Things work great the first time my InterceptorSelector returns an InterceptorReference. The next time, when it returns an InterceptorReference to an InterceptorAdapter with a different generic type argument, I get
Castle.MicroKernel.ComponentRegistrationException occurred
Message=There is a component already registered for the given key interceptor
Source=Castle.Windsor
StackTrace:
at Castle.MicroKernel.SubSystems.Naming.DefaultNamingSubSystem.Register(String key, IHandler handler) in c:\TeamCity\buildAgent\work\1ab5e0b25b145b19\src\Castle.Windsor\MicroKernel\SubSystems\Naming\DefaultNamingSubSystem.cs:line 75
InnerException:
My LazyComponentLoader simply does
public IRegistration Load(string key, Type service, IDictionary arguments)
{
ComponentRegistration<object> component = Component.For(service).Named(key);
if (arguments != null)
{
// merge is an extension method to merge dictionaries.
component.DynamicParameters((k, d) => d.Merge(arguments));
}
return component;
}
My container setup looks like
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.AddFacility("factories", new FactorySupportFacility());
container.Register(Component.For<ILazyComponentLoader>().ImplementedBy<MyLazyComponentLoader>().LifeStyle.Singleton);
container.Kernel.ProxyFactory.AddInterceptorSelector(new InterceptorSelector(container.Kernel, container.Resolve<ILazyComponentLoader>()));
Any suggestions?
Thanks!
This seems to be a problem in the way Castle resolves Interceptors using an LazyComponentLoader.
Changing my code in the selector to do:
if (kernel.GetHandler(interceptorType) == null)
{
// need to do this or Castle complains it can't create my
// interceptor...I guess LazyComponentLoaders don't work for InterceptorReferences?...
// I suspect the problem may be here...
kernel.Register(lazyComponentLoader.Load(null, interceptorType, null));
}
Type interceptorAdapterType = typeof(InterceptorAdapter<>).MakeGenericType(interceptorType);
if (kernel.GetHandler(interceptorAdapterType) == null)
{
// need to do this or Castle complains it can't create my
// interceptor...I guess LazyComponentLoaders don't work for InterceptorReferences?...
// I suspect the problem may be here...
kernel.Register(lazyComponentLoader.Load(null, interceptorAdapterType, null));
}
Seems to fix the problem.

Resources