使WCF更易于配置

时间:2008-09-17 20:50:50

标签: .net wcf configuration

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

我的问题是WCF需要工作的非常详细的配置设置。让SSL工作涉及自定义设置。让MTOM或其他任何东西工作需要更多。你想要压缩吗?我们再来一次......

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

我想让桌面应用程序更容易配置 - 理想情况下是某种自动发现。桌面应用程序的用户应该只能输入URL,然后完成剩下的工作。

有没有人知道这样做的好方法?

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

我知道VS的工具可以在外部使用,但我正在寻找桌面应用的用户而不必是WCF专家。我知道MS故意使这个过于复杂。

有没有办法,机制,第三方库或任何可以自动发现WCF设置的东西?

3 个答案:

答案 0 :(得分:9)

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

答案 1 :(得分:1)

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

虽然它有点乱,有一些错误(例如,不应该是区分大小写的检查),有一些我不需要的UI功能,并且会重复大量的代码。

我已经从中获取了实际的发现机制,重新编写并几乎让它工作(连接,但需要一些精力)。

首先使用main方法使用的一些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;
}

答案 2 :(得分:1)

现在有另一种方法可以解决这个问题。 Microsoft现在支持针对WCF服务的REST。

  • 使用REST的缺点是你失去了WSDL。
  • 优点是配置最少,你的WCF合约接口仍然有用!

您需要对System.ServiceModel.Web

的新引用

使用WebInvokeWebGet

标记您的操作
//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序列化 - 允许Java,ActionScript,Javascript,Silverlight或其他任何可以轻松处理JSON和REST的东西使用相同的WCF服务。