| Severity | Error |
| Reported by | PostSharp |
| Message | Cannot apply the multicast attribute "<Attribute>" to the parameters or the return value of the method "<Method>" because the method is located outside the current assembly. |
Cause
With the AttributeTargetAssemblies property, you can multicast an attribute to the declarations of a referenced assembly, when the AllowExternalAssemblies property of its usage allows it. PostSharp then processes the methods of the referenced assembly that the current assembly uses. It cannot add an attribute to the parameters or the return value of such a method, because they belong to the other assembly, which PostSharp does not modify. PostSharp reports PS0104 for each external method that the attribute reaches when the attribute targets parameters (Parameter) or return values (ReturnValue).
<Attribute> is the attribute class, and <Method> the external method. The location of the message is the method in the source of the other assembly, when PostSharp can find it.
In the following example, the [Sensitive] attribute is multicast to the cardNumber parameter of PaymentGateway.Charge, which is in another assembly.
// @SkipPostSharpOnDependency
// @DisabledMessages(PS0131)
using System;
using System.Linq;
using System.Reflection;
using Errors.PS0104_Error.Payments;
using PostSharp.Extensibility;
// The attribute is multicast to the parameters of PaymentGateway, which is in another assembly.
[assembly: Errors.PS0104_Error.Sensitive(
AttributeTargetAssemblies = "PS0104_Error.Dependency",
AttributeTargetTypes = "Errors.PS0104_Error.Payments.PaymentGateway",
AttributeTargetParameters = "cardNumber" )]
namespace Errors.PS0104_Error;
// Marks the parameters whose values must not appear in logs.
[MulticastAttributeUsage( MulticastTargets.Parameter, AllowExternalAssemblies = true, PersistMetaData = true )]
[AttributeUsage( AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = true )]
public sealed class SensitiveAttribute : MulticastAttribute
{
}
public class CheckoutService
{
public string Checkout( string cardNumber, decimal amount ) => PaymentGateway.Charge( cardNumber, amount );
}
public static class Program
{
public static void Main()
{
foreach ( ParameterInfo parameter in typeof(CheckoutService).GetMethod( nameof(CheckoutService.Checkout) )!.GetParameters() )
{
Console.WriteLine( $"{parameter.Name}: {(parameter.GetCustomAttributes( typeof(SensitiveAttribute), false ).Any() ? "sensitive" : "not sensitive")}" );
}
Console.WriteLine( new CheckoutService().Checkout( "4111111111111111", 42m ) );
}
}
error PS0104: PS0104_Error.Dependency.cs(5,26): Cannot apply the multicast attribute "Errors.PS0104_Error.SensitiveAttribute" to the parameters or the return value of the method "Errors.PS0104_Error.Payments.PaymentGateway.Charge(System.String, System.Decimal)" because the method is located outside the current assembly.
Resolution
- Multicast the attribute to the parameters of the methods of the current assembly, for example to the methods that call the external method, by removing AttributeTargetAssemblies.
- When you own the other assembly, apply the attribute in that assembly.
- Narrow AttributeTargetElements so that the attribute does not target parameters or return values in the external assembly.
In the following example, the attribute is multicast to the cardNumber parameter of CheckoutService.Checkout, in the current assembly.
// @SkipPostSharpOnDependency
// @DisabledMessages(PS0131)
using System;
using System.Linq;
using System.Reflection;
using Errors.PS0104_Fixed.Payments;
using PostSharp.Extensibility;
// The attribute is multicast to the parameters of CheckoutService, which is in the current assembly.
[assembly: Errors.PS0104_Fixed.Sensitive(
AttributeTargetTypes = "Errors.PS0104_Fixed.CheckoutService",
AttributeTargetParameters = "cardNumber" )]
namespace Errors.PS0104_Fixed;
// Marks the parameters whose values must not appear in logs.
[MulticastAttributeUsage( MulticastTargets.Parameter, AllowExternalAssemblies = true, PersistMetaData = true )]
[AttributeUsage( AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = true )]
public sealed class SensitiveAttribute : MulticastAttribute
{
}
public class CheckoutService
{
public string Checkout( string cardNumber, decimal amount ) => PaymentGateway.Charge( cardNumber, amount );
}
public static class Program
{
public static void Main()
{
foreach ( ParameterInfo parameter in typeof(CheckoutService).GetMethod( nameof(CheckoutService.Checkout) )!.GetParameters() )
{
Console.WriteLine( $"{parameter.Name}: {(parameter.GetCustomAttributes( typeof(SensitiveAttribute), false ).Any() ? "sensitive" : "not sensitive")}" );
}
Console.WriteLine( new CheckoutService().Checkout( "4111111111111111", 42m ) );
}
}
cardNumber: sensitive
amount: not sensitive
Charged 42.00 to the card ending with 1111.
See Also
Reference
MulticastAttribute
MulticastAttributeUsageAttribute
Other Resources
Adding Aspects to Multiple Declarations Using Attributes
Understanding Attribute Multicasting