Custom Assembly Attributes

Custom Assembly Attributes

Yes you can. We do this kind of thing.

[AttributeUsage(AttributeTargets.Assembly)]
public class MyCustomAttribute : Attribute {
string someText;
public MyCustomAttribute() : this(string.Empty) {}
public MyCustomAttribute(string txt) { someText = txt; }
...
}

To read use this kind of linq stmt.

var attributes = assembly
.GetCustomAttributes(typeof(MyCustomAttribute), false)
.Cast<MyCustomAttribute>();

AssemblyInfo and custom attributes

You need to provide a public member that exposes what you want to display:

[AttributeUsage(AttributeTargets.Assembly)]
public class AssemblyMyCustomAttribute : Attribute
{
public string Value { get; private set; }

public AssemblyMyCustomAttribute() : this("") { }
public AssemblyMyCustomAttribute(string value) { Value = value; }
}

Then cast the attribute and access the member:

var attribute = ViewContext.Controller.GetType().Assembly.GetCustomAttributes(typeof(AssemblyMyCustomAttribute), false)[0];

@(((AssemblyMyCustomaAttribute)attribute).Value)

How to use a custom attribute on an assembly in .NET Core 1.1

You can always create a new AssemblyInfo.cs file or any other .cs file to do the same.

However you can also use the new auto-generated assembly info mechanism. You can add this to your csproj file, replace the value replacing the Include attributes value with the type name of your custom attribute:

<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>DasMulli.Win32.ServiceUtils.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

[assembly: attribution ?? custom assembly attributes that executes code

When log4net assembly initializes, it searches for such attribute on the assembly level of your assembly and reads the provided values of properties (such as Watch=true) from it. According to those values, it decides how to configure the logging.

Getting custom assembly attributes without loading into current AppDomain

The short answer is, no, there's no way to do what you're asking.

The longer answer is this: There is a special assembly loading method, Assembly.ReflectionOnlyLoad(), which uses a "reflection-only" load context. This lets you load assemblies that cannot be executed, but can have their metadata read.

In your case (and, apparently, in every use case I could come up with myself) it's not really that helpful. You cannot get typed attributes from this kind of assembly, only CustomAttributeData. That class doesn't provide any good way to filter for a specific attribute (the best I could come up with was to cast it to a string and use StartsWith("[System.Diagnostics.Debuggable");

Even worse, a reflection-only load does not load any dependency assemblies, but it forces you to do it manually. That makes it objectively worse than what you're doing now; at least now you get the dependency loading automatically.

(Also, my previous answer made reference to MEF; I was wrong, it appears that MEF includes a whole ton of custom reflection code to make this work.)

Ultimately, you cannot unload an assembly once it has been loaded. You need to unload the entire app domain, as described in this MSDN article.

UPDATE:

As noted in the comments, I was able to get the attribute information you needed via the reflection-only load (and a normal load) but the lack of typed attribute metadata makes it a serious pain.

If loaded into a normal assembly context, you can get the information you need easily enough:

var d = a.GetCustomAttributes(typeof(DebuggableAttribute), false) as DebuggableAttribute;
var tracking = d.IsJITTrackingEnabled;
var optimized = !d.IsJITOptimizerDisabled;

If loaded into a reflection-only context, you get to do some work; you have to figure out the form that the attribute constructor took, know what the default values are, and combine that information to come up with the final values of each property. You get the information you need like this:

var d2 = a.GetCustomAttributesData()
.SingleOrDefault(x => x.ToString()
.StartsWith("[System.Diagnostics.DebuggableAttribute"));

From there, you need to check the ConstructorArguments to see which constructor was called: this one with one argument or this one with two arguments. You can then use the values of the appropriate parameters to figure out what values the two properties you are interested in would have taken:

if (d2.ConstructorArguments.Count == 1)
{
var mode = d2.ConstructorArguments[0].Value as DebuggableAttribute.DebuggingModes;
// Parse the modes enumeration and figure out the values.
}
else
{
var tracking = (bool)d2.ConstructorArguments[0].Value;
var optimized = !((bool)d2.ConstructorArguments[1].Value);
}

Finally, you need to check for NamedArguments that might override those set on the constructor, using for example:

var arg = NamedArguments.SingleOrDefault(x => x.MemberInfo.Name.Equals("IsJITOptimizerDisabled"));
var optimized = (arg == null || !((bool)arg.TypedValue.Value));

On one final note, if you are running this under .NET 2.0 or higher, and haven't already seen in, MSDN points this out in the DebuggingModes documentation:

In the .NET Framework version 2.0, JIT tracking information is always generated, and this flag has the same effect as Default with the exception of the IsJITTrackingEnabled property being false, which has no meaning in version 2.0.

Calling Custom Assembly Attributes

You have to use Reflection to get attribute information and value, and you will need one proc for each attribute.

First though, your sample Attribute class is missing a key item: HOW TO RETURN the info. You need to add a property getter:

Friend ReadOnly GetBuild() As String
Get
Return _p1
End Get
End Property

NOW you are ready

Friend Function GetAsmBuild() As String
Dim assy As [Assembly] = [Assembly].GetExecutingAssembly
Dim Attributes As Object()

Attributes = assy.GetCustomAttributes(GetType(AssemblyBuildNameAttribute), False)
If Attributes.Length > 0 Then
Return Attributes(0).GetBuild
Else
Return String.Empty
End If

End Function

GetVersion is the name of the Property getter. So for the one I added it would be:

Return Attributes(0).GetBuild

It is about the same as getting Attr for Classes or Enums etc. Also: Assemblies already have a version and such you can control in the Project properties settings. And procs already exist in System.Reflection to return them.

Edit:

The way to get the info at runtime:

Public Shared Function VersionPatch() As String
Return GetAsmBuild
End Function

or name my proc VersionPatch

Custom Assembly Attribute to String

you just need a cast, as Assembly.GetCustomAttributes(xxx) return type is Object[]

so

ViewBag.Version = (attr[0] as SmverAttribute).getversion;

EDIT

this could be rewritten like that (for example)

var attribute = Assembly.GetExecutingAssembly()
.GetCustomAttributes(false)
.OfType<SemverAttribute>()
.FirstOrDefault();

ViewBag.version = (attribute == null)
? string.Empty
: attribute.getversion;

How to get custom attributes from an assembly that is not (really) loaded

After checking all answers and doing some more research, it seems that there is simply no way to do what I want: check if an assembly is a valid extension module before loading it into the application domain.

Either I have to load the assembly that should be inspected into another application domain, inspect it there and when it succeeds load it again into my current application domain or I need to store metadata of the assembly outside the assembly itself and trust this metadata. Option one is not possible because of architectural restrictions, option two just shifts the problem but not solves it.

Probably the best alternative is to use the Managed Extensibility Framework, but this is unfortunately not that easy in the current setup.

I end up with trusting that there is nothing "bad" in the modules directory and loading everything (with some checks for not exceeding a maximum file size and not being loaded already).

Nevertheless, thank you for your ideas.



Related Topics



Leave a reply



Submit