Конфігурація WCF без конфігураційного файлу


90

Хтось знає хороший приклад того, як програмно виставляти службу WCF без використання конфігураційного файлу? Я знаю, що об'єктна модель обслуговування набагато багатша з WCF, тому знаю, що це можливо. Я просто не бачив прикладу, як це робити. І навпаки, я хотів би побачити, як витрачається і без файлу конфігурації.

Перш ніж хтось запитає, у мене є дуже конкретна потреба зробити це без файлів конфігурації. Зазвичай я б не рекомендував таку практику, але, як я вже сказав, у цьому випадку існує цілком конкретна потреба.


1
Чому б вам не рекомендувати таку практику (виставляти послугу програмно без конфігурації)?
— BornToCode

Відповіді:


115

Як я виявив, користуватися веб-службою без конфігураційного файлу дуже просто. Вам просто потрібно створити об’єкт прив’язки та об’єкт адреси та передати їх або конструктору клієнтського проксі-сервера, або загальному екземпляру ChannelFactory. Ви можете подивитися за замовчуванням app.config, щоб побачити, які налаштування використовувати, а потім створити статичний метод-помічник десь, який створює екземпляр вашого проксі:

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" ) );
}

Мені особисто подобається такий підхід для прикладів, коли ви збираєтеся використовувати файл в іншому питанні, наприклад, якщо ви зашифрували свій app.config (або еквівалентний конфігураційний файл) і вам не потрібно використовувати вбудований WCF можливості його читання у зв'язку
— Ной

18
Для використання https додайте binding.Security.Mode = BasicHttpSecurityMode.Transport;
— ciscoheat

Це спрацювало для мене досить добре. Єдина різниця для мене полягає в тому, що я також встановлюю ReaderQuotas та інформацію про безпеку. Я скористався порадою ciscoheat і встановив Security.Transport.Mode на Transport, якщо використовую https (для мене це невідомо під час компіляції).
— Кірк Лімон,

2
Я щойно перевірив, що всі властивості, що встановлюються, дорівнюють значенням за замовчуванням у WCF 4, fwiw. (Але зверніть увагу, що Security.Modeза замовчуванням None.)
— ladenedge

19

Якщо ви зацікавлені усунути використання розділу System.ServiceModel у веб-файлі web.config для хостингу IIS, я опублікував приклад, як це зробити тут ( http://bejabbers2.blogspot.com/2010/02/wcf -zero-config-in-net-35-part-ii.html ). Я показую, як налаштувати ServiceHost для створення як метаданих, так і кінцевих точок wshttpbinding. Я роблю це загальним способом, який не вимагає додаткового кодування. Для тих, хто не відразу переходить на .NET 4.0, це може бути досить зручно.


Джон, я впевнений, що це чудова публікація в блозі, але оскільки є прийнята відповідь 17 місяців тому, чи справді є якась мета вашої відповіді?
— Джон Сондерс,

36
Оскільки це моя перша відповідь на переповнення стека, можливо, це не так, як це зазвичай роблять. Будучи знайомим із книгами Лоуі та Бустаманте, які є чудовими посиланнями, я думаю, що моя відповідь виходить далеко за межі зразків, які вони пропонують. Я в основному використовую Stack Overflow під час гуглювання, тому я часто читаю повідомлення, які старіші. Мати більш сучасні відповіді допомагає лише з моєї точки зору. Я погуглив цю публікацію перед написанням коду, щоб уникнути повторного винайдення колеса.
— Джон Віггер

48
Як частий користувач SO, я вважаю, що дуже бажано читати нові повідомлення на старі теми. Це допомагає мені краще виконувати свою роботу, що збільшує цінність цього веб-сайту (оскільки я та інші відвідуватимемо його більше). Замість того, щоб бути прихильником правил, чому б не дозволити людям обговорювати так кращі відповіді? Хіба не в цьому справа?

7
Здається, Джон Сондерс був поставлений на його місце з відповіддю на його власне запитання (жодне з яких він не прийняв як відповідь, я можу додати). У мене особисто немає проблем із запізнілими відповідями на запитання, і я, як правило, радий побачити нову відповідь на запитання, яке я задав, місяці, якщо не роки потому. За іронією долі, я отримав власний значок «Некромант», прийнявши відповідь саме на це питання. :)
— devios1

3
У мене було те саме питання, і прийнята відповідь мені не допомогла, але це допомогло, ура на пізні відповіді! Якби не пізні відповіді, мені довелося б створити дублікат цього запитання.
— Didier A.

15

Ось це повний і робочий код. Думаю, це тобі дуже допоможе. Я шукав і ніколи не знаходжу повного коду, тому намагався ввести повний та робочий код. Удачі.

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;
    }
}

Дуже гарний приклад! Ви демонструєте майже кожен аспект ручного налаштування. Чудово зроблено!
— Kilhoffer

5
Я не розумію, як EvalServiceClient вписується в цей код. Це посилання, але не визначене. Чому сервер створює клієнта?
— BlueMonkMN


3

Всі конфігурації WCF можна виконувати програмно. Отже, можна створювати як сервери, так і клієнти без конфігураційного файлу.

Я рекомендую книгу "Програмування служб WCF" Джувала Лоуі, яка містить багато прикладів програмної конфігурації.


2

Це дуже легко зробити як на клієнтській, так і на серверній стороні. У книзі Джувала Лоуі є чудові приклади.

Щодо вашого коментаря щодо конфігураційних файлів, я б сказав, що конфігураційні файли - це бідна людина, яка займає друге місце в коді. Файли конфігурації чудово підходять, коли ви керуєте кожним клієнтом, який підключатиметься до вашого сервера та переконайтеся, що вони оновлені, і що користувачі не можуть їх знайти та щось змінити. Я вважаю, що модель файлу конфігурації WCF є обмежувальною, злегка складною для проектування та кошмаром для обслуговування. Загалом, я думаю, що було дуже поганим рішенням з боку MS зробити файли конфігурації типовими способами.

РЕДАГУВАТИ: Однією з речей, яку ви не можете зробити з файлом конфігурації, є створення служб із конструкторами, які не є типовими. Це призводить до статичних / глобальних змінних та синглтонів та інших типів не-сенсу в WCF.


2

Я знайшов повідомлення в блозі за посиланням нижче навколо цієї теми дуже цікавим.

Одна ідея, яка мені подобається, полягає в тому, що я можу просто передати прив'язку або поведінку або звернутися до XML-розділу з конфігурації до відповідного об'єкта WCF і дозволити йому обробляти призначення властивостей - наразі ви не можете цього зробити.

Як і інші в Інтернеті, у мене виникають проблеми з необхідністю моєї реалізації WCF використовувати інший файл конфігурації, ніж файл мого хостинг-додатку (який є службою Windows .NET 2.0).

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.