Injection using Attributes - c#

I'm not sure this is what it's called, but here's what I'm trying to achieve:
I need to be able to specify an Attribute to properties, fields and classes, and every time an object with the [Attribute] specified will call a certain static function.
I already know how to set up the attribute, but I'm not sure how to go about intercepting the creation of every object and calling the function on it.

You cannot intercept an object being created without inserting some sort of code into the class itself, or creating a Factory around the class to manage instantiation.
Assuming you have a class like this:
public class MyData
{
[Captialization]
public string Name { get; set; }
}
With an attribute defined like this:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Class)]
public class CaptializationAttribute : Attribute { }
You can detect and manipulate the properties tagged with various attributes like this:
public static class DataUtilities
{
public static void ApplyAttributes<T>(T obj)
{
// Capitalization attribute
var props = typeof (T).GetProperties().Where(p => p.GetCustomAttributes(typeof (CaptializationAttribute), true).Any());
foreach (var prop in props)
{
// This is just an example, if you use this code you
// should check if the property is a string first!
prop.SetValue(obj, prop.GetValue(obj).ToString().ToUpper());
// Or perform some other manipulation here.
}
}
}
Now, to invoke this code automatically, you need to decide when you want it to occur. If it's well after the instantiation, you'll likely have to call it yourself from somewhere. But if it's during instantiation, you can do one of two things:
Using a Factory:
public static class MyDataFactory
{
public static MyData Create()
{
var myData = new MyData();
DataUtilities.ApplyAttributes(myData);
return myData;
}
}
You'll likely want to use an internal constructor to prevent outside instantiation.
// No instantiation from outside the assembly
internal MyData() { }
Using the constructor:
Add the call to the manipulation utility into your constructor:
public MyData()
{
DataUtilities.ApplyAttributes(this);
}
There are other methods of doing this, such as using a Proxy, Dependency Injection, or as #Yuval Itzchakov mentioned, an AOP framework, but the ones I described are probably the easiest to implement.

Related

C# Read attributes from Generic class without instance

Problem Description
I'm trying to implement a very specific sort of cache of objects that I may not be able to instantiate directly (private constructors for instance)
What I want to do is read some information about the particular class, preferably through some kind of interface (which sadly doesn't support static methods defined for every subclass)
In other words:
public class Data
{
public static bool Attribute1() => False;
private Data(...) { ... }
}
public class Cache<T> // T is for instance Data
{
void SomeMethod()
{
bool Value = T.Attribute1()
...
}
}
It's fine if I can make T inherit from some base class or some interface, and to get the attribute through some sort of method or directly. It is very important though that I can
Program multiple data classes A and B, where A.Attribute1() is different from B.Attribute1()
Get the attribute from the data class type without instantiating the data type
Current Solution
I do currently have a solution in the shape of a registry built when the static objects are initialised, like this:
class CacheAttributesRegistry
{
static RegisterAttributes(Type T, bool Attribute1, ...) { ... }
}
class Data
{
static Data() { RegisterAttributes(typeof(Data), true, ...); }
}
class Cache<T>
{
void SomeMethod()
{
bool Value = CacheAttributesRegistry.Attribute1(typeof(T));
}
}
It does exactly what I want, but I'd prefer avoiding a static constructor in every data class, also I don't want it to be possible to accidentally call RegisterAttributes at runtime.
Preferably I'd also avoid reflection because I'd like it to be obvious how to set the attributes for a class without the code magically inferring it in the background.
Am I missing some option or have I just reached some language limitations?

AutoFixture create property with internal setter

Is there some kind of way to let AutoFixture create properties with an internal setter?
I've looked at the AutoFixture source and found that in the AutoPropertiesCommand the GetProperties method checks whether a property has GetSetMethod() != null.
With an internal setter this returns null, unless you set the ignorePublic argument to true.
The easiest thing would of course be to make the setter public but in the project I'm working on this just wouldn't be the right solution.
Below is a simplified piece of code from the project as an example.
public class Dummy
{
public int Id { get; set; }
public string Name { get; internal set; }
}
public class TestClass
{
[Fact]
public void Test()
{
var dummy = new Fixture().Create<Dummy>();
Assert.NotNull(dummy.Name);
}
}
Ideally, the tests shouldn't have to interact with the internal members of a class, since they are explicitly excluded from its public API. Instead, these members would be tested indirectly by the code paths initiated through the public API.
However, if this isn't feasible in your particular situation, a possible workaround could be to explicitly assign a value to the internal properties from within the tests.
You can do that in one of two ways:
By exposing all internal members within the assembly to the test project using the InternalsVisibleTo attribute.
By representing the modifiable state of the class in a specific interface and implement that explicitly.
In your example, option 1 would be:
// [assembly:InternalsVisibleTo("Tests")]
// is applied to the assembly that contains the 'Dummy' type
[Fact]
public void Test()
{
var fixture = new Fixture();
var dummy = fixture.Create<Dummy>();
dummy.Name = fixture.Create<string>();
// ...
}
Option 2, instead, would be something like:
public class Dummy : IModifiableDummy
{
public string Name { get; private set; }
public void IModifiableDummy.SetName(string value)
{
this.Name = value;
}
}
[Fact]
public void Test()
{
var fixture = new Fixture();
var dummy = fixture.Create<Dummy>();
((IModifiableDummy)dummy).SetName(fixture.Create<string>());
// ...
}
Option 1 is fairly quick to implement, but has the side effect of opening up all internal members within the assembly, which may not be what you want.
Option 2, on the other hand, allows you to control what part of the object's state should be exposed as modifiable, while still keeping it separated the object's own public API.
As a side note, I'd like to point out that, since you're using xUnit, you can take advantage of AutoFixture's support for Data Theories to make your tests slightly more terse:
[Theory, AutoData]
public void Test(Dummy dummy, string name)
{
((IModifiableDummy)dummy).SetName(name);
// ...
}
If you prefer to set the Name property to a known value while still keeping the rest of the Dummy object anonymous, you have also the possibility to combine the two within the same Data Theory:
[Theory, InlineAutoData("SomeName")]
public void Test(string name, Dummy dummy)
{
((IModifiableDummy)dummy).SetName(name);
// ...
}

Handling custom attributes

I have a custom attribute now I didn't know that how to restrict the access to the method on which I have applied my attribute.
For example: I have custom attribute say "CustomRole" now if value of CustomRole is "Admin" then and only then it should access method.
CustomRole["Admin"]
public void Method()
{
// code
}
How to perform verify the value?
You need some kind of aspect oriented programming approach here. Attribute itself can't 'access' the method as it is not evaluated by the runtime, but you might use some framework which will intercept the call, check the attribute and context and properly handle the case.
So in short, you will:
decorate a method with an attribute
provide an interceptor to handle the call
instantiate the class via some tools which provides AOP functionality
execute the call. The call will be intercepted and handled according to your implementation
Specifying the requirements
As you already noted, this can be easily specified with attributes:
[RequiredPermission(Permissions.CanCreateOrder)]
public virtual Guid CreateOrder(string orderCode) {...}
Intercepting the call
Now you need to pick a tool which will instantiate your object and intercept calls to it. This can be done with IoC containers which support AOP, or you can wrap it manually (e.g. use an AOP tool to create a proxy to the object and use the proxy).
You need to write an interceptor, or a wrapper method which has a chance to evaluate the call context before forwarding the execution to your method or rejecting the call.
You can find a discussion and code samples here. Take a look at OrderManagementService class which declares requirements via attribute.
Poor man's AOP
You can do all of this without resorting to proper AOP tools, but in a less generic way (which may be perfectly fine for simpler projects), using some form of Decorator pattern - please note, this is written from head, not in IDE:
interface IService
{
void Method();
}
class ServiceImpl : IService // one of many implementations
{
[CustomRole("Admin")]
public void Method() { ... }
}
class ServiceChecker : IService // one of many implementations
{
IService m_svc;
public ServiceChecker(IService wrapped) { m_svc = wrapped; }
public void Method()
{
var mi = m_svc.GetType().GetMethod("Method");
if(mi.IsDefined(typeof(CustomRoleAttribute), true)
{
CustomRoleAttribute attr = (CustomRoleAttribute)mi.GetCustomAttributes(typeof(CustomRoleAttribute), true)[0];
if(!attr.Role.Equals( GetCurrentUserRole() ) // depends on where you get user data from
{
throw new SecurityException("Access denied");
}
}
m_svc.Method();
}
}
// the client code
IService svc = new ServiceChecker(new ServiceImpl());
svc.Method();
Your code looks a little bit wrong.
Here is my class with the method with a CustomRoleAttribute
public class MyClass
{
[CustomRole("Admin")]
public void MyMethod()
{
}
}
You attribute should define the AttributeUsage to ensure other developers not uses your attribute on a property or constructor:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false,Inherited = true)]
public class CustomRoleAttribute : Attribute
{
public string Role { get; private set; }
public CustomRoleAttribute(string role)
{
Role = role;
}
}
And now put both together:
MyClass myClass = new MyClass();
MethodInfo[] methods = myClass.GetType().GetMethods(); // Access all the public methods.
foreach (var methodInfo in methods) // iterate trough all methods.
{
// Get all custom attributes from the method.
object[] attributes = methodInfo.GetCustomAttributes(typeof (CustomRoleAttribute), true);
if (attributes.Length > 0)
{
CustomRoleAttribute attribute = (CustomRoleAttribute)attributes[0];
if (attribute.Role == "Admin")
{
// the role is admin
}
}
}
You see now, how to use attributes. Bu you must first check the attribute and than access the method.

Generate custom setter using attributes

In classes whose instances I persist using an object database, I keep having to do this:
private string _name;
public string Name
{
get { return this._name; }
set { _name = value; this.Save(); }
}
whereas I would much rather type this:
[PersistedProperty(Name)]
private string _name;
where the PersistedProperty attributes generates a Getter and Setter just like the default [Property()] attribute, except I want to add a line of code to the generated Setter.
Is there a way I can create an attribute which does this? Hopefully , which works with Intellisense.
How does the default [Property()] attribute even do it's stuff? If I saw the code I could graft that...
Note: I am actually doing this in Boo, but thought I'd give c# code as more people might be willing to answer that, however, if there is a Boo specific solution, I'm all ears!
Update:
My aim was simply to reduce typing and clutter. It turns out the simplest way of doing this was with a script which generates partial classes based on markup in my classes.
Auto-generating source code from markup (in tandem with partial classes) is easy, and actually looks like an extremely promising way to get round some of the problems we normally try to solve with inheritance and generic types.
This requires aspect oriented programming. While not directly supported in .NET, it can be done via third party tooling, such as PostSharp.
For intellisense to work, however, this must be done in a library, as the (final) compiled code will be unrolled into the full property getter/setter.
Not easy to implement using attributes IMO.
Maybe you could use another approach, such as an extension method:
// Extension method that allows updating a property
// and calling .Save() in a single line of code.
public static class ISaveableExtensions
{
public static void UpdateAndSave<T>(
this ISaveable instance,
Expression<Func<T>> propertyExpression, T newValue)
{
// Gets the property name
string propertyName = ((MemberExpression)propertyExpression.Body).Member.Name;
// Updates its value
PropertyInfo prop = instance.GetType().GetProperty(propertyName);
prop.SetValue(instance, newValue, null);
// Now call Save
instance.Save();
}
}
...
// Some interface that implements the Save method
public interface ISaveable
{
void Save();
}
...
// Test class
public class Foo : ISaveable
{
public string Property { get; set; }
public void Save()
{
// Some stuff here
Console.WriteLine("Saving");
}
public override string ToString()
{
return this.Property;
}
}
...
public class Program
{
private static void Main(string[] args)
{
Foo d = new Foo();
// Updates the property with a new value, and automatically call Save
d.UpdateAndSave(() => d.Property, "newValue");
Console.WriteLine(d);
Console.ReadKey();
}
}
It's type-safe, autocompletion-friendly, but it requires more code than just .Save() in all setters, so not sure I would use it actually...

Retrieving annotated method from attribute constructor

If I annotate a method of a class with an attribute, I can then retrieve custom attributes for that class and see if it has that attribute or not. For example, I'm building a message-oriented program so I have classes like
public class ErrorHandler
{
[HandleMessage(ErrorHandling.ERROR)]
private static void OnError(string message, object context, params object[] args)
{
Exception e;
args.Extract(out e);
Console.WriteLine(e.Message + Environment.NewLine + e.StackTrace);
}
}
At runtime I can do this:
public static void RegisterStaticHandlers(Type type)
{
foreach (var mInfo in type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static))
{
var mAttr = mInfo.GetCustomAttribute<HandleMessageAttribute>();
if (mAttr != null)
RegisterInstanceHandler(mAttr.Message, mInfo.CreateDelegate<MessageHandler>());
}
}
(I have some extension methods to simplify the code, they're not relevant now.)
My question is: can I get rid of this RegisterStaticHandlers method altogether and register the handler in the attribute constructor?
public class HandleMessageAttribute : Attribute
{
public string Message { get; private set; }
public HandleMessageAttribute(string message)
{
Message = message;
Messages.RegisterInstanceHandler(message, ... method reference here ...);
}
}
Is there a way to retrieve the method that is annotated by an attribute in the attribute constructor, instead of the opposite (and regular) way of having the method and getting its attributes?
[Edited]
I just realized that I can at least do this in the static constructor:
static ErrorHandler()
{
Messages.RegisterStaticHandlers(typeof(ErrorHandler));
}
This at least keeps the registration of a class inside that class, which is great as far as I'm concerned :)
In short, you can't do it from the attribute constructor, When the attribute is constructed it has no access to the target method/class/field/etc to which it is being applied.
From the code, I'm assuming you want the code to auto-register on startup? One way to do this might be to probe your assembly (once, at startup) - enumerate all classes (foreach(Type type in assembly)), finding those with candidate error handlers. This reduces the maintenance burden. Another option would be something similar using a configuration file.

Categories