Restrict attribute usage to be mutually exclusive at design time? - c#

I'm developing a serialization class that uses attributes on custom classes to decorate whether a property is a fixed length format or a delimited format. These two attributes should be mutually exclusive, meaning that the developer can either specify [FixedLength] or [Delimited] (with appropriate constructors) on a property, but not both. In order to reduce complexity and increase cleanliness, I don't want to combine the attributes and set a flag based on the format type, e.g. [Formatted(Formatter=Formatting.Delimited)]. Is it possible to restrict these attributes to be mutually exclusive to one another at design time? I'm aware how I can check for this scenerio at run-time.

You cannot do this in .NET. At most you can allow a single instance of the same attribute on a class, like in this example:
using System;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
class BaseAttribute : Attribute {
}
[Base]
[Base] // compiler error here
class DoubleBase {
}
But this behavior cannot be extended to derived classes, i.e. if you do this it compiles:
using System;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
class BaseAttribute : Attribute {
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
class Derived1Attribute : BaseAttribute {
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
class Derived2Attribute : BaseAttribute {
}
[Derived1]
[Derived2] // this one is ok
class DoubleDerived {
}
The best I can think of is that you could write something to check that there are no types with both attributes applied and use the check as a post-build step.

Related

ABP Appservice Authorized by default

We're using ABP 7.3
We'd like for all classes inheriting from the [project]AppServiceBase to be authorized by default so their methods are only available to users which are logged in. There are some exceptions (off course), in those cases we use the [AbpAllowAnonymous] attribute.
We could (of course) decorate every class with the [AbpAuthorize] attribute but that's asking for problems since someone might forget to do that (ask me how I know) and then that functionality is publicly available.
I tried putting the [AbpAuthorize] attribute on the [project]AppServiceBase (from which all xxxAppService class inherits) but the attribute doesn't get inherited by the subclass.
I then created a myAbpAuthorize attribute and put that on the [project]AppServiceBase, that works, now the subclasses have this attribute as well, but the authorization part doesn't work.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class MyAbpAuthorizeAttribute : AbpAuthorizeAttribute
{
}

Is it possible to extend an attribute?

In an app, I use different frameworks/technologies to serialize/deserialize objects. To ignore properties in the objects there are attributes like BsonIgnore or JsonIgnore.
[JsonIgnore]
[BsonIgnore]
public bool MyProperty
{
get;
set;
}
How can I create an attribute that extends from BsonIgnore and JsonIgnore so that I only need to specify one attribute for MyProperty?
The following does not work as an attribute has to extend System.Attribute.
[AttributeUsage(AttributeTargets.Class)]
public class MyIgnoreAttribute : BsonIgnore, JsonIgnore
{ ... }
-------------------------
[MyIgnore]
public bool MyProperty
{
get;
set;
}
C# doesn't support multiple-inheritance, and each of those types is sealed, so they couldn't be inherited from anyway. But there may be a different approach to do what you're trying to do.
If it is a predictable thing, for example: if something which has one attribute should always have the other attribute; you could use Aspect-Oriented Programming to inject the other attribute at compile time.
Your next question is going to be "how do I do that?", the answer to which will depend on what product you use.
Your question after that will be "which product should I use to do AOP?", which is off-topic, as shown here (hint: take a look at the linked page).
It's useless and impossible.
Look at source code of JsonIgnoreAttribute:
namespace Newtonsoft.Json
{
/// <summary>
/// Instructs the <see cref="T:Newtonsoft.Json.JsonSerializer" /> not to serialize the public field or public read/write property value.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public sealed class JsonIgnoreAttribute : Attribute
{
}
}
As you see, it does nothing.
In newtonsoft framework there is a code, that check that property has JsonIgnoreAttribute and do special work for that. It expects JsonIgnoreAttribute only.
Also, JsonIgnoreAttribute is sealed, you can't extend it.

Why is the C# SerializedAttribute is sealed?

I was trying to create an attribute that implies [Serializable] but I noticed that this SerializableAttribute class is sealed.
In Java it was possible to create an interface (say, MyInterface) that is inherited from Serializable interface and so all the subclasses of MyInterface would also be serializable, even its sub-sub classes would be so.
Let's say I am creating an ORM and I want customers to annotate their entity classes as [DatabaseEntity] but in order to make sure that entities are serializable, I also need to ask them to attribute their classes with extra [Serializable] which does not look quite compact and neat.
I am wondering why SerializableAttribute class is sealed and why has Inherited=false which implies that subclasses of serializable class will not be serializable unless it is explicitly stated. What motives are behind these design choices?
The SerializableAttribute is only used by the BinaryFormatter. If you are writing your own serialiser then don't worry about.
The sealed keyword is applied to the attribute not the class associated with the attribute. It is saying that the SerializableAttribute cannot be subclassed.
The BinaryFormatter uses an opt-in model. Any class (or subclass) must specify that it is serializable. This why the Inherited=false is used.
It's suggested best practice that all .Net attributes should be sealed, according to Microsoft:
The .NET Framework class library provides methods for retrieving custom attributes. By default, these methods search the attribute inheritance hierarchy; for example System.Attribute.GetCustomAttribute searches for the specified attribute type, or any attribute type that extends the specified attribute type. Sealing the attribute eliminates the search through the inheritance hierarchy, and can improve performance. [my emphasis]
So [Serializable] is sealed because it's quicker for .Net reflection to check the attributes. The cost is that you can't inherit and extend SerializableAttribute.
You can make your own un-sealed attributes if you want (you'll get code analysis warnings though).
This gets a little confusing with how attributes are used in inheritance for the classes that they apply to. It's probably best to use an example:
[Serializable]
public class A
{
public int SimpleSerialisableProperty { get; set;}
}
public class B : A
{
public C ComplexReferenceProperty { get; set; }
}
[Serializable]
public class D : A
{
public bool AnotherSerialisableProperty { get; set;}
}
You asked why SerializableAttribute.Inherited = false and this is why:
Class A is marked as [Serializable], and it is.
However class B inherits A and extends it with properties that are not serialisable. If .Net tries to serialise B it will encounter an error.
That Inherited = false tells .Net that just because A has been marked as [Serializable] not every class that inherits it will be serialisable too.
Now class D inherits A and is serialisable, so it gets its own [Serializable] attribute.
Finally, in terms of design attributes are a great way of extending behaviour (nice UI editors in property grids, etc). However they are terrible at enforcing it. If you need your customers to implement their entity classes in a particular way then an abstract base class or an interface is a much better way to go. If you make it an attribute then you're basically letting them know that [Serializable] is an option that you can handle either way.
Serialization is not a magic thing and you don't need any attribute to serialize an object. It is a process of writing your class' properties and fields to a stream (and attributes are only directives to serializers about how to behave while outputting an object).
See this over-simplified serializer code which totally ignores all attributes including NonSerializable
object obj = yourObject;
var props = obj.GetType()
.GetProperties()
.ToDictionary(p => p.Name, p => p.GetValue(obj, null));
string serializedText = String.Join("\n",
props.Select(kv => kv.Key + "=" + kv.Value ?? kv.Value.ToString()));
Above code, for example, would give
IsEmpty=False
X=3
Y=5
for object obj = new Point(3,5);
Deserialization process would be to read these values and set the properties back accordingly.
Put the [Serializable] attribute on top of the class you want serialized. Serialization is opt-in process. You have to manually do that for each class you want serialized. There are bunch of other keywords.

Why ValidationAttribute.IsValid is called later than expected?

I have a property annotated with a validation attribute.
Why is the setter on the property called before the IsValid method of the attribute, and more importantly how do i get it to validate before setting the value ?
Here is a sketched code model to see how the validator attribute looks like:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class MyAttribute: ValidationAttribute
{
public override bool IsValid(object value)
{
...
}
}
Here is how the attribute is used on the property:
[MyAttribute]
public string MyProperty
{
get { ... }
set { ... }
}
I assume you're talking about the ValidationAttribute within the DataAnnotations namespace? These attributes are used to generally describe validation requirements, without any particular prescribed model.
But, in many cases, it makes sense for an object or set of objects to be constructed, and then for a call to be made to ask "Is this now valid?" - so, of course, in such a case, the call to your IsValid method will occur well after the value of the property was set.
Attributes, in general, are passive - until such time as something actually accesses the attribute programatically and does something with it, none of your code within the attribute will run. There's no general way to write an attribute that says "when the member that this attribute is attached to is invoked, run this piece of code first".

Why is .Net best practice to design custom attributes as sealed?

I'm reading Pro C# 2010 and the .Net 4 Platform by Andrew Troelsen.
In Chapter 15 about Attributes exists a note:
Note: For security reasons, it is considered a .Net best practice to design all custom attributes as sealed.
The author doesn't explain why, can someone explain why?
CA1813: Avoid unsealed attributes:
The .NET Framework class library provides methods for retrieving
custom attributes. By default, these methods search the attribute
inheritance hierarchy; for example Attribute.GetCustomAttribute
searches for the specified attribute type, or any attribute type that
extends the specified attribute type. Sealing the attribute eliminates
the search through the inheritance hierarchy, and can improve
performance.
Ref: https://learn.microsoft.com/visualstudio/code-quality/ca1813-avoid-unsealed-attributes
Attributes are simply metadata discovered at runtime. As it is quoted, if someone else derives from your custom attribute class, by default .NET will find them too, which may imply a security risk if the derived attribute class is modifying the behavior of your original attribute in a way to you never intended to.
Even though performance is the prime reason to seal attribute classes, here is a formidable article dealing with its security side.
There is one more reason to seal attributes.
Consider the following attribute:
[AttributeUsageAttribute(AttributeTargets.Class, AllowMultiple = false)]
public class Attr1 : Attribute
{
}
Here you allow only single attribute decoration: AllowMultiple = false
Compiler won't allow this:
[Attr1]
[Attr1]
public class Foo
{
}
Later in your code you can safely call memberInfo.GetCustomAttribute() which will throw AmbiguousMatchException if more then one attribute of the given type was found.
Let's now inherit:
public class Attr2 : Attr1
{
}
Now compiler is silent.
[Attr1]
[Attr2]
public class Foo
{
}
So if later somebody inherits from your attribute and passes back to your code some entity marked with both attributes unexpected exception will be thrown.
Full example:
class Program
{
static void Main(params string[] args)
{
typeof(Foo).GetCustomAttribute<Attr1>();
}
[AttributeUsageAttribute(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class Attr1 : Attribute
{
}
public class Attr2 : Attr1
{
}
[Attr1]
[Attr2]
public class Foo
{
}
[Attr1]
public class Bar : Foo
{
}
}
Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries just says:
DO seal custom attribute classes, if possible. This makes the look-up for the attribute faster.
I didn't see anything about security in that section, but #Teoman Soygul makes a good point. So I'd agree with Mr. Troelsen.

Categories

Resources