14

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

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

WCF 真的很强大——你可以使用许多不同的方式来连接,但似乎都涉及到很多详细的配置。如果主机和客户端不完全匹配,您将很难破译错误。

我想让桌面应用程序更容易配置——最好是某种自动发现。桌面应用程序的用户应该能够输入 URL,然后它会完成其余的工作。

有谁知道这样做的好方法?

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

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

是否有任何方法、机制、第 3 方库或任何东西可以自动发现 WCF 设置?

4

3 回答 3

9

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

于 2008-09-19T06:30:49.650 回答
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;
}
于 2008-09-19T11:27:26.910 回答
1

现在有另一种方法可以做到这一点,当我问最初的问题时它是不可用的。Microsoft 现在支持 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 序列化 - 这允许 Java、ActionScript、Javascript、Silverlight 或其他任何可以轻松处理 JSON 和 REST 的东西使用相同的 WCF 服务。

于 2009-12-02T16:45:10.223 回答