2013-06-13 22 views
7

Czy istnieje sposób na wykorzystanie przechwytywania przez atrybut w C# jedności i zachowanie kodu rejestracyjnego obiektu w pliku XML (jak app.config)? Jeśli tak, czy możesz podać kod, jak powinna wyglądać taka rejestracja? Zrobiłem dużo obejścia, ale nie znalazłem działającego rozwiązania dla tego problemu.Przechwytywanie jedności C# według atrybutu

Odpowiedz

14

Zakładam, że masz na myśli użycie niestandardowego atrybutu, aby wskazać metody przechwytywania. Za pomocą wtrysku zasad można uzyskać przechwycenie za pomocą konfiguracji XML.

Najpierw zdefiniować atrybut niestandardowy:

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

Następny możemy stworzyć ICallHandler popracować przechwytywania. Ta implementacja będzie po prostu zrobić Console.WriteLine przed i po metody:

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; } 
} 

Następnie załóżmy, że mamy jakiś interfejs i implementację:

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!"); 
    } 
} 

Zauważ, że mam zastosowany atrybut niestandardowy , MyInterception, tylko do metody Do, ale nie do metody DoAgain. Przechwycimy wszystkie połączenia do metody Do.

Następnie tworzymy konfigurację do określenia polityki, należy skonfigurować reguły dopasowania i zarejestrować typ wraz z kolektora:

<?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> 

Musimy również konwerter typu przekonwertować ciąg znaków reprezentujący atrybutu niestandardowego do właściwy typ:

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; 
    } 
} 

Gdy mamy wszystko skonfigurować możemy utworzyć kontener i załadować konfigurację:

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

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

Wydajność wynosi:

Invoking Do 
Do! 
Done Invoke 
Do Again! 

pokazując, że pierwszy sposób jest przechwytywane, a drugi nie.

+0

Wielkie dzięki za pomoc! –

+2

@ Tuzo, jak wyglądała konfiguracja w kodzie C#? Czy nadal potrzebujesz 'AssemblyQualifiedTypeNameConverter', jeśli jest to zrobione w kodzie? –

Powiązane problemy