Ciao Sebastiano,
non so se hai già risolto il problema, provo a risponderti lo stesso.
sem ha scritto:
Ho provato anche ad usare wsHttpBinding ma, l'uso di questo binding, genera nel server del destinatario un errore 500.
Può darsi che il servizio non supporti tutto lo stack di tecnologie WS-*. Infatti wsHttpBinding è meno interoperabile e ti conviene tornare a basicHttpBinding.
sem ha scritto:
HttpClientCredentialType.Basic
In ogni caso il messaggio di errore che ricevo e': "Credenziali non presenti".
Dev'essere che le credenziali vengono fornire a livello di messaggio, quindi come intestazioni del messaggio SOAP. Non so tu, ma io ogni volta che mi scontro con la configurazione di WCF perdo sempre un sacco di tempo.
Secondo me dovresti rinunciare a configurare il binding ed usare invece un
message inspector, che ti permette di modificare la richiesta subito prima che sia inviata al servizio.
Non sarà la più elegante delle soluzioni, ma almeno in capo a 10 minuti riesci a farla funzionare.
Partiamo dalla documentazione: "Inspect or modify messages on the client".
http://msdn.microsoft.com/it-it/library/ms733786(v=vs.110).aspxSembra che possa fare al caso nostro. L'esempio ci chiede di scrivere alcune classi.
- Un IClientMessageInspector. E' la classe che useremo per scrivere fisicamente l'intestazione Authorization sulla richiesta HTTP.
- Un IEndpointBehavior. E' la classe che viene pluggata alla pipeline di WCF per modificarne il comportamento, ed è quella che si occuperà di creare un'istanza dell'IClientMessageInspector al momento opportuno.
- Un BehaviorExtensionElement. Questo per ora non ci serve. Il suo compito è di supportare la configurazione del behavior da file .config. Lasciamolo perdere un attimo, perché possiamo configurare il behavior anche via API, mediante le proprietà della classe client Invio.
Dunque per prima cosa prepara la classe che implementa IClientMessageInspector. Può essere una cosa del genere:
public class BasicAuthenticationInspector : IClientMessageInspector
{
private readonly string _authorization;
public BasicAuthenticationInspector(string username, string password)
{
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
throw new ArgumentException("Devi fornire username e password");
_authorization = "Basic " +
Convert.ToBase64String(
Encoding.UTF8.GetBytes(string.Format("{0}:{1}", username, password))
);
}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message messaggio, System.ServiceModel.IClientChannel channel)
{
//ottengo un riferimento alla richiesta http sottostante
var richiestaHttp = messaggio.Properties.Values.OfType<HttpRequestMessageProperty>().FirstOrDefault();
if (richiestaHttp != null)
{
richiestaHttp.Headers.Add("Authorization", _authorization);
}
return messaggio;
}
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
//non ci interessa esaminare la risposta
}
}
Gli ho dato un costruttore che richiede username e password, a ribadire che questo message inspector si occupa di scrivere delle credenziali. Nel costruttore vado subito ad assemblare il valore della header Authorization.
Invece nel metodo BeforeSendRequest ottengo un riferimento alla richiesta HTTP e aggiungo l'intestazione Authorization prevista dalla Basic Authentication.
Ora è il momento di creare l'IEndpointBehavior.
public class BasicAuthenticationBehavior : IEndpointBehavior {
private readonly string _username;
private readonly string _password;
public BasicAuthenticationBehavior(string username, string password) {
//raccolgo user e password che passerò poi al costruttore di IClientMessageInspector
_username = username;
_password = password;
}
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) {
return;
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) {
//aggiungo un'istanza dell'inspector
clientRuntime.MessageInspectors.Add(new BasicAuthenticationInspector(_username, _password));
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) {
return;
}
public void Validate(ServiceEndpoint endpoint)
{
return;
}
}
Dei 4 metodi che l'interfaccia ti chiede di implementare, solo ApplyClientBehavior è rilevante in questo caso: è quello che si occuperà di istanziare il message inspector e di passarlo al runtime.
Il costruttore si occupa solo di raccogliere user e password che verranno poi passate al message inspector.
Adesso non resta che aggiungere questo behavior alla tua classe proxy Invio. E' facilissimo.
//metti questo prima di invocare le operazioni del servizio
invio.Endpoint.EndpointBehaviors.Add(new BasicAuthenticationBehavior("Username", "Password"));
Ovviamente togli le righe in cui valorizzati le ClientCredentials. Ora username e password vengono forniti al costruttore del behavior.
Se vuoi ispezionare la richiesta che stai inviando al servizio, ti consiglio di usare Fiddler. E' un web debugger che si pone fra te e il server. Dato che il servizio è protetto da certificato SSL, allora assicurati che Fiddler sia configurato per
decrittare il traffico HTTPS.
ciao,
Moreno
Modificato da BrightSoul il 05 agosto 2014 18.51 -