Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# unity interception by attribute

Is there a way on how to use interception by attribute in C# unity and keep the object registration code in XML file(like app.config)? If yes, can you provide me with code, how should such registration look? I did a lot of workaround but did not find some working solution for this issue.

like image 705
TechCrap Avatar asked Jun 13 '13 15:06

TechCrap


People also ask

What do you mean by C?

C is an imperative procedural language supporting structured programming, lexical variable scope, and recursion, with a static type system. It was designed to be compiled to provide low-level access to memory and language constructs that map efficiently to machine instructions, all with minimal runtime support.

Is C language easy?

Compared to other languages—like Java, PHP, or C#—C is a relatively simple language to learn for anyone just starting to learn computer programming because of its limited number of keywords.

What is %d in C programming?

In C programming language, %d and %i are format specifiers as where %d specifies the type of variable as decimal and %i specifies the type as integer. In usage terms, there is no difference in printf() function output while printing a number using %d or %i but using scanf the difference occurs.

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.


2 Answers

I'm assuming you mean using a custom attribute to indicate what methods to intercept. You can use policy injection to achieve interception using XML configuration.

First, let's define a custom attribute:

[AttributeUsage(AttributeTargets.Method)]
public class MyInterceptionAttribute : Attribute
{
}

Next we can create an ICallHandler to do some interception work. This implementation will just do a Console.WriteLine before and after the method:

public class MyLoggingCallHandler : ICallHandler
{
    IMethodReturn ICallHandler.Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        Console.WriteLine("Invoking " + input.MethodBase.Name);
        IMethodReturn result = getNext()(input, getNext);
        Console.WriteLine("Done Invoke");
        return result;
    }

    int ICallHandler.Order { get; set; }
}

Next let's assume that we have some interface and an implementation:

public interface IMyClass
{
    void Do();
    void DoAgain();
}

public class MyClass : IMyClass 
{
    [MyInterception]
    public void Do()
    {
        Console.WriteLine("Do!");
    }

    public void DoAgain()
    {
        Console.WriteLine("Do Again!");
    }
}

Notice that I've applied the custom attribute, MyInterception, to only the Do method but not the DoAgain method. We will intercept all calls to the Do method.

Next we create the configuration to define a policy, configure the matching rule and register the type along with an interceptor:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <namespace name="UnityCallHandlerConfig" />
    <assembly name="UnityCallHandlerConfig"  />
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>
    <container>
      <extension type="Interception"/>
      <interception>
        <policy name="Policy">
          <matchingRule name="Match" type="Microsoft.Practices.Unity.InterceptionExtension.CustomAttributeMatchingRule, Microsoft.Practices.Unity.Interception">
            <constructor>
              <param name="attributeType" value="UnityCallHandlerConfig.MyInterceptionAttribute, UnityCallHandlerConfig" typeConverter="AssemblyQualifiedTypeNameConverter" />
              <param name="inherited">
                <value value="false"/>
              </param>
            </constructor>
          </matchingRule>
          <callHandler name="MyLogging" type="MyLoggingCallHandler">
            <lifetime type="singleton"/>
          </callHandler>
        </policy>
      </interception>
      <register type="IMyClass" mapTo="MyClass">
        <interceptor type="InterfaceInterceptor"/>
        <interceptionBehavior type="PolicyInjectionBehavior"/>
      </register>
    </container>
  </unity>

  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
  </startup>
</configuration>

We also need a type converter to convert the string representation of the custom attribute to the proper type:

public class AssemblyQualifiedTypeNameConverter : ConfigurationConverterBase
{
    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        if (value != null)
        {
            Type typeValue = value as Type;
            if (typeValue == null)
            {
                throw new ArgumentException("Cannot convert type", typeof(Type).Name);
            }

            if (typeValue != null) return (typeValue).AssemblyQualifiedName;
        }
        return null;
    }

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        string stringValue = (string)value;
        if (!string.IsNullOrEmpty(stringValue))
        {
            Type result = Type.GetType(stringValue, false);
            if (result == null)
            {
                throw new ArgumentException("Invalid type", "value");
            }

            return result;
        }
        return null;
    }
}

Once we have all that set up we can create a container and load the configuration:

var container = new UnityContainer().LoadConfiguration();

var myClass = container.Resolve<IMyClass>();
myClass.Do();
myClass.DoAgain();

The output will be:

Invoking Do
Do!
Done Invoke
Do Again!

showing that the first method is intercepted while the second is not.

like image 66
Randy supports Monica Avatar answered Nov 10 '22 23:11

Randy supports Monica


This is an old question but was really useful to me so I'll add the C# version of the unity configuration.

container.Configure<Interception>()
            .AddPolicy("LoggingPolicy")
            .AddMatchingRule(new CustomAttributeMatchingRule(typeof(MyInterceptionAttribute), false))
            .AddCallHandler<MyLoggingCallHandler>();
container.RegisterType<IMyClass , MyClass>(new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<PolicyInjectionBehavior>());
like image 32
MichaelChan Avatar answered Nov 10 '22 21:11

MichaelChan