代码之家  ›  专栏  ›  技术社区  ›  Keith

使WCF更易于配置

  •  14
  • Keith  · 技术社区  · 17 年前

    我有一组通过桌面应用程序动态连接到的WCF Web服务。

    我的问题是WCF工作所需的真正详细的配置设置。让SSL工作涉及到自定义设置。要想让MTOM或其他设备工作需要更多。你想要压缩吗?我们再来一次……

    WCF非常强大-您可以使用多种不同的方式连接主机,但似乎都涉及大量详细的配置。如果主机和客户机不完全匹配,就很难破译错误。

    我想让桌面应用程序更容易配置-理想情况下是某种自动发现。桌面应用程序的用户只需输入URL,其余的就可以了。

    有人知道怎么做吗?

    我知道Visual Studio可以为您设置配置,但我希望桌面应用程序能够基于各种不同的服务器设置进行配置。

    我知道vs的工具可以在外部使用,但我在寻找桌面应用的用户,不必成为wcf专家。我知道微软故意把这件事搞得太复杂了。

    是否有任何方法、机制、第三方库或任何东西使自动发现WCF设置成为可能?

    3 回复  |  直到 17 年前
        1
  •  9
  •   MichaelT    17 年前

    关于端点的所有信息都可以在服务的元数据中找到,您可以编写一个客户端,它将探索服务的元数据并配置客户端。对于一个代码示例,您可以查看这个优秀的 Mex Explorer 来自Juval Lowy。

        2
  •  1
  •   Keith    17 年前

    谢谢,这是有用的代码(+1)。

    不过,它有点混乱,有一些错误(例如,不应该进行区分大小写的检查),有很多我不需要的UI功能,并且重复了很多代码。

    我从中获取了实际的发现机制,重新编写了它,几乎使其正常工作(连接,但需要一些微调)。

    首先,主方法使用的一些util函数:

    /// <summary>If the url doesn't end with a WSDL query string append it</summary>
    static string AddWsdlQueryStringIfMissing( string input )
    {
        return input.EndsWith( "?wsdl", StringComparison.OrdinalIgnoreCase ) ?
            input : input + "?wsdl";
    }
    
    /// <summary>Imports the meta data from the specified location</summary>
    static ServiceEndpointCollection GetEndpoints( BindingElement bindingElement, Uri address, MetadataExchangeClientMode mode )
    {
        CustomBinding binding = new CustomBinding( bindingElement );
        MetadataSet metadata = new MetadataExchangeClient( binding ).GetMetadata( address, mode );
        return new WsdlImporter( metadata ).ImportAllEndpoints();
    }
    

    然后,一个尝试不同方式连接并返回端点的方法:

    public static ServiceEndpointCollection Discover( string url )
    {
        Uri address = new Uri( url );
        ServiceEndpointCollection endpoints = null;
    
        if ( string.Equals( address.Scheme, "http", StringComparison.OrdinalIgnoreCase ) )
        {
            var httpBindingElement = new HttpTransportBindingElement();
    
            //Try the HTTP MEX Endpoint
            try { endpoints = GetEndpoints( httpBindingElement, address, MetadataExchangeClientMode.MetadataExchange ); }
            catch { }
    
            //Try over HTTP-GET
            if ( endpoints == null )
                endpoints = GetEndpoints( httpBindingElement,
                    new Uri( AddWsdlQueryStringIfMissing( url ) ), MetadataExchangeClientMode.HttpGet );
        }
        else if ( string.Equals( address.Scheme, "https", StringComparison.OrdinalIgnoreCase ) )
        {
            var httpsBindingElement = new HttpsTransportBindingElement();
    
            //Try the HTTPS MEX Endpoint
            try { endpoints = GetEndpoints( httpsBindingElement, address, MetadataExchangeClientMode.MetadataExchange ); }
            catch { }
    
            //Try over HTTP-GET
            if ( endpoints == null )
                endpoints = GetEndpoints( httpsBindingElement,
                    new Uri( AddWsdlQueryStringIfMissing( url ) ), MetadataExchangeClientMode.HttpGet );
        }
        else if ( string.Equals( address.Scheme, "net.tcp", StringComparison.OrdinalIgnoreCase ) )
            endpoints = GetEndpoints( new TcpTransportBindingElement(), 
                address, MetadataExchangeClientMode.MetadataExchange );
    
        else if ( string.Equals( address.Scheme, "net.pipe", StringComparison.OrdinalIgnoreCase ) )
            endpoints = GetEndpoints( new NamedPipeTransportBindingElement(), 
                address, MetadataExchangeClientMode.MetadataExchange );
    
        return endpoints;
    }
    
        3
  •  1
  •   Keith    15 年前

    现在有另一种方法可以做到这一点,但在我问最初的问题时却没有。微软现在支持WCF服务的REST。

    • 使用REST的缺点是您会丢失WSDL。
    • 好处是配置最少,您的WCF合同接口仍然可以工作!

    你需要一个新的参考 System.ServiceModel.Web

    标记您的操作 WebInvoke WebGet

    //get a user - note that this can be cached by IIS and proxies
    [WebGet]
    User GetUser(string id )
    
    //post changes to a user
    [WebInvoke]
    void SaveUser(string id, User changes )
    

    将这些添加到站点很容易-添加 .svc 文件:

    <%@ServiceHost 
       Service="MyNamespace.MyServiceImplementationClass" 
       Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
    

    工厂行告诉ASP.NET如何激活端点-您根本不需要服务器端配置!

    然后构建 ChannelFactory 基本上是不变的,只是您不再需要指定端点(或者像我在其他答案中那样自动发现端点)。

    var cf = new WebChannelFactory<IMyContractInterface>();
    var binding = new WebHttpBinding();
    
    cf.Endpoint.Binding = binding;
    cf.Endpoint.Address = new EndpointAddress(new Uri("mywebsite.com/myservice.svc"));
    cf.Endpoint.Behaviors.Add(new WebHttpBehavior());
    
    IMyContractInterface wcfClient = cf.CreateChannel();
    
    var usr = wcfClient.GetUser("demouser");
    // and so on...
    

    注意,我没有指定或发现客户端配置-不需要本地配置!

    另一个大的好处是,您可以轻松切换到JSON序列化-允许相同的WCF服务被Java、ActionScript、JavaScript、Silverlight或任何其他可以轻松处理JSON和REST的东西所消耗。

    推荐文章