2014-06-13 15 views
9

Sto tentando di utilizzare IDispatchMessageInspector in un'implementazione del servizio WCF per accedere a valori di intestazione personalizzati.Come utilizzare IDispatchMessageInspector in un servizio WCF?

Qualcosa di simile:

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);    
    } 
} 

ho implementato mia classe IDispatchMessageInspector.

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; 
    } 
} 

Come faccio a passare

  • System.ServiceModel.Channels. Messaggio e

  • System.ServiceModel. IClientChannel

a AfterReceiveRequest chiamato dalla implementazione del servizio?

EDIT:

Molti articoli come this one o this one, dare esempi su come implementare il proprio ServiceBehavior. Così il vostro implementazione del servizio è simile al seguente:

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

Quindi, con questo, posso accedere MyCustomBehavior in qualche modo all'interno del metodo di funzionamento del servizio per accedere ai valori di intestazione personalizzati?

+0

http://blogs.msdn.com/b/zelmalki/archive/2008/12/29/creating-a- wcf-idispatchmessageinspector.aspx questo potrebbe essere molto utile –

risposta

6

è necessario configurare il

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

Poi l'estensione verrà gestito nel tuo stack WCF. Il servizio in sé non ha alcuna nozione di serviceInterceptors e non devi fare qualcosa del genere nel tuo primo blocco di codice. Lo stack WCF ti inietterà Inspector.

MSDN: system.servicemodel.dispatcher.idispatchmessageinspector

+0

Avete qualche idea su dove implementare IDispatchmessageInspector? Ho iniziato un'altra domanda: http://stackoverflow.com/questions/31171943/how-and-where-to-implement-the-idispatchmessageinspector – Popo

0

Nella pagina MSDN che si è collegato a c'è anche una descrizione di come può essere inserito un ispettore e anche un esempio di questo. Per citare:

In genere, gli ispettori di messaggi vengono inseriti da un comportamento di servizio, un comportamento di endpoint, o un comportamento contratto. Il comportamento quindi aggiunge la finestra di ispezione messaggi alla raccolta DispatchRuntime.MessageInspectors.

In seguito si hanno i seguenti esempi:

  • implementazione personalizzata IDispatchMessageInspector
  • implementazione personalizzata IServiceBehavior che aggiunge l'ispettore al runtime.
  • Configurazione del comportamento tramite file .config.

Questo dovrebbe essere sufficiente per iniziare. Altrimenti sentiti libero di chiedere :)

Se vuoi solo accedere alle intestazioni dal tuo servizio, puoi provare a OperationContext.Current.IncomingMessageHeaders.

3

Sto utilizzando IClientMessageInspector per lo stesso obiettivo. Ecco come si possono applicare dal codice:

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 
    } 
} 

Ed ecco campione attuazione MessageInspector che sto usando per passare la versione client al server, e recuperare la versione del server di intestazioni personalizzate:

/// <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

credo che non è necessario implementare personalizzato IDispatchMessageInspector per recuperare intestazioni personalizzate, può essere fatto dal metodo di funzionamento servizio come questo:

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

Ha senso implementare l'ispettore messaggi di spedizione personalizzato se si desidera interrompere l'elaborazione dei messaggi, ad esempio se mancano le credenziali - in questo caso è sufficiente lanciare FaultException.

Ma se si vuole ancora passare valore dal messaggio di spedizione ispettore al servizio metodo di funzionamento - probabilmente può essere passato attraverso alcune Singleton con codice identificativo (ID di sessione), da estrarre in seguito con il metodo, o utilizzando wcf extensions

1

Quello che ho fatto per accedere ai dettagli ho impostato il seguente all'interno IDispatchMessageInspector.AfterReceiveRequest

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

ho omesso il codice di autenticazione da questo.

Per accedere al valore del metodo di servizio, è possibile chiamare

Thread.CurrentPrincipal.Identity.Name

Problemi correlati