通过fsharp 使用Enterprise Library Unity 4 - Policy Injection

policy interception
Interception class拦截器还可以用Policy 以一种更高效的方式进行加载使用。拦截和被拦截对象的关系常见的是一对多,因为被拦截的主要是对象的方法所以有时数量巨大。Policy具有定义匹配模式的功能,所以可以简化这一匹配工作,不用一一添加被拦截对象。匹配的模式有
Assembly name
Namespace
Type
Tag attribute
Custom attribute
Member name
Method signature
Parameter type
Property
Return type
有时候在Interception class中也可进行一些过滤,这部分工作也可以移转到这里进行。我猜想这里的效率更高一些。不过两处目的不同,不可一概而论。
照例,显示被拦截对象
open System
open System.Collections
open Microsoft.Practices.Unity
open Microsoft.Practices.Unity.InterceptionExtension

type ITenantStore = 
    abstract member Msg : unit->unit

type TenantStore() as x= 
    //do printfn "new TenantStore %A" (x.GetHashCode())
    abstract Msg : unit -> unit
    default x.Msg() = 
        printfn "Hello, it's TenantStore"
    abstract Dispose : unit -> unit
    default x.Dispose() = 
        printfn "TenantStore hase been cleaned"
    interface ITenantStore with
        member x.Msg() = 
            x.Dispose()                         //测试Virtual Method中拦截内部方法的结果
            x.Msg()
    interface IDisposable with
        member x.Dispose() = 
            x.Dispose()
声明实现ICallHandler接口的类。此处有一个地方需要注意。还是Fsharp语言的特性,无法隐式对接口进行转换。Fsharp的接口都是显示声明实现。如果不在类中暴露Order属性,在注册CallHandler的时候会提示缺少Order属性。好在ICallHandler接口比IInterceptionBehavior功能少,附加的点也就这一个。

type LoggingCallHandler() = 
    let WriteLog message = 
        printfn "From the logging interceptor: %A" message
    member val Order=0 with get,set
    interface ICallHandler with
        member x.Invoke((input:IMethodInvocation), (getNext:GetNextHandlerDelegate)) = 
            String.Format("Invoke method {0}:{2} at {1}", input.MethodBase, DateTime.Now.ToLongTimeString(), input.MethodBase.DeclaringType) |>  WriteLog
            let result = getNext.Invoke().Invoke(input, getNext)
            match result.Exception with
            | null ->
                String.Format("Method {0}:{3} returned {1} at {2}", input.MethodBase, result.ReturnValue, DateTime.Now.ToLongTimeString(), input.MethodBase.DeclaringType) |> WriteLog
            | _ ->
                String.Format("Method {0} threw exception {1} at {2}", input.MethodBase, result.Exception.Message, DateTime.Now.ToLongTimeString()) |> WriteLog
            result
        member x.Order with get()=x.Order and
                            set(v) = x.Order <- v
下面是具体的注册调用
using(new UnityContainer())(fun ctner->
    ctner.AddNewExtension<Interception>() |> ignore
    ctner.RegisterType<ITenantStore, TenantStore>(new InterceptionBehavior<PolicyInjectionBehavior>(),
                                                  new Interceptor<VirtualMethodInterceptor>()) |> ignore

    let first = new InjectionProperty("Order", 1)

    ctner.Configure<Interception>().AddPolicy("logging")
                                   .AddMatchingRule<MemberNameMatchingRule>(new InjectionConstructor([|"Msg"|], true))
                                   .AddCallHandler<LoggingCallHandler>(new ContainerControlledLifetimeManager(), new InjectionConstructor(),first) |> ignore

    showregistrations ctner
    let t = ctner.Resolve<ITenantStore>()
    t.Msg()
    )

从代码中可以看到使用了PolicyInjectionBehavior指出Policy行为,打了一个行为桩。后续往容器中添加定义的CallHandler。模式匹配的定义也在这里。简单期间我选用了MemberNameMatchingRule,选中Msg方法。这里的方面名也可以加入*号作为通配符。
运行的结果和之前用InterceptionBehavior的方法的结果是一样的。比较感兴趣的是Order参数的行为,因为Fsharp在这里不是直接引用接口中的Order属性。这一层多余的层次会不会影响到顺序的表现呢?
我添加了一个CallHandler并切断了包括前一个接口实现时,往后续Pipe传递的通路。
type LoggingCallHandler() = 
    let WriteLog message = 
        printfn "From the logging interceptor: %A" message
    member val Order=0 with get,set
    interface ICallHandler with
        member x.Invoke((input:IMethodInvocation), (getNext:GetNextHandlerDelegate)) = 
            String.Format("Invoke method {0}:{2} at {1}", input.MethodBase, DateTime.Now.ToLongTimeString(), input.MethodBase.DeclaringType) |>  WriteLog
            let result = input.CreateMethodReturn(0)  //break the pipe line
            //let result = getNext.Invoke().Invoke(input, getNext)
            match result.Exception with
            | null ->
                String.Format("Method {0}:{3} returned {1} at {2}", input.MethodBase, result.ReturnValue, DateTime.Now.ToLongTimeString(), input.MethodBase.DeclaringType) |> WriteLog
            | _ ->
                String.Format("Method {0} threw exception {1} at {2}", input.MethodBase, result.Exception.Message, DateTime.Now.ToLongTimeString()) |> WriteLog
            result
        member x.Order with get()=x.Order and
                            set(v) = x.Order <- v

type LoggingCallHandler2() = 
    let WriteLog message = 
        printfn "From the logging interceptor: %A" message
    member val Order=0 with get,set
    interface ICallHandler with
        member x.Invoke((input:IMethodInvocation), (getNext:GetNextHandlerDelegate)) = 
            String.Format("Invoke method2 {0}:{2} at {1}", input.MethodBase, DateTime.Now.ToLongTimeString(), input.MethodBase.DeclaringType) |>  WriteLog
            //let result = getNext.Invoke().Invoke(input, getNext)
            let result = input.CreateMethodReturn(0) //break the pipe line
            match result.Exception with
            | null ->
                String.Format("Method2 {0}:{3} returned {1} at {2}", input.MethodBase, result.ReturnValue, DateTime.Now.ToLongTimeString(), input.MethodBase.DeclaringType) |> WriteLog
            | _ ->
                String.Format("Method2 {0} threw exception {1} at {2}", input.MethodBase, result.Exception.Message, DateTime.Now.ToLongTimeString()) |> WriteLog
            result
        member x.Order with get()=x.Order and
                            set(v) = x.Order <- v


随后在调用时增加一块,切换 order顺序
using(new UnityContainer())(fun ctner->
    ctner.AddNewExtension<Interception>() |> ignore
    ctner.RegisterType<ITenantStore, TenantStore>(new InterceptionBehavior<PolicyInjectionBehavior>(),
                                                  new Interceptor<VirtualMethodInterceptor>()) |> ignore

    let first = new InjectionProperty("Order", 1)
    let second = new InjectionProperty("Order", 2)

    ctner.Configure<Interception>().AddPolicy("logging")
                                   .AddMatchingRule<MemberNameMatchingRule>(new InjectionConstructor([|"Msg"|], true))
                                   .AddCallHandler<LoggingCallHandler>(new ContainerControlledLifetimeManager(), new InjectionConstructor(),second) |> ignore

    ctner.Configure<Interception>().AddPolicy("logging2")
                                   .AddMatchingRule<MemberNameMatchingRule>(new InjectionConstructor([|"Msg"|], true))
                                   .AddCallHandler<LoggingCallHandler2>(new ContainerControlledLifetimeManager(), new InjectionConstructor(),first) |> ignore

    showregistrations ctner
    let t = ctner.Resolve<ITenantStore>()
    t.Msg()
    )

结果与设想一致。


用自定义参数监视接口
通过实现
type LoggingCallHandlerAttribute(od:int) =
    inherit HandlerAttribute()
    let order = od
    override x.CreateHandler(container:IUnityContainer) =
        let result = new LoggingCallHandler()
        result.Order <- order
        result :> ICallHandler

可以简化Policy的注册流程,之前如果说是大面积轰炸的话,现在则是精确战术打击。

type TenantStore()= 
    //do printfn "new TenantStore %A" (x.GetHashCode())
    abstract Msg : unit -> unit
    default x.Msg() = 
        printfn "Hello, it's TenantStore"
    abstract Dispose : unit -> unit
    default x.Dispose() = 
        printfn "TenantStore hase been cleaned"
    interface ITenantStore with
        [<LoggingCallHandler(1)>]
        member x.Msg() = 
            x.Msg()
    interface IDisposable with
        member x.Dispose() = 
            x.Dispose()
    member x.NewMethod() = 
        printfn "just test from TenantStore"


使用时不用注册policy了。
using(new UnityContainer())(fun ctner->
    ctner.AddNewExtension<Interception>() |> ignore
    ctner.RegisterType<ITenantStore, TenantStore>(new InterceptionBehavior<PolicyInjectionBehavior>(),
                                                  new Interceptor<InterfaceInterceptor>())|> ignore


    showregistrations ctner
    let t = ctner.Resolve<ITenantStore>()
    t.Msg()
    )

以上
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值