假设我有一个通过 WCF 公开的接口:
[ServiceContract]
interface IService
{
[OperationContract]
void Foo();
}
和一个实现:
[ServiceBehavior(...)]
class Service : IService
{
public void Foo() { /* impl */ }
}
我可以通过 WCF 发布 Service
并且一切正常。
现在,我想使用Unity来执行Service
的拦截。我可以为此使用 WCF 行为,但是 IService
(以及实现它的 Service
)有时由内部服务访问,而不是通过 WCF 访问,并且我需要一种拦截机制当通过 WCF 访问该类以及在本地访问该类时都适用。
我可以使用 Unity 的 InterfaceInterceptor 来实现此目的,但是我获得的代理将不具有 ServiceBehavior 属性,该属性显然会影响 WCF 行为,因此是必需的。
现在,我可以使用 TransparentProxyInterceptor
或 VirtualMethodInterceptor
,它们将从我的 Service
类继承(从而继承属性?),但是 >InterfaceInterceptor
似乎是在这种情况下使用的“正确”拦截器。毕竟我在这里使用的是接口。
查看Unity的代码,似乎InterfaceInterceptor
使用Reflection.Emit
来生成代理。如果仅使用 TypeBuilder.SetCustomAttributes,它可以简单地从我的原始类型复制属性并将它们应用到其代理。不过,我找不到 Unity 扩展点来执行此操作。我得到的最接近的是InterfaceInterceptorClassGenerator,但它也没有公开它的TypeBuilder。
有没有一种简单的方法来扩展InterfaceInterceptor以从底层实现复制属性?是否有另一种方法可以将 Service
上指定的 ServiceBehavior
应用于代理?
Suppose I have an interface exposed over WCF:
[ServiceContract]
interface IService
{
[OperationContract]
void Foo();
}
And an implementation:
[ServiceBehavior(...)]
class Service : IService
{
public void Foo() { /* impl */ }
}
I can publish Service
over WCF and everything works well.
Now, I want to use Unity to perform interception of Service
. I can use WCF behaviors for that, but IService
(and Service
that implements it) are sometimes accessed by internal services and not over WCF, and I want an interception mechanism that will apply both when the class is accessed over WCF and when it's accessed locally.
I can use Unity's InterfaceInterceptor
for this, but then the proxy that I get will not have the ServiceBehavior
attribute, which obviously affects the WCF behavior and is therefore needed.
Now, I can use TransparentProxyInterceptor
or VirtualMethodInterceptor
, which will inherit from my Service
class (and thus inherit the attributes?), but the InterfaceInterceptor
seems like the "right" interceptor to use in this case. I'm working with interfaces here, after all.
Looking at Unity's code, it seems that InterfaceInterceptor
uses Reflection.Emit
to generate the proxy. If only it used TypeBuilder.SetCustomAttributes
, it could simply copy the attributes from my original type and apply them to its proxy. I couldn't find a Unity extension point to do this, though. The closest I got was the InterfaceInterceptorClassGenerator
, but it too does not expose its TypeBuilder
.
Is there a simple way to extend the InterfaceInterceptor
to copy attributes from the underlying implementation? Is there another way to get the ServiceBehavior
specified on Service
to apply to the proxy?
发布评论
评论(2)
我认为您可以为您的场景添加一个新层,如下所示,
您可以对“ServiceImp”进行任何拦截” 实现 IServiceImp. Service 没有任何函数代码,只是一个扭曲器,仅用作 Service,不对 Service 进行任何拦截,Service 依赖于 ServiceImp(或 IServiceImp)可以通过Unity注入)。
现在您的本地可以使用 Service 或 ServiceImp。 WCF InstanceProvider 可以使用仍具有 ServiceBehavior 属性的 resovled Service。
I think you can add a new layer for your scenario as follows,
You can do any interception to "ServiceImp" that implement IServiceImp. Service do not have any function code but just a warpper and used as a Service ONLY, Do NOT do any interception to Service, Service has a dependency on ServiceImp(or IServiceImp which can be injected by Unity).
Now your local can use Service or ServiceImp. and WCF InstanceProvider can use resovled Service which still has ServiceBehavior attribute.
如果您使用的是 WCF,那么我不明白为什么您没有内部使用的端点。
例如,您可以使用命名管道传输,而不是使用网络传输。
使用另一个拦截框架(无论是Unity还是其他)的风险在于,无法保证您在拦截实现中保持平等。
也就是说,您最好也只在内部使用 WCF,以及适合您在该场景中的需求的通道。
请注意,您可以编写自己的传输(也许使用共享内存或类似的东西),这在同一应用程序域中进行调用时会更有效(假设您已经确定传输实际上是一个问题 em>)。
If you are using WCF, then I don't see why you wouldn't have an endpoint that you use internally.
Instead of using a network transport, for example, you'd use a named-pipe transport.
The risk in using another interception framework (whether it's Unity or another) is that you aren't guaranteed that you are maintaining parity in the interception implementations.
That said, you are better off just using WCF internally as well, along with a channel that suits your needs in that scenario.
Note that you can write your own transport (perhaps using shared memory, or something of the sort) which is more efficient when making calls in the same app domain (assuming you've determined that the transport actually is a problem).