Configurazione WCF senza un file di configurazione


90

Qualcuno conosce un buon esempio di come esporre un servizio WCF in modo programmatico senza l'uso di un file di configurazione? So che il modello a oggetti del servizio è molto più ricco ora con WCF, quindi so che è possibile. Semplicemente non ho visto un esempio di come farlo. Al contrario, vorrei vedere come si consuma anche senza un file di configurazione.

Prima che qualcuno me lo chieda, ho un bisogno molto specifico di farlo senza i file di configurazione. Normalmente non consiglierei una tale pratica, ma come ho detto, in questo caso c'è un'esigenza molto specifica.


1
Perché non consiglieresti una tale pratica (esponendo il servizio in modo programmatico senza configurazione)?
BornToCode

Risposte:


115

L'utilizzo di un servizio Web senza un file di configurazione è molto semplice, come ho scoperto. È sufficiente creare un oggetto di associazione e un oggetto indirizzo e passarli al costruttore del proxy client o a un'istanza ChannelFactory generica. Puoi guardare l'app.config predefinito per vedere quali impostazioni utilizzare, quindi creare un metodo di supporto statico da qualche parte che istanzia il tuo proxy:

internal static MyServiceSoapClient CreateWebServiceInstance() {
    BasicHttpBinding binding = new BasicHttpBinding();
    // I think most (or all) of these are defaults--I just copied them from app.config:
    binding.SendTimeout = TimeSpan.FromMinutes( 1 );
    binding.OpenTimeout = TimeSpan.FromMinutes( 1 );
    binding.CloseTimeout = TimeSpan.FromMinutes( 1 );
    binding.ReceiveTimeout = TimeSpan.FromMinutes( 10 );
    binding.AllowCookies = false;
    binding.BypassProxyOnLocal = false;
    binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
    binding.MessageEncoding = WSMessageEncoding.Text;
    binding.TextEncoding = System.Text.Encoding.UTF8;
    binding.TransferMode = TransferMode.Buffered;
    binding.UseDefaultWebProxy = true;
    return new MyServiceSoapClient( binding, new EndpointAddress( "http://www.mysite.com/MyService.asmx" ) );
}

Personalmente mi piace questo approccio per esempi quando utilizzerai il file in una questione diversa, ad esempio, se hai crittografato il tuo app.config (o il file di configurazione equivalente) e non è necessario utilizzare il WCF integrato capacità di lettura in una connessione
Noah

18
Per l'utilizzo di https, aggiungi binding.Security.Mode = BasicHttpSecurityMode.Transport;
ciscoheat

Questo ha funzionato abbastanza bene per me. L'unica differenza per me è che ho impostato anche ReaderQuotas e Informazioni sulla sicurezza. Ho utilizzato i consigli di ciscoheat e ho impostato Security.Transport.Mode su Transport se si utilizza https (per me questo non è noto in fase di compilazione).
Kirk Liemohn

2
Ho appena verificato che tutte le proprietà impostate sono uguali ai valori predefiniti in WCF 4, fwiw. (Ma nota che il Security.Modevalore predefinito è None.)
ladenedge

19

Se sei interessato a eliminare l'utilizzo della sezione System.ServiceModel nel web.config per l'hosting IIS, ho pubblicato un esempio di come farlo qui ( http://bejabbers2.blogspot.com/2010/02/wcf -zero-config-in-net-35-part-ii.html ). Mostro come personalizzare un ServiceHost per creare sia metadati che endpoint wshttpbinding. Lo faccio in un modo generico che non richiede codifica aggiuntiva. Per coloro che non aggiornano immediatamente a .NET 4.0 questo può essere piuttosto conveniente.


John, sono sicuro che sia un ottimo post sul blog, ma dato che c'è una risposta accettata di 17 mesi fa, c'è davvero uno scopo nella tua risposta?
John Saunders,

36
Poiché questa è la mia prima risposta di Stack Overflow, potrebbe non essere il modo in cui vengono fatte le cose di solito. Avendo familiarità con i libri di Lowy e Bustamante, che sono ottimi riferimenti, penso che la mia risposta vada ben oltre gli esempi che offrono. Uso principalmente Stack Overflow quando scrivo su Google, quindi leggo spesso i post più vecchi. Avere risposte più aggiornate aiuta solo dal mio punto di vista. Ho cercato su Google questo post prima di scrivere il mio codice per evitare di reinventare la ruota.
John Wigger,

48
Come utente SO abituale, trovo piuttosto desiderabile leggere nuovi post su vecchi argomenti. Mi aiuta a fare meglio il mio lavoro, il che aumenta il valore di questo sito (poiché io e gli altri lo visiteremo di più). Piuttosto che essere un pignolo con le regole, perché non permettere alle persone di discutere in modo da poter trovare risposte migliori? Non è questo il punto?

7
Sembra che John Saunders sia stato messo al suo posto con la risposta alla sua stessa domanda (nessuna delle quali ha accettato come risposta potrei aggiungere). Personalmente non ho alcun problema con le risposte tardive alle domande e di solito sono felice di vedere una nuova risposta a una domanda che ho posto, mesi se non anni dopo. Ironia della sorte, ho guadagnato il mio distintivo da Negromante con la mia risposta accettata proprio a questa domanda. :)
devios1

3
Ho avuto lo stesso problema e la risposta accettata non mi ha aiutato, ma questo sì, evviva le risposte tardive! Se non fosse stato per le risposte tardive, avrei dovuto creare una domanda duplicata di questo.
Didier A.

15

Ecco, questo è un codice completo e funzionante. Penso che ti aiuterà molto. Stavo cercando e non trova mai un codice completo, ecco perché ho provato a inserire un codice completo e funzionante. In bocca al lupo.

public class ValidatorClass
{
    WSHttpBinding BindingConfig;
    EndpointIdentity DNSIdentity;
    Uri URI;
    ContractDescription ConfDescription;

    public ValidatorClass()
    {  
        // In constructor initializing configuration elements by code
        BindingConfig = ValidatorClass.ConfigBinding();
        DNSIdentity = ValidatorClass.ConfigEndPoint();
        URI = ValidatorClass.ConfigURI();
        ConfDescription = ValidatorClass.ConfigContractDescription();
    }


    public void MainOperation()
    {
         var Address = new EndpointAddress(URI, DNSIdentity);
         var Client = new EvalServiceClient(BindingConfig, Address);
         Client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerTrust;
         Client.Endpoint.Contract = ConfDescription;
         Client.ClientCredentials.UserName.UserName = "companyUserName";
         Client.ClientCredentials.UserName.Password = "companyPassword";
         Client.Open();

         string CatchData = Client.CallServiceMethod();

         Client.Close();
    }



    public static WSHttpBinding ConfigBinding()
    {
        // ----- Programmatic definition of the SomeService Binding -----
        var wsHttpBinding = new WSHttpBinding();

        wsHttpBinding.Name = "BindingName";
        wsHttpBinding.CloseTimeout = TimeSpan.FromMinutes(1);
        wsHttpBinding.OpenTimeout = TimeSpan.FromMinutes(1);
        wsHttpBinding.ReceiveTimeout = TimeSpan.FromMinutes(10);
        wsHttpBinding.SendTimeout = TimeSpan.FromMinutes(1);
        wsHttpBinding.BypassProxyOnLocal = false;
        wsHttpBinding.TransactionFlow = false;
        wsHttpBinding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
        wsHttpBinding.MaxBufferPoolSize = 524288;
        wsHttpBinding.MaxReceivedMessageSize = 65536;
        wsHttpBinding.MessageEncoding = WSMessageEncoding.Text;
        wsHttpBinding.TextEncoding = Encoding.UTF8;
        wsHttpBinding.UseDefaultWebProxy = true;
        wsHttpBinding.AllowCookies = false;

        wsHttpBinding.ReaderQuotas.MaxDepth = 32;
        wsHttpBinding.ReaderQuotas.MaxArrayLength = 16384;
        wsHttpBinding.ReaderQuotas.MaxStringContentLength = 8192;
        wsHttpBinding.ReaderQuotas.MaxBytesPerRead = 4096;
        wsHttpBinding.ReaderQuotas.MaxNameTableCharCount = 16384;

        wsHttpBinding.ReliableSession.Ordered = true;
        wsHttpBinding.ReliableSession.InactivityTimeout = TimeSpan.FromMinutes(10);
        wsHttpBinding.ReliableSession.Enabled = false;

        wsHttpBinding.Security.Mode = SecurityMode.Message;
        wsHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
        wsHttpBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
        wsHttpBinding.Security.Transport.Realm = "";

        wsHttpBinding.Security.Message.NegotiateServiceCredential = true;
        wsHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
        wsHttpBinding.Security.Message.AlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Basic256;
        // ----------- End Programmatic definition of the SomeServiceServiceBinding --------------

        return wsHttpBinding;

    }

    public static Uri ConfigURI()
    {
        // ----- Programmatic definition of the Service URI configuration -----
        Uri URI = new Uri("http://localhost:8732/Design_Time_Addresses/TestWcfServiceLibrary/EvalService/");

        return URI;
    }

    public static EndpointIdentity ConfigEndPoint()
    {
        // ----- Programmatic definition of the Service EndPointIdentitiy configuration -----
        EndpointIdentity DNSIdentity = EndpointIdentity.CreateDnsIdentity("tempCert");

        return DNSIdentity;
    }


    public static ContractDescription ConfigContractDescription()
    {
        // ----- Programmatic definition of the Service ContractDescription Binding -----
        ContractDescription Contract = ContractDescription.GetContract(typeof(IEvalService), typeof(EvalServiceClient));

        return Contract;
    }
}

Esempio molto carino! Dimostrate quasi ogni aspetto della configurazione manuale. Ben fatto!
Kilhoffer

5
Non capisco come EvalServiceClient si inserisca in questo codice. È referenziato, ma non definito. Perché il server crea un client?
BlueMonkMN


3

Tutta la configurazione WCF può essere eseguita in modo programmatico. Quindi è possibile creare sia server che client senza un file di configurazione.

Consiglio il libro "Programming WCF Services" di Juval Lowy, che contiene molti esempi di configurazione programmatica.


2

È molto facile da fare sia dal lato client che dal lato server. Il libro di Juval Lowy ha ottimi esempi.

Per quanto riguarda il tuo commento sui file di configurazione, direi che i file di configurazione sono i secondi di un uomo povero a farlo in codice. I file di configurazione sono ottimi quando controlli ogni client che si connetterà al tuo server e assicurati che siano aggiornati e che gli utenti non possano trovarli e modificare nulla. Trovo che il modello del file di configurazione WCF sia limitante, leggermente difficile da progettare e un incubo di manutenzione. Tutto sommato, penso che sia stata una decisione molto sbagliata da parte di MS rendere i file di configurazione il modo predefinito di fare le cose.

EDIT: una delle cose che non puoi fare con il file di configurazione è creare servizi con costruttori non predefiniti. Questo porta a variabili statiche / globali e singleton e altri tipi di non senso in WCF.


2

Ho trovato molto interessante il post del blog al link sottostante su questo argomento.

Un'idea che mi piace è quella di poter semplicemente passare una sezione XML di binding o comportamento o indirizzo dalla configurazione all'oggetto WCF appropriato e lasciare che gestisca l'assegnazione delle proprietà - attualmente non puoi farlo.

Come altri sul Web, sto riscontrando problemi riguardo alla necessità della mia implementazione WCF per utilizzare un file di configurazione diverso da quello della mia applicazione di hosting (che è un servizio Windows .NET 2.0).

http://salvoz.com/blog/2007/12/09/programmatically-setting-wcf-configuration/

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.