Cấu hình WCF không có tệp cấu hình


90

Có ai biết một ví dụ hay về cách hiển thị dịch vụ WCF theo chương trình mà không cần sử dụng tệp cấu hình không? Tôi biết mô hình đối tượng dịch vụ giờ đã phong phú hơn nhiều với WCF, vì vậy tôi biết nó có thể. Tôi chỉ chưa thấy một ví dụ về cách làm như vậy. Ngược lại, tôi cũng muốn biết mức độ tiêu thụ mà không có tệp cấu hình được thực hiện.

Trước khi bất kỳ ai hỏi, tôi có một nhu cầu rất cụ thể để làm điều này mà không có tệp cấu hình. Tôi thường không khuyến nghị một cách thực hành như vậy, nhưng như tôi đã nói, có một nhu cầu rất cụ thể trong trường hợp này.


1
Tại sao bạn không đề xuất một phương pháp như vậy (hiển thị dịch vụ theo chương trình mà không cần cấu hình)?
BornToCode

Câu trả lời:


115

Sử dụng một dịch vụ web mà không có tệp cấu hình rất đơn giản, như tôi đã khám phá. Bạn chỉ cần tạo một đối tượng ràng buộc và đối tượng địa chỉ và chuyển chúng đến phương thức khởi tạo của proxy máy khách hoặc đến một cá thể ChannelFactory chung. Bạn có thể xem app.config mặc định để xem cài đặt nào sẽ sử dụng, sau đó tạo phương thức trợ giúp tĩnh ở đâu đó khởi tạo proxy của bạn:

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

Cá nhân tôi thích cách tiếp cận này cho các ví dụ khi bạn định sử dụng tệp trong một vấn đề khác, ví dụ: nếu bạn đã mã hóa app.config của mình (hoặc tệp cấu hình tương đương) và không cần sử dụng WCF tích hợp sẵn. khả năng của nó đọc trong một kết nối
Noah

18
Để sử dụng https, hãy thêm bind.Security.Mode = BasicHttpSecurityMode.Transport;
ciscoheat

Điều này làm việc khá tốt cho tôi. Điểm khác biệt duy nhất đối với tôi là tôi cũng đặt thông tin ReaderQuotas và Security. Tôi đã sử dụng lời khuyên của ciscoheat và đặt Security.Transport.Mode thành Giao thông vận tải nếu sử dụng https (đối với tôi điều này không được biết tại thời điểm biên dịch).
Kirk Liemohn

2
Tôi vừa xác minh rằng tất cả các thuộc tính đang được đặt bằng với giá trị mặc định trong WCF 4, fwiw. (Nhưng lưu ý rằng Security.Modemặc định là None.)
ladenedge

19

Nếu bạn quan tâm đến việc loại bỏ việc sử dụng phần System.ServiceModel trong web.config cho lưu trữ IIS, tôi đã đăng một ví dụ về cách thực hiện điều đó tại đây ( http://bejabbers2.blogspot.com/2010/02/wcf -zero-config-in-net-35-part-ii.html ). Tôi chỉ cách tùy chỉnh ServiceHost để tạo cả siêu dữ liệu và điểm cuối wshttpbinding. Tôi làm điều đó theo cách có mục đích chung mà không yêu cầu mã hóa bổ sung. Đối với những người không ngay lập tức nâng cấp lên .NET 4.0, điều này có thể khá thuận tiện.


John, tôi chắc rằng đó là một bài đăng trên blog tuyệt vời, nhưng vì đã có câu trả lời được chấp nhận từ 17 tháng trước, nên câu trả lời của bạn có thực sự có mục đích gì không?
John Saunders

36
Vì đây là câu trả lời Stack Overflow đầu tiên của tôi nên có thể không phải là cách mọi thứ thường được thực hiện. Đã quen thuộc với những cuốn sách của Lowy và Bustamante, đó là những tài liệu tham khảo tuyệt vời, tôi nghĩ câu trả lời của tôi vượt xa những mẫu họ đưa ra. Tôi chủ yếu sử dụng Stack Overflow khi googling để tôi thường xuyên đọc các bài đăng cũ hơn. Có nhiều câu trả lời cập nhật hơn chỉ giúp ích từ quan điểm của tôi. Tôi đã truy cập vào bài đăng này trước khi viết mã của mình để tránh phát minh lại bánh xe.
John Wigger

48
Là một người dùng SO thường xuyên, tôi thấy khá mong muốn được đọc các bài viết mới về các chủ đề cũ. Nó giúp tôi thực hiện công việc của mình tốt hơn, điều này làm tăng giá trị của trang web này (vì bản thân tôi và những người khác sẽ truy cập nó nhiều hơn). Thay vì là người tuân theo các quy tắc, tại sao không cho phép mọi người thảo luận để có thể khám phá ra những câu trả lời hay hơn? Đó không phải là vấn đề?

7
Có vẻ như John Saunders đã được đặt vào vị trí của anh ấy với câu trả lời cho câu hỏi của chính anh ấy (không câu hỏi nào anh ấy chấp nhận là câu trả lời mà tôi có thể thêm vào). Cá nhân tôi không gặp vấn đề gì với việc trả lời muộn cho các câu hỏi và thường rất vui khi thấy câu trả lời mới cho câu hỏi tôi đã hỏi, vài tháng nếu không phải là nhiều năm sau. Trớ trêu thay, tôi đã giành được huy hiệu Necromancer của riêng mình nhờ câu trả lời được chấp nhận cho chính câu hỏi này. :)
tàis1

3
Tôi đã gặp vấn đề tương tự và câu trả lời được chấp nhận không giúp được gì cho tôi, nhưng điều này đã xảy ra, khiến bạn có câu trả lời muộn! Nếu không có câu trả lời muộn, tôi đã phải tạo ra một câu hỏi trùng lặp về điều này.
Didier A.

15

Đây, đây là mã hoàn chỉnh và đang hoạt động. Tôi nghĩ nó sẽ giúp ích cho bạn rất nhiều. Tôi đã tìm kiếm và không bao giờ tìm thấy mã hoàn chỉnh, đó là lý do tại sao tôi cố gắng đặt mã hoàn chỉnh và hoạt động. Chúc may mắn.

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

Ví dụ rất hay! Bạn thể hiện gần như mọi khía cạnh của cấu hình thủ công. Rất tốt!
Kilhoffer

5
Tôi không hiểu cách EvalServiceClient phù hợp với mã này. Nó được tham chiếu, nhưng không được định nghĩa. Tại sao máy chủ tạo máy khách?
BlueMonkMN


3

Tất cả cấu hình WCF có thể được thực hiện theo chương trình. Vì vậy, có thể tạo cả máy chủ và máy khách mà không cần tệp cấu hình.

Tôi giới thiệu cuốn sách "Lập trình các dịch vụ WCF" của Juval Lowy, trong đó có nhiều ví dụ về cấu hình lập trình.


2

Nó rất dễ thực hiện trên cả máy khách và máy chủ. Cuốn sách của Juval Lowy có những ví dụ xuất sắc.

Đối với nhận xét của bạn về các tệp cấu hình, tôi muốn nói rằng tệp cấu hình là một người nghèo thứ hai để làm điều đó trong mã. Tệp cấu hình tuyệt vời khi bạn kiểm soát mọi máy khách sẽ kết nối với máy chủ của bạn và đảm bảo rằng chúng được cập nhật và người dùng không thể tìm thấy chúng và thay đổi bất kỳ điều gì. Tôi thấy mô hình tệp cấu hình WCF bị hạn chế, hơi khó thiết kế và một cơn ác mộng bảo trì. Nói chung, tôi nghĩ rằng đó là một quyết định rất sai lầm của MS khi đặt các tệp cấu hình làm cách hoạt động mặc định.

CHỈNH SỬA: Một trong những điều bạn không thể làm với tệp cấu hình là tạo các dịch vụ với các hàm tạo không mặc định. Điều này dẫn đến các biến tĩnh / toàn cục và các đơn lẻ và các loại không có nghĩa khác trong WCF.


2

Tôi thấy bài đăng trên blog ở liên kết bên dưới xoay quanh chủ đề này rất thú vị.

Một ý tưởng tôi thích là có thể chuyển phần XML liên kết hoặc hành vi hoặc địa chỉ từ cấu hình đến đối tượng WCF thích hợp và để nó xử lý việc gán các thuộc tính - hiện tại bạn không thể làm điều này.

Giống như những người khác trên web, tôi đang gặp sự cố xung quanh việc cần triển khai WCF của mình để sử dụng tệp cấu hình khác với tệp cấu hình của ứng dụng lưu trữ của tôi (là dịch vụ .NET 2.0 Windows).

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.