Archivi tag: Csharp

Ottenere il Soap Message in WCF

A volte cose molto semplici richiedono delle operazioni aggiuntive per essere espletate, e quindi cio che ci aspettiamo essere una semplice Get, prevede invece l’utilizzo di diversi pattern.

Il nostro caso:

stiamo utilizzando un client WCF per chiamare un webservice e vorremmo ottenere programmaticamente, quindi da codice, la busta Soap per memorizzarla ad esempio in sistemi di monitoring o debug particolari.

La soluzione:

Realizziamo una classe che implementi due interfacce, IClientMessageInspector e IEndpointBehavior.

Implementiamo le interfacce e otteniamo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class MessageInspector : IClientMessageInspector, IEndpointBehavior

{
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
//throw new NotImplementedException();
}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
Console.WriteLine("Soap Message:"+request.toString());
return null;
}

public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
//;
}

public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(this);
}

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

public void Validate(ServiceEndpoint endpoint)
{
//;
}

}

Nel metodo BeforeSendRequest otteniamo il messaggio prima dell’invio e ad esempio lo stampiamo sulla console..

Per poter poi aggiungere questo Inspector alle caratteristiche del nostro client, basta passarlo in questo modo:

1
2
//serviceClient e' l'istanza del nostro client WCF
serviceClient.ChannelFactory.Endpoint.Behaviors.Add(new MessageInspector());

Importante l’implementazione del metodo ApplyClientBehavior , dall’interfaccia IEndpointBehavior, che ci permette di aggiungere il nostro Inspector agli Inspector del client WCF. Come tutto in WCF, anche gli inspector sono completamente configurabili nell’app.config (o web.config), nella parte di serviceModel e tramite delle extensions.

Spero di avervi (e in particolare a chi me lo ha chiesto) aiutato.

Consumare Wcf con configurazione programmatica (senza toccare il web.config)

Le Windows Communication Foundation permettono una configurazione molto semplice e efficace, risolvendo in automatico i binding e tutte le configurazioni di channel, porte e quanto altro direttamente leggendo da web.config oppure da un app.config.

Il problema nasce quando andiamo a utilizzare ad esempio un client verso un servizio wcf , direttamente in delle application pages o webpart all’interno di Sharepoint.

In questo caso la configurazione può essere gestita in 3 modi:

Nel primo caso dobbiamo mettere mano al web.config di Sharepoint, in quanto le application pages e/o le webpart sono hostate all’interno della sua Web Applicaiton, e questo per motivi di policy, non sempre è possibile.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<system.serviceModel>

<bindings>

<basicHttpBinding>

<binding name="RichiestaDatiSoapBinding" closeTimeout="00:01:00"

openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"

allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"

maxBufferSize="2147483647" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"

messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"

useDefaultWebProxy="true">

<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="16384"

maxBytesPerRead="4096" maxNameTableCharCount="16384" />

<security mode="None">

<transport clientCredentialType="None" proxyCredentialType="None"

realm="" />

<message clientCredentialType="UserName" algorithmSuite="Default" />

</security>

</binding>

</basicHttpBinding>

</bindings>

<client>

<endpoint address="http://localhost:81/testservice/servizio.asmx" binding="basicHttpBinding" bindingConfiguration="RichiestaDatiSoapBinding"

contract="TestService.RichiestaDatiSoapBinding" name="RichiestaDatiSoapBinding" />

</client>

</system.serviceModel>

Il secondo meccanismo , messo a disposizione direttamente dalle Api di Sharepoint, prevede l’utilizzo delle SPWebConfigModification Api, che permettonod i manipolare il web.config di iis, mediante codice, andando ad aggiungere le parti che servono in fase , ad esempio, di attivazione di una feature.. A mio avviso questa parte è qualcosa di veramente terrificante, perche si arriva ad ottenere un web.config spesso illeggibile e quasi sempre non funzionante e oltretutto difficile da controllare visto che tutto il value che deve essere passato al configModification deve avere l’escape di tutti i caratteri particolari.. quindi pieno di entity xml come il @quot …

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SPWebConfigModification modificaWebConfig= new SPWebConfigModification();

modificaWebConfig.Path = "configuration/system.serviceModel";

modificaWebConfig.Sequence = 0;

modificaWebConfig.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

modificaWebConfig.Owner = System.Threading.Thread.CurrentPrincipal.Identity.Name;

modificaWebConfig.Value = @"<bindings><basicHttpBinding>..etc.etc..inserire qui tutto l'xml del binding";

SPWebService service = SPWebService.ContentService;

service.WebConfigModifications.Add(modificaWebConfig);
service.Update();
service.ApplyWebConfigModifications();

Un terzo modo è quello di creare una classe che fornisca direttamente il Binding (BasicHttpBinding) e l’Endpoint (EndPointAddess).

Purtroppo per motivi di sicurezza , microsoft ha bloccato la possibilità di leggere l’xml e deserializzarlo nelle relative classi messe a disposizioni dal Framework, quindi la creazione del binding va fatta “a mano”.

I dati possono essere statiticizzati nel codice o ad esempio letti da una Lista di Sharepoint, in cui magari andiamo a memorizzare in un unico Item tutto il blocco xml della configurazione del binding .

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class WCFClientConfiguration
{

public BasicHttpBinding Binding
{
get
{
BasicHttpBinding _binding = new BasicHttpBinding()
{
Name = "ServizioTestSoap",
CloseTimeout = new TimeSpan(1, 5, 0),
OpenTimeout = new TimeSpan(1, 5, 0),
ReceiveTimeout = new TimeSpan(1, 10, 0),
SendTimeout = new TimeSpan(1, 5, 0),
AllowCookies = false,
BypassProxyOnLocal = true,
HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
MaxBufferSize = 600000,
MaxBufferPoolSize = 524288,
MaxReceivedMessageSize = 600000,
MessageEncoding = WSMessageEncoding.Text,
TextEncoding = System.Text.Encoding.UTF8,
TransferMode = TransferMode.Buffered,
UseDefaultWebProxy = false,
ReaderQuotas = new XmlDictionaryReaderQuotas()
{
MaxDepth = 32,
MaxStringContentLength = 500000,
MaxArrayLength = 16384,
MaxBytesPerRead = 4096,
MaxNameTableCharCount = 16384
}

};

_binding.Security.Mode = BasicHttpSecurityMode.Transport;

return _binding;
}
}

public EndpointAddress Endpoint
{
get
{
return new EndpointAddress("https://localhost:81/testService/service.asmx");
}
}
}

 

In questo modo quando andiamo a instanziare il nostro client, usiamo il costruttore che accetta in input Binding e Endpoint.

1
2
3
WcfConfiguration conf = new WCFClientConfiguration();

ServizioTestSoapClient client = new ServizioTestSoapClient (conf.Binding,conf.Endpoint);

Questo permette la memorizzazione ad esempio della configurazione su DB o su altri sistemi di persistenza .