2009-05-22 21 views
40

Sto provando a scrivere un client di servizi Web in C# che il servizio Web è Java Axis 1.4. Il servizio Axis richiede il valore Autorizzazione: Base64EncodedToken di intestazione nelle intestazioni HTTP. Non riesco a trovare un modo per impostare questa intestazione in modalità standart di consumare servizi Web in visual studio.net, come il normale riferimento generato da WSDL né con WSE3.0Come aggiungere un'intestazione Http personalizzata per il client di servizio Web C# che utilizza il servizio Web Axis 1.4

Non riesco a utilizzare WCF come il progetto è sviluppato utilizzando .net 2.0.

C'è un modo per farlo?

risposta

7

Se si desidera inviare un costume intestazione HTTP (non un'intestazione SOAP), allora è necessario utilizzare la classe HttpWebRequest il codice sarà simile:

HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url); 
webRequest.Headers.Add("Authorization", token); 

Non è possibile aggiungere intestazioni HTTP utilizzando il Visual Studio generato proxy, che può essere un vero dolore.

+0

"non è possibile aggiungere intestazioni HTTP utilizzando il visual Studio proxy generato" È ancora il caso? – chaostheory

+0

Posso aggiungere le intestazioni in questo modo ma come posso riaverle nel servizio WCF? – Joshy

24

Stiamo parlando di WCF qui? Ho riscontrato problemi in cui le chiamate di servizio non aggiungevano le intestazioni di autorizzazione http, mentre l'inserimento di eventuali chiamate in questa istruzione ha risolto il problema.

using (OperationContextScope scope = new OperationContextScope(RefundClient.InnerChannel)) 
    { 
      var httpRequestProperty = new HttpRequestMessageProperty(); 
      httpRequestProperty.Headers[System.Net.HttpRequestHeader.Authorization] = "Basic " + 
      Convert.ToBase64String(Encoding.ASCII.GetBytes(RefundClient.ClientCredentials.UserName.UserName + ":" + 
      RefundClient.ClientCredentials.UserName.Password)); 
      OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty; 

      PaymentResponse = RefundClient.Payment(PaymentRequest); 
    } 

Questo eseguiva chiamate SOAP a IBM ESB tramite .NET con autenticazione di base su http o https.

Spero che questo aiuti qualcuno perché ho avuto enormi problemi a trovare una soluzione online.

+2

Questo era in realtà il mio problema. In qualche modo quando si impostano le credenziali nel proxy, non funziona. Grazie! – Tawani

+0

Sto usando WCF/Soap, quindi questo ha funzionato molto bene per me. Nel mio caso avevo bisogno di un'intestazione personalizzata chiamata "Auth-Token". Quindi il mio codice (VB.NET) era -> httpRequestProperty.Headers.Add ("Auth-Token", "xxxxx") – robnick

+0

Anche questo ha risolto i miei problemi. Ho avuto lo stesso problema di Tawani, quando ho impostato le credenziali tramite il proxy, ho riavuto 401. Ma con il tuo codice tutto funziona perfettamente! Grazie tante! – merger

40

Sembra che l'autore originale ha trovato la loro soluzione, ma per chiunque altro chi viene qui in cerca di aggiungere intestazioni personalizzate effettivi, se si ha accesso al mod codice protocollo generato è possibile ignorare GetWebRequest:

protected override System.Net.WebRequest GetWebRequest(Uri uri) 
{ 
    System.Net.WebRequest request = base.GetWebRequest(uri); 
    request.Headers.Add("myheader", "myheader_value"); 
    return request; 
} 

Assicurati di rimuovere l'attributo DebuggerStepThroughAttribute se desideri intervenire.

+0

Questo era esattamente quello di cui avevo bisogno. Il servizio Web restituiva 500 anziché 401 per Non autorizzato, quindi le credenziali non venivano mai inviate utilizzando l'approccio nella risposta accettata. Mentre mi sento sporco modificando il codice generato, questo mi ha permesso di forzare l'invio con la prima richiesta. Vedi http://www.west-wind.com/weblog/posts/243915.aspx. –

+2

Ehi, sembra esattamente quello di cui ho bisogno. ma dove dovrei inserire questa funzione? –

+0

ma non è possibile che un'aggiunta all'intestazione abbia più valori separati da virgole nella porzione di valore per l'intestazione che si sta aggiungendo? Anche questo è molto importante per sapere come per i parametri di autorizzazione OAuth – PositiveGuy

4

Trovo questo codice e risolve il mio problema.

http://arcware.net/setting-http-header-authorization-for-web-services/

protected override WebRequest GetWebRequest(Uri uri) 
{ 
    // Assuming authValue is set from somewhere, such as the config file 
    HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(uri); 
    request.Headers.Add("Authorization", string.Format("Basic {0}", authValue)); 
    return request; 
} 
+2

Ehi, sembra esattamente quello di cui ho bisogno. ma dove dovrei inserire questa funzione? –

+1

Anche io non so dove metterlo e sto usando .net 4.0. Il mio servizio è generato in modo diverso rispetto ad altri esempi trovo –

0

Ecco cosa ha funzionato per me:

protected override System.Net.WebRequest GetWebRequest(Uri uri) 
{ 
     HttpWebRequest request; 
     request = (HttpWebRequest)base.GetWebRequest(uri); 
     NetworkCredential networkCredentials = 
     Credentials.GetCredential(uri, "Basic"); 
     if (networkCredentials != null) 
     { 
      byte[] credentialBuffer = new UTF8Encoding().GetBytes(
      networkCredentials.UserName + ":" + 
      networkCredentials.Password); 
      request.Headers["Authorization"] = 
      "Basic " + Convert.ToBase64String(credentialBuffer); 
      request.Headers["Cookie"] = "BCSI-CS-2rtyueru7546356=1"; 
      request.Headers["Cookie2"] = "$Version=1"; 
     } 
     else 
     { 
      throw new ApplicationException("No network credentials"); 
     } 
     return request; 
} 

Non dimenticare di impostare questa proprietà:

service.Credentials = new NetworkCredential("username", "password"); 

Cookie e Cookie2 sono impostati nell'intestazione perché il servizio java non accettava la richiesta e ricevevo un errore non autorizzato.

+0

Mi sono liberato del sovraccarico di cui sopra e solo questo codice ha fatto tutta la magia: serviceClient.CookieContainer = new CookieContainer(); –

3

Invece di modding del codice generato automaticamente o avvolgere ogni chiamata nel codice duplicato, è possibile iniettare le intestazioni HTTP personalizzate con l'aggiunta di un messaggio personalizzato ispettore, è più facile di quanto sembri:

public class CustomMessageInspector : IClientMessageInspector 
{ 
    readonly string _authToken; 

    public CustomMessageInspector(string authToken) 
    { 
     _authToken = authToken; 
    } 

    public object BeforeSendRequest(ref Message request, IClientChannel channel) 
    { 
     var reqMsgProperty = new HttpRequestMessageProperty(); 
     reqMsgProperty.Headers.Add("Auth-Token", _authToken); 
     request.Properties[HttpRequestMessageProperty.Name] = reqMsgProperty; 
     return null; 
    } 

    public void AfterReceiveReply(ref Message reply, object correlationState) 
    { } 
} 


public class CustomAuthenticationBehaviour : IEndpointBehavior 
{ 
    readonly string _authToken; 

    public CustomAuthenticationBehaviour (string authToken) 
    { 
     _authToken = authToken; 
    } 
    public void Validate(ServiceEndpoint endpoint) 
    { } 

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) 
    { } 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
    { } 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
    { 
     clientRuntime.ClientMessageInspectors.Add(new CustomMessageInspector(_authToken)); 
    } 
} 

E quando un'istanza la classe cliente si può semplicemente aggiungerlo come comportamento:

this.Endpoint.EndpointBehaviors.Add(new CustomAuthenticationBehaviour("Auth Token")); 

questo renderà ogni chiamata di servizio in uscita per avere l'intestazione HTTP personalizzato.

+1

Saeb Amini, grazie. Questa era la risposta che stavo cercando per risolvere il mio problema utilizzando un servizio web di terze parti che era passato all'autenticazione a 2 fattori. La loro API ci è stata fornita da XSD e WSDL che abbiamo generato il codice client tramite il programma svcutil. L'utilizzo del codice precedente mi ha permesso di aggiungere il comportamento per iniettare l'intestazione HTTP con il token per eseguire l'autenticazione a 2 fattori. Grazie ancora! – bolski

1

La risposta dell'utente334291 è stata per me un salvavita. Voglio solo aggiungere come è possibile aggiungere ciò che l'OP originariamente destinato a fare (quello che ho finito per usare):

Superamento della funzione GetWebRequest sul codice webservice generato:

protected override System.Net.WebRequest GetWebRequest(Uri uri) 
{ 
    System.Net.WebRequest request = base.GetWebRequest(uri);   
    string auth = "Basic " + Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(this.Credentials.GetCredential(uri, "Basic").UserName + ":" + this.Credentials.GetCredential(uri, "Basic").Password)); 
    request.Headers.Add("Authorization", auth); 
    return request; 
} 

e impostando le credenziali prima di chiamare il webservice:

client.Credentials = new NetworkCredential(user, password);