我有一组由桌面应用程序动态连接的WCF Web服务。
我的问题是WCF需要工作的非常详细的配置设置。让SSL工作涉及自定义设置。让MTOM或其他任何东西工作需要更多。你想要压缩吗?我们再来一次......
WCF非常强大 - 您可以使用许多不同的方式进行连接,但似乎都涉及大量详细的配置。如果主机和客户端不完全匹配,则很难解密错误。
我想让桌面应用程序更容易配置 - 理想情况下是某种自动发现。桌面应用程序的用户应该只能输入URL,然后完成剩下的工作。
有没有人知道这样做的好方法?
我知道Visual Studio可以为您设置配置,但我希望桌面应用能够基于各种不同的服务器设置来完成。
我知道VS的工具可以在外部使用,但我正在寻找桌面应用的用户而不必是WCF专家。我知道MS故意使这个过于复杂。
有没有办法,机制,第三方库或任何可以自动发现WCF设置的东西?
答案 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。
您需要对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服务。