WCF自定义ServiceBehavior / InstanceProvider带参数的构造函数自定义、函数、参数、WCF

2023-09-06 22:53:04 作者:南巷挽清风

我们正在尝试使用依赖注入WCF服务。该服务有一个统一容器的依赖。该容器是用来发现,实现了一个 IJob 接口相应的类(根据在方法调用 JobKey 参数)并在其上调用方法

该服务被托管在MVC2。我省略了尽可能多的不相关的东西,可以从下面的代码片段。全部code可如果需要的话...

我到目前为止,完成的:

在此基础上 MSDN文章,我创建了一个自定义 InstanceProvider 这应该实例我的服务,并通过它的容器。

然后,我创建了一个非常诺迪 ServiceBehavior 使用 InstanceProvider 最后一个 BehaviorExtension 刚刚返回 ServiceBehavior

 公共类WCFDIInstanceProvider
    实现IInstanceProvider

    私人服务类型为类型

    私有财产_container作为IUnityContainer
    私人只读属性容器IUnityContainer
        得到
            如果_container是没有那么
                _container = InitialiseContainer()
            结束如果
            返回_container
        最终获取
    高端物业

    公共子新(BYVAL服务类型为类型)
        Me.ServiceType =服务类型
    结束小组

    专用功能InitialiseContainer()作为IUnityContainer
            code的扫描组件,并填充容器适当
            我相信这个code工作,因为我已经在其他地方进行了测试
        返回容器
    端功能

    公共职能的GetInstance(BYVAL的InstanceContext作为System.ServiceModel.InstanceContext)作为对象实现System.ServiceModel.Dispatcher.IInstanceProvider.GetInstance
        返回的GetInstance(的InstanceContext,为Nothing)
    端功能

    公共职能的GetInstance(BYVAL的InstanceContext作为System.ServiceModel.InstanceContext,BYVAL消息System.ServiceModel.Channels.Message)作为对象实现System.ServiceModel.Dispatcher.IInstanceProvider.GetInstance
        返回Container.Resolve(Me.ServiceType)
    端功能

末级
 

ServiceBehavior

 公共类WCFDIServiceBehavior
实现IServiceBehavior接口

    公用Sub ApplyDispatchBehavior(BYVAL serviceDescription作为System.ServiceModel.Description.ServiceDescription,BYVAL serviceHostBase作为System.ServiceModel.ServiceHostBase)实现System.ServiceModel.Description.IServiceBehavior.ApplyDispatchBehavior
        对于每个ChannelDispatcherBase作为ChannelDispatcherBase在serviceHostBase.ChannelDispatchers
            昏暗ChannelDispatcher作为ChannelDispatcher = TryCast(ChannelDispatcherBase,ChannelDispatcher)
            如果ChannelDispatcher状态并没有任何然后
                对于每个调度员EndpointDispatcher在ChannelDispatcher.Endpoints
                    Dispatcher.DispatchRuntime.InstanceProvider =新WCFDIInstanceProvider(serviceDescription.ServiceType)
                下一个
            结束如果
        下一个
    结束小组
 
Silverlight 4 MVVM with Commanding and WCF RIA Services

最后,的真正的诺迪BehaviorExtension:

 公共类WCFDIBehaviorExtension
    继承BehaviorExtensionElement

    公共覆盖只读属性BehaviorType作为的System.Type
        得到
            返回的GetType(WCFDIServiceBehavior)
        最终获取
    高端物业

    受保护的覆盖功能CreateBehavior()为对象
        返回新WCFDIServiceBehavior
    端功能
末级
 

在WCF配置工具似乎喜欢所有的上面,并产生了以下配置XML:

 < serviceHostingEnvironment multipleSiteBindingsEnabled =真
                             aspNetCompatibilityEnabled =真正的>
      < serviceActivati​​ons>
          <新增relativeAddress =WebJob.svc
               服务=MyApplication.WebJobService
               工厂=System.ServiceModel.Activati​​on.ServiceHostFactory/>
      < / serviceActivati​​ons>
  < / serviceHostingEnvironment>
< standardEndpoints>
  < mexEndpoint>
    < standardEndpoint名=WebJobServiceMex/>
  < / mexEndpoint>
< / standardEndpoints>
<行为>
  < serviceBehaviors>
    <行为NAME =WCFDIServiceBehavior>
      < serviceMetadata httpGetEnabled =真/>
      < serviceDebug includeExceptionDetailInFaults =真/>
      < WCFDIBehavior />
    < /行为>
  < / serviceBehaviors>
< /行为>
<服务>
  <服务名称=WebJobService>
    <端点地址=绑定=basicHttpBinding的bindingConfiguration =htt​​pBinding
      NAME =HTTPEndpoint合同=MyApplication.JobService.Common.IWebJobService/>
    <端点绑定=mexTcpBindingbindingConfiguration =NAME =mexEndpoint/>
  < /服务>
< /服务>
 

我得到的例外是:

  

System.ServiceModel.ServiceActivati​​onException:服务   /MyAppDir/WebJob.svc不能因为在激活异常   汇编。异常消息是:所提供的服务类型   无法加载作为服务,因为它不具有默认   (无参数的)构造函数。要解决该问题,添加默认   构造的类型,或通过型的一个实例给主机。

     

System.InvalidOperationException:所提供的服务类型不能   装载作为服务,因为它不具有默认   (无参数的)构造函数。要解决该问题,添加默认   构造的类型,或通过型的一个实例给主机。

 虚拟主机提供商无法处理请求。
 发件人信息:System.ServiceModel.ServiceHostingEnvironment + HostingManager / 13982700
 例外:System.ServiceModel.ServiceActivati​​onException:服务/MyAppDir/WebJob.svc不能因为编译过程中的异常激活。异常消息是:所提供的服务类型无法装入作为服务,因为它不具有默认(无参数)构造。要解决该问题,添加一个默认的构造函数的类型,或者传递给主机类型的实例.. ---> System.InvalidOperationException:提供无法加载为服务,因为它没有一个默认的(无参数的)构造函数的服务类型。要解决该问题,添加一个默认的构造函数的类型,或者通过类型主机的一个实例。
   在System.ServiceModel.Dispatcher.InstanceBehavior..ctor(DispatchRuntime调度,ImmutableDispatchRuntime immutableRuntime)
   在System.ServiceModel.Dispatcher.ImmutableDispatchRuntime..ctor(DispatchRuntime派遣)
   在System.ServiceModel.Dispatcher.DispatchRuntime.GetRuntimeCore()
   在System.ServiceModel.Dispatcher.ChannelDispatcher.OnOpened()
   在System.ServiceModel.Channels.CommunicationObject.Open(时间跨度超时)
   在System.ServiceModel.ServiceHostBase.OnOpen(时间跨度超时)
   [胡说]
 进程名称:W3WP
 进程ID:2108
 

这是合理的假设它没有采用我的自定义 ServiceBehavior - 默认ServiceBehavior的InstaceProvider不能实例化服务

有些事情需要注意:如果我添加一个无参数的构造函数来我的服务,我没有得到一个异常(当然,我没有得到通过的容器或者),所以我相当有信心,我已经找到该问题的根源

有人可以指出我在做什么错了?

解决方案

我想这个问题是在<服务名称=WebJobService> 服务元素呢不含behaviorConfiguration。此外name属性通常必须包含名称空间类型名称。所以,你的情况应该是 MyApplication.WebJobService

您还可以查看这些文章的替代实施的 1 ,的 2 。

We're trying to use Dependency Injection for a WCF Service. The Service has a dependency on a Unity Container. The container is used to find the appropriate class that implements an IJob Interface (based on a JobKey parameter in the method call) and calls a method on it.

The Service is being hosted in MVC2. I've omitted as much irrelevant stuff as possible from the snippets below. Full code available if required...

What I've done so far:

Based on this MSDN Article, I've created a custom InstanceProvider which should instantiate my service and pass it a container.

I then created a very noddy ServiceBehavior to use the InstanceProvider and finally a BehaviorExtension which just returns the ServiceBehavior.

Public Class WCFDIInstanceProvider
    Implements IInstanceProvider

    Private ServiceType As Type

    Private Property _Container As IUnityContainer
    Private ReadOnly Property Container As IUnityContainer
        Get
            If _Container Is Nothing Then
                _Container = InitialiseContainer()
            End If
            Return _Container
        End Get
    End Property

    Public Sub New(ByVal ServiceType As Type)
        Me.ServiceType = ServiceType
    End Sub

    Private Function InitialiseContainer() As IUnityContainer
            'Code which scans assemblies and populates the container as appropriate
            'I'm confident this code works as I've tested it elsewhere
        Return Container
    End Function

    Public Function GetInstance(ByVal instanceContext As System.ServiceModel.InstanceContext) As Object Implements System.ServiceModel.Dispatcher.IInstanceProvider.GetInstance
        Return GetInstance(instanceContext, Nothing)
    End Function

    Public Function GetInstance(ByVal instanceContext As System.ServiceModel.InstanceContext, ByVal message As System.ServiceModel.Channels.Message) As Object Implements System.ServiceModel.Dispatcher.IInstanceProvider.GetInstance
        Return Container.Resolve(Me.ServiceType)
    End Function

End Class

And the ServiceBehavior:

Public Class WCFDIServiceBehavior
Implements IServiceBehavior

    Public Sub ApplyDispatchBehavior(ByVal serviceDescription As System.ServiceModel.Description.ServiceDescription, ByVal serviceHostBase As System.ServiceModel.ServiceHostBase) Implements System.ServiceModel.Description.IServiceBehavior.ApplyDispatchBehavior
        For Each ChannelDispatcherBase As ChannelDispatcherBase In serviceHostBase.ChannelDispatchers
            Dim ChannelDispatcher As ChannelDispatcher = TryCast(ChannelDispatcherBase, ChannelDispatcher)
            If ChannelDispatcher IsNot Nothing Then
                For Each Dispatcher As EndpointDispatcher In ChannelDispatcher.Endpoints
                    Dispatcher.DispatchRuntime.InstanceProvider = New WCFDIInstanceProvider(serviceDescription.ServiceType)
                Next
            End If
        Next
    End Sub

And finally, the really noddy BehaviorExtension:

Public Class WCFDIBehaviorExtension
    Inherits BehaviorExtensionElement

    Public Overrides ReadOnly Property BehaviorType As System.Type
        Get
            Return GetType(WCFDIServiceBehavior)
        End Get
    End Property

    Protected Overrides Function CreateBehavior() As Object
        Return New WCFDIServiceBehavior
    End Function
End Class

The WCF Config tool seems to like all of the above and has generated the following Config XML:

  <serviceHostingEnvironment multipleSiteBindingsEnabled="true"
                             aspNetCompatibilityEnabled="true">
      <serviceActivations>
          <add relativeAddress="WebJob.svc"
               service="MyApplication.WebJobService"
               factory="System.ServiceModel.Activation.ServiceHostFactory" />
      </serviceActivations>
  </serviceHostingEnvironment>
<standardEndpoints>
  <mexEndpoint>
    <standardEndpoint name="WebJobServiceMex" />
  </mexEndpoint>
</standardEndpoints>
<behaviors>
  <serviceBehaviors>
    <behavior name="WCFDIServiceBehavior">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="true" />
      <WCFDIBehavior />
    </behavior>
  </serviceBehaviors>
</behaviors>
<services>
  <service name="WebJobService">
    <endpoint address="" binding="basicHttpBinding" bindingConfiguration="httpBinding"
      name="HTTPEndpoint" contract="MyApplication.JobService.Common.IWebJobService" />
    <endpoint binding="mexTcpBinding" bindingConfiguration="" name="mexEndpoint" />
  </service>
</services>

The exception I get is:

System.ServiceModel.ServiceActivationException: The service '/MyAppDir/WebJob.svc' cannot be activated due to an exception during compilation. The exception message is: The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.

System.InvalidOperationException: The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.

WebHost failed to process a request.
 Sender Information: System.ServiceModel.ServiceHostingEnvironment+HostingManager/13982700
 Exception: System.ServiceModel.ServiceActivationException: The service '/MyAppDir/WebJob.svc' cannot be activated due to an exception during compilation.  The exception message is: The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.. ---> System.InvalidOperationException: The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.
   at System.ServiceModel.Dispatcher.InstanceBehavior..ctor(DispatchRuntime dispatch, ImmutableDispatchRuntime immutableRuntime)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime..ctor(DispatchRuntime dispatch)
   at System.ServiceModel.Dispatcher.DispatchRuntime.GetRuntimeCore()
   at System.ServiceModel.Dispatcher.ChannelDispatcher.OnOpened()
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout)
   [Blah]
 Process Name: w3wp
 Process ID: 2108

Which makes sense assuming it's not applying my custom ServiceBehavior - The default ServiceBehavior's InstaceProvider can't instantiate the service.

Some things to note: If I add a parameterless constructor to my service, I don't get an exception (but of course, I don't get passed a container either) so I'm fairly confident I've found the source of the problem

Can someone please point out what I'm doing wrong?

解决方案

I guess that problem is in <service name="WebJobService">. Service element does not contain behaviorConfiguration. Also name attribute must normally contain type name with namespaces. So in your case it should be MyApplication.WebJobService.

You can also check these articles for alternative implementations 1, 2.