Конфигурация 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" ) );
}
devios1
источник
Мне лично нравится этот подход для примеров, когда вы собираетесь использовать файл в другом деле, например, если вы зашифровали свой app.config (или эквивалентный файл конфигурации) и вам не нужно использовать встроенный WCF возможности чтения в связке
Ной
18
Для использования https добавьте привязку.Security.Mode = BasicHttpSecurityMode.Transport;
ciscoheat
У меня это сработало. Единственное отличие для меня в том, что я также установил ReaderQuotas и информацию о безопасности. Я воспользовался советом ciscoheat и установил для Security.Transport.Mode значение Transport при использовании https (для меня это не известно во время компиляции).
Kirk Liemohn
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 для создания как метаданных, так и конечных точек привязки wshttp. Я делаю это универсальным способом, который не требует дополнительного программирования. Для тех, кто не обновляется сразу до .NET 4.0, это может быть очень удобно.

Джон Виггер
источник
Джон, я уверен, что это отличный пост в блоге, но, поскольку есть принятый ответ от 17 месяцев назад, есть ли смысл в вашем ответе?
Джон Сондерс,
36
Поскольку это мой первый ответ о переполнении стека, который может быть не таким, как обычно. Поскольку я знаком с книгами Лоуи и Бустаманте, которые являются отличными справочными материалами, я думаю, что мой ответ выходит далеко за рамки предлагаемых ими образцов. Я в основном использую Stack Overflow при поиске в Google, поэтому я часто читаю более старые сообщения. Наличие более свежих ответов помогает только с моей точки зрения. Я погуглил этот пост перед написанием кода, чтобы не изобретать колесо заново.
Джон Виггер,
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;
    }
}
С.М. Халед Реза
источник
Очень красивый пример! Вы демонстрируете почти все аспекты ручной настройки. Отлично сделано!
Килхоффер
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/

Тон
источник