2011-01-13 11 views
1

WCFサービスに依存性注入を使用しようとしています。サービスはUnityコンテナに依存しています。コンテナは、IJobインターフェイス(メソッド呼び出しのJobKeyパラメータに基づく)を実装する適切なクラスを見つけるために使用され、そのメソッドを呼び出します。WCFカスタムのServiceBehavior/InstanceProvider(パラメータのないコンストラクタ)

サービスはMVC2でホストされています。私は以下のスニペットから無関係なものをできるだけ省いています。必要に応じて利用できる完全なコード...私がこれまで行ってきた

何:

このMSDN Articleに基づいて、私は私のサービスをインスタンス化し、それにコンテナを渡す必要がありますカスタムInstanceProviderを作成しました。

ServiceBehaviorを使用してInstanceProviderを使用し、最後にBehaviorExtensionを使用して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 

そして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 

そして最後に、本当に 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 

WCFコンフィグツールは、上記のすべてが好きのようですし、生成しました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> 

私が得る例外は次のとおりです。

System.ServiceModel.ServiceActivationException:サービス '/MyAppDir/WebJob.svc' は コンパイル時に例外のために活性化することはできません。例外メッセージは次のとおりです。 のサービスタイプは、デフォルトの (パラメータなし)コンストラクタを持たないため、サービスとしてロードできませんでした。問題を解決するには、デフォルトの コンストラクターを型に追加するか、またはその型のインスタンスをホストに渡します。

System.InvalidOperationException:提供されたサービスタイプが、デフォルトの (パラメータなし)コンストラクタを持たないため、サービスとしてロードされない サービスタイプです。問題を解決するには、デフォルトの コンストラクターを型に追加するか、またはその型のインスタンスをホストに渡します。 ServiceBehaviorのInstaceProviderは、サービスをインスタンス化することはできませんデフォルト - それは私のカスタムServiceBehaviorを適用していないと仮定すると理にかなって

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 

注意事項:パラメータのないコンストラクタをサービスに追加すると、例外は発生しません(もちろん、コンテナも渡されません)ので、私はかなり自信があります問題の原因を見つけた

誰かが間違っていることを指摘できますか?

+0

@Steven編集していただきありがとうございますが、私は例外ダンプがかなり明確だと思いました。クォート内のエラーメッセージを複製すると、実際に品質が向上しますか? – Basic

+0

はい、私はそう信じています。例外メッセージのグーグルでこの質問を見つけましたが、質問をスキャンした後、私はこのメッセージを見つけることができませんでした。私の編集では、他の人がこのメッセージをより簡単に見つけることができます。それが私の目標です。 – Steven

答えて

1

問題は<service name="WebJobService">.にあると思います。サービス要素にはbehaviorConfigurationが含まれていません。また、name属性は通常、名前空間を持つ型名を含まなければなりません。したがって、あなたの場合はMyApplication.WebJobServiceでなければなりません。

代替実装については、1,2のこれらの記事をチェックすることもできます。

+0

私は、すべてのサービスに適用されるサービスの行動が間違いであるかもしれないという印象を受けていました。私は明日オフィスでチェックインします。命名に関しては、これは単にXMLの他の部分から要素を参照するために使用される名前だと思いますか? – Basic

+0

いいえ。設定でサービス設定を参照する必要はありません。名前はサービスタイプをこの設定にバインドします。少なくともインスタント・オン・ザ・インスタンスでは、名前は名前空間の型名とまったく同じでなければならず、それ以外の構成は使用されません。 –

1

私はこの問題を単純化します。それはUnityについてではなく、あなたのサービスをインスタンス化し、コンストラクタにパラメータを渡すことです。それが問題なら、property injectionの使用を検討してください。

私は通常、サービスをUnityコンテナをインスタンス化して、問題を完全に回避します。

「アセンブリをスキャンしてコンテナを読み込むコード」は、MEFがUnityよりも適しているように思えます。

EDIT:私はプロパティーの注入をお勧めしないと思います。あなたはUnityにサービスのインスタンスを作成させたくありません。 UnityContainer.Resolve is thread safe(設定にはロックが必要ですが)のため、サービスにコンテナの静的インスタンスを作成して所有させることができます。コンテナインスタンスは他の依存関係を解決します。

+0

MEFはほぼ確実に良い選択です。残念ながら、このプロジェクトは新しいスタートアップのためのものであり、リソースは限られています.MEFに切り替えるには、ATMを確保できない開発時間がかかります。私たちはすでにそれ以降のバージョンのためにそれを考えています - それを指摘していただきありがとうございます。 – Basic

関連する問題