在 WCF 中寻址服务时出现问题
本文关键字:问题 服务 WCF 寻址 | 更新日期: 2023-09-27 17:56:31
我正在使用 wcf 编写服务。我创建了一个包含两个项目的解决方案:
- 库:用于存储与服务相关的文件的项目(包含该服务的接口和相应的实现)。此项目是一个库项目。 托管
- 应用程序 用于托管这些服务(自托管)的项目。出于这个原因,这个项目是一个可执行项目,有一个配置文件,我在其中放置了配置服务所需的信息。
我还编写了一个客户端来调用该服务。这将称为客户端应用程序。
我有一项服务。以下是接口和实现(库项目):
namespace EchoWcfLibrary {
/// <summary>
/// The interface specifies for those classes implementing it (services), the operation that the service will expose.
/// </summary>
[ServiceContract]
public interface IService1 {
// This does not use serialization (implicit serialization in considered: base types used).
[OperationContract]
string GetData(int value);
// This uses data contracts and serialization.
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
}
[DataContract]
public class CompositeType {
// Members not serialized
bool boolValue = true;
string stringValue = "Hello ";
// Serialized
[DataMember]
public bool BoolValue {
get { return boolValue; }
set { boolValue = value; }
}
// Serialized
[DataMember]
public string StringValue {
get { return stringValue; }
set { stringValue = value; }
}
}
}
以下是服务主机应用程序(可执行项目)的启动:
namespace WcfServiceApplication {
public static class Program {
static void Main(string[] args) {
// Setting endpoints and setting the service to start properly.
// Base address specified: http://localhost:8081/Service1
Console.WriteLine("Beginning...");
using (ServiceHost host = new ServiceHost(typeof(Service1), new Uri("http://localhost:8081/Service1"))) {
Console.WriteLine("Opening host...");
host.Open();
Console.WriteLine("Waiting...");
System.Threading.Thread.Sleep(1000000);
Console.WriteLine("Closing...");
host.Close();
Console.WriteLine("Quitting...");
}
}
}
}
以下是可执行项目(托管应用程序)中的App.config
:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<services>
<service name="WcfServiceLibrary.Service1">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8081/Service1" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="/GoInto/Svc"
binding="basicHttpBinding"
contract="WcfServiceLibrary.IService1">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="/GoInto/Sav"
binding="basicHttpBinding"
contract="WcfServiceLibrary.IService1">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="GoInto/Mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
以下是客户端可执行项目中的程序启动(已经建立了库项目的链接),基本上这就是客户端:
namespace WcfServiceClient {
class Program {
static void Main(string[] args) {
ServiceEndpoint httpEndpoint = new ServiceEndpoint(ContractDescription.GetContract(typeof(IService1)), new BasicHttpBinding(), new EndpointAddress("http://localhost:8081/Service1"));
ChannelFactory<IService1> channelFactory = new ChannelFactory<IService1>(httpEndpoint);
IService1 svc = channelFactory.CreateChannel();
Console.WriteLine(svc.GetData(121));
System.Threading.Thread.Sleep(10000);
}
}
}
井。。。我的问题是:此应用程序有效!!为什么这是一个问题???问题是我在托管服务时在App.config
文件中指定了三个终结点:两个 basicHttp 和一个元数据终结点。好吧,我想解决<endpoint address="/GoInto/Svc"...
端点,我假设这是完整的地址(请注意,我已经指定了一个基址):http://localhost:8081/Service1/GoInto/Svc
.
好吧,不幸的是,在客户端中,我解决了这个端点:http://localhost:8081/Service1
它只是基址......为什么它有效????我想在客户端中指定此地址:
namespace WcfServiceClient {
class Program {
static void Main(string[] args) {
ServiceEndpoint httpEndpoint = new ServiceEndpoint(ContractDescription.GetContract(typeof(IService1)), new BasicHttpBinding(), new EndpointAddress("http://localhost:8081/Service1/GoInto/Svc"));
ChannelFactory<IService1> channelFactory = new ChannelFactory<IService1>(httpEndpoint);
IService1 svc = channelFactory.CreateChannel();
Console.WriteLine(svc.GetData(121));
System.Threading.Thread.Sleep(10000);
}
}
}
但是如果我这样做,就会引发不匹配错误:
带有"收件人"的消息 "http://localhost:8081/Service1/GoInto/Svc" 无法在接收器处处理, 由于地址过滤器不匹配 端点调度程序。 检查 发送方和接收方的 端点地址同意。
为什么不起作用?
址必须在一个位置指定,无论是在 ServiceHost 构造函数上,还是在元素中。如果同时具有这两个位置,WCF 将引发异常,指出同一方案 (HTTP) 有两个基址。
可能发生的情况是,托管项目的 app.config 上的服务名称不匹配,因此不会选取配置(并且您得到的是一个默认终结点,其地址与基址位于同一终结点)。尝试在托管代码上添加 foreach 循环,应会看到服务正在侦听的终结点的地址。
Console.WriteLine("Opening host...");
host.Open();
foreach (ServiceEndpoint endpoint in host.Description.Endpoints)
{
Console.WriteLine("Endpoint:");
Console.WriteLine(" Address: {0}", endpoint.Address.Uri);
Console.WriteLine(" Binding: {0}", endpoint.Binding);
Console.WriteLine(" Contract: {0}", endpoint.Contract.Name);
}
Console.WriteLine("Waiting...");