Wir versuchen Dependency Injection für einen WCF-Dienst zu verwenden. Der Dienst ist von einem Unity-Container abhängig. Der Container wird verwendet, um die geeignete Klasse zu finden, die eine IJob
Schnittstelle implementiert (basierend auf einem JobKey
Parameter im Methodenaufruf) und eine Methode dafür aufruft.WCF Custom ServiceBehavior/InstanceProvider mit parameterlosem Konstruktor
Der Dienst wird in MVC2 gehostet. Ich habe so viel irrelevantes Zeug wie möglich aus den Schnipsel unten weggelassen. Full-Code zur Verfügung, wenn erforderlich ...
Was ich bisher getan:
Basierend auf dieser MSDN Article, ich habe eine benutzerdefinierte InstanceProvider
geschaffen, die meinen Dienst instanziiert sollte und er einen Behälter übergeben.
Ich erstellte dann eine sehr noddy ServiceBehavior
, um die InstanceProvider
und schließlich eine BehaviorExtension
zu verwenden, die nur die ServiceBehavior
zurückgibt.
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
Und die 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
Und schließlich die wirklich 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
Der WCF-Config-Tool scheint alle oben zu mögen und hat die erzeugte folgende 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>
Die Ausnahme, die ich bekommen ist:
System.ServiceModel.ServiceActivationException: Der Dienst '/MyAppDir/WebJob.svc' kann nicht aufgrund einer Ausnahme während Kompilierung aktiviert werden. Die Ausnahmebedingungsnachricht lautet: Der angegebene Servicetyp konnte nicht als Dienst geladen werden, da er keinen Standardkonstruktor (parameterlos) hat. Um das Problem zu beheben, fügen Sie dem Typ einen Standard -Konstruktor hinzu oder übergeben Sie eine Instanz des Typs an den Host.
System.InvalidOperationException: Der angegebene Servicetyp konnte nicht als Dienst geladen werden, da kein Standard (parameterlos) -Konstruktor vorhanden ist. Um das Problem zu beheben, fügen Sie dem Typ einen Standard -Konstruktor hinzu oder übergeben Sie eine Instanz des Typs an den 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
Welchen Sinn unter der Annahme, macht es nicht meine Gewohnheit ist die Anwendung ServiceBehavior
- Der Standard ServiceBehavior den InstaceProvider kann den Dienst nicht instanziiert.
Einige Dinge zu beachten: Wenn ich einen parameterlosen Konstruktor zu meinem Dienst hinzufüge, bekomme ich keine Ausnahme (aber natürlich bekomme ich auch keinen Container), also bin ich ziemlich zuversichtlich, dass ich habe gefunden die Quelle des Problems
Kann jemand bitte darauf hinweisen, was ich falsch mache?
@Steven Danke für die Bearbeitung, aber ich dachte, die Ausnahme Dump war ziemlich klar - macht das Duplizieren der Fehlermeldung in einem Zitat wirklich die Qualität zu verbessern? – Basic
Ja, ich glaube es tut. Ich habe diese Frage gefunden, indem ich die Ausnahmebedingung gegoogelt habe, aber nach dem Durchsuchen der Frage konnte ich diese Nachricht nicht finden. Meine Bearbeitung erlaubt anderen, diese Nachricht leichter zu finden, das war mein Ziel. – Steven