2014-06-13 14 views
9

Ich versuche, IDispatchMessageInspector in einer Implementierung des WCF-Diensts zu verwenden, um auf benutzerdefinierte Headerwerte zuzugreifen.Wie IDispatchMessageInspector in einem WCF-Dienst verwenden?

Etwas wie:

public class MyService : IMyService 
{ 
    public List<string> GetNames() 
    { 
     var headerInspector = new CustomHeaderInspector(); 

     // Where do request & client channel come from? 
     var values = headerInspector.AfterReceiveRequest(ref request, clientChannel, OperationContext.Current.InstanceContext);    
    } 
} 

Ich habe meine eigene IDispatchMessageInspector Klasse implementiert.

public class CustomHeaderInspector : IDispatchMessageInspector 
{ 
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 
    { 
     var prop = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name]; 
     var userName = prop.Headers["Username"]; 

     return userName; 
    } 
} 

Wie gehe ich

  • System.ServiceModel.Channels. Nachricht und

  • System.ServiceModel. IClientChannel

zu AfterReceiveRequestvon der Service-Implementierung genannt?

EDIT:

Viele Artikel wie this one oder this one, geben Beispiele, wie Sie Ihre eigenen ServiceBehavior zu implementieren. So Ihre Service-Implementierung sieht wie folgt aus:

[MyCustomBehavior] 
public class MyService : IMyService 
{ 
    public List<string> GetNames() 
    { 
     // Can you use 'MyCustomBehavior' here to access the header properties? 
    } 
} 

Also mit diesem, kann ich MyCustomBehavior zugreifen irgendwie innerhalb der Service-Operation Methode, um benutzerdefinierte Header-Werte zugreifen?

+0

http://blogs.msdn.com/b/zelmalki/archive/2008/12/29/creating-a- nennen wcf-idispatchmessagerinspector.aspx das könnte sehr hilfreich sein –

Antwort

6

Sie haben die

<extensions> 
    <behaviorExtensions> 
    <add 
     name="serviceInterceptors" 
     type="CustomHeaderInspector , MyDLL, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" 
    /> 
    </behaviorExtensions> 
</extensions> 

Dann wird die Erweiterung zu konfigurieren, wird in Ihrem WCF-Stack behandelt werden. Der Dienst selbst hat keine Ahnung von der serviceInterceptors und Sie müssen nicht so etwas wie in Ihrem ersten Codeblock tun. Der WCF-Stapel injiziert Ihnen Inspector.

MSDN: system.servicemodel.dispatcher.idispatchmessageinspector

+0

Haben Sie einen Einblick, wo der IDispatchmessageInspector implementieren? Ich begann eine andere Frage: http://stackoverflow.com/questions/31171943/how-and-where-to-implement-the-idispatchmessageInspector – Popo

0

auf der MSDN-Seite, die Sie dort verknüpft ist auch eine Beschreibung, wie ein Inspektor eingesetzt und auch ein Beispiel dafür werden kann. Zum Angebot:

In der Regel werden Nachrichteninspektoren durch ein Dienstverhalten, ein Endpunktverhalten oder ein Vertragsverhalten eingefügt. Das Verhalten fügt dann der DispatchRuntime.MessageInspectors-Auflistung den Nachrichteninspektor hinzu.

Später haben Sie die folgenden Beispiele:

  • Implementierung eigener IDispatchMessageInspector
  • individuelle IServiceBehavior Implementierung, die den Inspektor auf die Laufzeit hinzufügt.
  • Konfiguration des Verhaltens über .config-Datei.

Das sollte genug sein, um Sie zu beginnen. Sonst zögern Sie nicht zu fragen :)

Wenn Sie nur Zugriff auf Header aus Ihrem Service erhalten möchten, können Sie versuchen, OperationContext.Current.IncomingMessageHeaders.

3

Ich verwende IClientMessageInspector für dasselbe Ziel. Hier ist, wie man sich aus dem Code anwenden kann:

var serviceClient = new ServiceClientClass(binding, endpointAddress); 
serviceClient.Endpoint.Behaviors.Add(
      new MessageInspectorEndpointBehavior<YourMessageInspectorType>()); 


/// <summary> 
/// Represents a run-time behavior extension for a client endpoint. 
/// </summary> 
public class MessageInspectorEndpointBehavior<T> : IEndpointBehavior 
    where T: IClientMessageInspector, new() 
{ 
    /// <summary> 
    /// Implements a modification or extension of the client across an endpoint. 
    /// </summary> 
    /// <param name="endpoint">The endpoint that is to be customized.</param> 
    /// <param name="clientRuntime">The client runtime to be customized.</param> 
    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
    { 
     clientRuntime.MessageInspectors.Add(new T()); 
    } 

    /// <summary> 
    /// Implement to pass data at runtime to bindings to support custom behavior. 
    /// </summary> 
    /// <param name="endpoint">The endpoint to modify.</param> 
    /// <param name="bindingParameters">The objects that binding elements require to support the behavior.</param> 
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) 
    { 
     // Nothing special here 
    } 

    /// <summary> 
    /// Implements a modification or extension of the service across an endpoint. 
    /// </summary> 
    /// <param name="endpoint">The endpoint that exposes the contract.</param> 
    /// <param name="endpointDispatcher">The endpoint dispatcher to be modified or extended.</param> 
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
    { 
     // Nothing special here 
    } 

    /// <summary> 
    /// Implement to confirm that the endpoint meets some intended criteria. 
    /// </summary> 
    /// <param name="endpoint">The endpoint to validate.</param> 
    public void Validate(ServiceEndpoint endpoint) 
    { 
     // Nothing special here 
    } 
} 

Und hier ist Beispielimplementierung von MessageInspector Ich bin mit Client-Version auf Server zu übergeben, und Server-Version in benutzerdefinierten Header abrufen:

/// <summary> 
/// Represents a message inspector object that can be added to the <c>MessageInspectors</c> collection to view or modify messages. 
/// </summary> 
public class VersionCheckMessageInspector : IClientMessageInspector 
{ 
    /// <summary> 
    /// Enables inspection or modification of a message before a request message is sent to a service. 
    /// </summary> 
    /// <param name="request">The message to be sent to the service.</param> 
    /// <param name="channel">The WCF client object channel.</param> 
    /// <returns> 
    /// The object that is returned as the <paramref name="correlationState " /> argument of 
    /// the <see cref="M:System.ServiceModel.Dispatcher.IClientMessageInspector.AfterReceiveReply([email protected],System.Object)" /> method. 
    /// This is null if no correlation state is used.The best practice is to make this a <see cref="T:System.Guid" /> to ensure that no two 
    /// <paramref name="correlationState" /> objects are the same. 
    /// </returns> 
    public object BeforeSendRequest(ref Message request, IClientChannel channel) 
    { 
     request.Headers.Add(new VersionMessageHeader()); 
     return null; 
    } 

    /// <summary> 
    /// Enables inspection or modification of a message after a reply message is received but prior to passing it back to the client application. 
    /// </summary> 
    /// <param name="reply">The message to be transformed into types and handed back to the client application.</param> 
    /// <param name="correlationState">Correlation state data.</param> 
    public void AfterReceiveReply(ref Message reply, object correlationState) 
    { 
     var serverVersion = string.Empty; 
     var idx = reply.Headers.FindHeader(VersionMessageHeader.HeaderName, VersionMessageHeader.HeaderNamespace); 
     if (idx >= 0) 
     { 
      var versionReader = reply.Headers.GetReaderAtHeader(idx); 
      while (versionReader.Name != "ServerVersion" 
        && versionReader.Read()) 
      { 
       serverVersion = versionReader.ReadInnerXml(); 
       break; 
      } 
     } 

     ValidateServerVersion(serverVersion); 
    } 

    private static void ValidateServerVersion(string serverVersion) 
    { 
     // TODO... 
    } 
} 

public class VersionMessageHeader : MessageHeader 
{ 
    public const string HeaderName = "VersionSoapHeader"; 
    public const string HeaderNamespace = "<your namespace>"; 
    private const string VersionElementName = "ClientVersion"; 

    public override string Name 
    { 
     get { return HeaderName; } 
    } 

    public override string Namespace 
    { 
     get { return HeaderNamespace; } 
    } 

    protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion) 
    { 
     writer.WriteElementString(
      VersionElementName, 
      Assembly.GetExecutingAssembly().GetName().Version.ToString()); 
    } 
} 
1

var mp = OperationContext.Current.IncomingMessageProperties; 
var property = (HttpRequestMessageProperty)mp[HttpRequestMessageProperty.Name]; 
var userName = property.Headers["Username"]; 
:

ich glaube, Sie keine benutzerdefinierten IDispatchMessageInspector implementieren müssen benutzerdefinierte Header abrufen, kann es von Service-Betrieb Methode wie folgt durchgeführt werden

Es ist sinnvoll, einen benutzerdefinierten Dispatch-Nachrichteninspektor zu implementieren, wenn Sie die Nachrichtenverarbeitung abbrechen möchten, z. B. wenn Anmeldeinformationen fehlen - Sie können in diesem Fall einfach FaultException auslösen.

Aber wenn Sie noch von Eilnachricht Inspektoren passieren Wert wollen Operationsmethode bedienen - wahrscheinlich kann er zusammen mit Anrufkennung (Session-ID), durch einige Singleton weitergegeben wird später durch Verfahren extrahiert werden, oder unter Verwendung von wcf extensions

1

Was ich die Details ich folgendes innen IDispatchMessageInspector.AfterReceiveRequest

Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(username, "Membership Provider"), roles);

ich die Authentifizierung festgelegt Zugriff haben, um Code aus dieser weggelassen habe.

Um den Wert der Service-Methode zuzugreifen, können Sie

Thread.CurrentPrincipal.Identity.Name