Configuration WCF sans fichier de configuration

90

Quelqu'un connaît-il un bon exemple de la façon d'exposer un service WCF par programme sans utiliser de fichier de configuration? Je sais que le modèle d'objet de service est beaucoup plus riche maintenant avec WCF, donc je sais que c'est possible. Je n'ai tout simplement pas vu d'exemple sur la façon de procéder. À l'inverse, j'aimerais voir comment la consommation sans fichier de configuration se fait également.

Avant que quiconque ne le demande, j'ai un besoin très spécifique de le faire sans fichiers de configuration. Je ne recommanderais normalement pas une telle pratique, mais comme je l'ai dit, il y a un besoin très spécifique dans ce cas.

Kilhoffer
la source
1
Pourquoi ne recommanderiez-vous pas une telle pratique (exposer le service par programme sans configuration)?
BornToCode

Réponses:

115

Consommer un service Web sans fichier de configuration est très simple, comme je l'ai découvert. Il vous suffit de créer un objet de liaison et un objet d'adresse et de les transmettre au constructeur du proxy client ou à une instance générique de ChannelFactory. Vous pouvez consulter le fichier app.config par défaut pour voir les paramètres à utiliser, puis créer une méthode d'assistance statique quelque part qui instancie votre 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" ) );
}
devios1
la source
Personnellement, j'aime cette approche pour des exemples lorsque vous allez utiliser le fichier dans un autre domaine, par exemple, si vous avez chiffré votre app.config (ou fichier de configuration équivalent) et n'avez pas besoin d'utiliser le WCF intégré capacités de lecture dans une connexion
Noah
18
Pour l'utilisation de https, ajoutez binding.Security.Mode = BasicHttpSecurityMode.Transport;
ciscoheat
Cela a très bien fonctionné pour moi. La seule différence pour moi est que j'ai également défini les informations de ReaderQuotas et de sécurité. J'ai utilisé les conseils de ciscoheat et défini le Security.Transport.Mode sur Transport si vous utilisez https (pour moi, cela n'est pas connu au moment de la compilation).
Kirk Liemohn
2
Je viens de vérifier que toutes les propriétés définies sont égales aux valeurs par défaut dans WCF 4, fwiw. (Mais notez que la valeur par Security.Modedéfaut est None.)
chargé
19

Si vous souhaitez éliminer l'utilisation de la section System.ServiceModel dans le web.config pour l'hébergement IIS, j'ai publié un exemple de la façon de le faire ici ( http://bejabbers2.blogspot.com/2010/02/wcf -zero-config-in-net-35-part-ii.html ). Je montre comment personnaliser un ServiceHost pour créer à la fois des métadonnées et des points de terminaison wshttpbinding. Je le fais d'une manière générale qui ne nécessite pas de codage supplémentaire. Pour ceux qui ne passent pas immédiatement à .NET 4.0, cela peut être très pratique.

John Wigger
la source
John, je suis sûr que c'est un excellent article de blog, mais comme il y a une réponse acceptée d'il y a 17 mois, y a-t-il vraiment un but à votre réponse?
John Saunders
36
Comme il s'agit de ma première réponse Stack Overflow, ce n'est peut-être pas la façon dont les choses sont généralement faites. Connaissant les livres Lowy et Bustamante, qui sont de belles références, je pense que ma réponse va bien au-delà des échantillons qu'ils proposent. J'utilise principalement Stack Overflow lorsque je cherche sur Google, donc je lis fréquemment les articles plus anciens. Avoir des réponses plus à jour n'aide que de mon point de vue. J'ai googlé ce post avant d'écrire mon code pour éviter de réinventer la roue.
John Wigger
48
En tant qu'utilisateur fréquent de SO, je trouve qu'il est tout à fait souhaitable de lire de nouveaux articles sur d'anciens sujets. Cela m'aide à mieux faire mon travail, ce qui augmente la valeur de ce site (car moi et d'autres le visiterons davantage). Plutôt que de rester fidèle aux règles, pourquoi ne pas permettre aux gens de discuter afin que de meilleures réponses puissent être trouvées? N'est-ce pas le but?
7
Il semble que John Saunders a été mis à sa place avec la réponse à sa propre question (dont il n'a accepté aucune comme réponse que je pourrais ajouter). Personnellement, je n'ai aucun problème avec les réponses tardives aux questions, et je suis généralement ravi de voir une nouvelle réponse à une question que j'ai posée, des mois sinon des années plus tard. Ironiquement, j'ai gagné mon propre badge Nécromancien avec ma réponse acceptée à cette question même. :)
devios1
3
J'ai eu le même problème, et la réponse acceptée ne m'a pas aidé, mais c'est le cas, hourra pour les réponses tardives! S'il n'y avait pas eu de réponses tardives, j'aurais dû créer une double question à ce sujet.
Didier A.
15

Ici, c'est un code complet et fonctionnel. Je pense que cela vous aidera beaucoup. Je cherchais et je ne trouve jamais de code complet, c'est pourquoi j'ai essayé de mettre du code complet et fonctionnel. Bonne chance.

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;
    }
}
SM Khaled Reza
la source
Très bel exemple! Vous démontrez presque tous les aspects de la configuration manuelle. Bien fait!
Kilhoffer
5
Je ne comprends pas comment EvalServiceClient s'intègre dans ce code. Il est référencé, mais non défini. Pourquoi le serveur crée-t-il un client?
BlueMonkMN
5

Ce n'est pas facile côté serveur .

Pour le côté client, vous pouvez utiliser ChannelFactory

Gulzar Nazim
la source
3

Toute configuration WCF peut être effectuée par programme. Il est donc possible de créer à la fois des serveurs et des clients sans fichier de configuration.

Je recommande le livre "Programming WCF Services" de Juval Lowy, qui contient de nombreux exemples de configuration programmatique.

Paul Lalonde
la source
2

C'est très facile à faire à la fois du côté client et du côté serveur. Le livre de Juval Lowy a d'excellents exemples.

Quant à votre commentaire sur les fichiers de configuration, je dirais que les fichiers de configuration sont une seconde pour les pauvres pour le faire dans le code. Les fichiers de configuration sont parfaits lorsque vous contrôlez chaque client qui se connectera à votre serveur et que vous vous assurez qu'ils sont mis à jour et que les utilisateurs ne peuvent pas les trouver et modifier quoi que ce soit. Je trouve que le modèle de fichier de configuration WCF est limitatif, légèrement difficile à concevoir et un cauchemar de maintenance. Dans l'ensemble, je pense que c'était une très mauvaise décision de la part de MS de faire des fichiers de configuration la manière par défaut de faire les choses.

EDIT: Une des choses que vous ne pouvez pas faire avec le fichier de configuration est de créer des services avec des constructeurs non par défaut. Cela conduit à des variables statiques / globales et des singletons et à d'autres types de non-sens dans WCF.

Steve
la source
2

J'ai trouvé le billet de blog sur le lien ci-dessous autour de ce sujet très intéressant.

Une idée que j'aime est de pouvoir simplement passer une section XML de liaison ou de comportement ou d'adresse de la configuration à l'objet WCF approprié et de le laisser gérer l'attribution des propriétés - actuellement, vous ne pouvez pas le faire.

Comme d'autres sur le Web, je rencontre des problèmes pour avoir besoin de mon implémentation WCF pour utiliser un fichier de configuration différent de celui de mon application d'hébergement (qui est un service Windows .NET 2.0).

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

Ton
la source