Конфігурація 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.