运行 没有 App.config 的 wcf 服务不工作

Running wcf service without App.config doesn't work

我在控制台应用程序中创建了简单的 wcf 主机。它不起作用,异常使没有意义:/ 异常看起来真的很奇怪:

"ContractDescription 'IFooService' has zero operations; a contract must have at least one operation."

因为,这是代码,我有一个操作:

[ServiceContract]
public interface IFooService
{
    [OperationContract]
    void DoNothing();

    [OperationContract]
    int GetFoo(int i);
}

public class FooService : IFooService
{
    public void DoNothing()
    {
    }

    public int GetFoo(int i)
    {
        return i + 1;
    }
}

class Program
{
    static void Main(string[] args)
    {
        try
        {
            string address = "http://localhost:9003/FooService";
            Uri addressBase = new Uri(address);

            var svcHost = new ServiceHost(typeof(FooService), addressBase);

            BasicHttpBinding bHttp = new BasicHttpBinding();

            Type contractType = typeof(IFooService);
            ContractDescription contractDescription = new ContractDescription(contractType.Name);
            contractDescription.ProtectionLevel = ProtectionLevel.None;
            contractDescription.ContractType = contractType;
            contractDescription.ConfigurationName = contractType.FullName;
            contractDescription.SessionMode = SessionMode.NotAllowed;

            svcHost.AddServiceEndpoint(new ServiceEndpoint(contractDescription, bHttp, new EndpointAddress(address)));

            svcHost.Open();
            Console.WriteLine("\n\nService is Running as >> " + address);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
        Console.ReadKey();
    }
}

这基本上是完整的代码。 App.config 保持不变:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
    </startup>
</configuration>

编辑: 一点线索,它是这样工作的:我没有更改服务或合同,但将配置移动到 App.config,所以只更改了 Main 方法:

App.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
    </startup>
  <system.serviceModel>
    <services>
      <service name="WcfDemos.ConsoleHost.FooService">
        <endpoint address="http://localhost:9003/FooService" binding="basicHttpBinding"
                  contract="WcfDemos.ConsoleHost.IFooService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

主要:

    static void Main(string[] args)
    {
        try
        {
            string address = "http://localhost:9003/FooService";
            Uri addressBase = new Uri(address);

            var svcHost = new ServiceHost(typeof(FooService), addressBase);
            svcHost.Open();

            Console.WriteLine("\n\nService is Running as >> " + address);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
        Console.ReadKey();
    }

为什么需要使用 ContractDescription?我想它会在配置文件中查找设置。 您可以执行以下操作(使用不带 ContractDescription 的 AddServiceEndpoint 方法):

    static void Main(string[] args)
    {
        try
        {
            string address = "http://localhost:9003/FooService";
            Uri addressBase = new Uri(address);

            var svcHost = new ServiceHost(typeof(FooService), addressBase);

             BasicHttpBinding bHttp = new BasicHttpBinding();

            //Type contractType = typeof(IFooService);
            //ContractDescription contractDescription = new ContractDescription(contractType.Name);
            //contractDescription.ProtectionLevel = ProtectionLevel.None;
            //contractDescription.ContractType = contractType;
            //contractDescription.ConfigurationName = contractType.FullName;
            //contractDescription.SessionMode = SessionMode.NotAllowed;
            //svcHost.AddServiceEndpoint(new ServiceEndpoint(contractDescription, bHttp, new EndpointAddress(address)));

            svcHost.AddServiceEndpoint(typeof(IFooService).ToString(), bHttp, address);

            svcHost.Open();
            Console.WriteLine("\n\nService is Running as >> " + address);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
        Console.ReadKey();
    }

顺便说一下,您可以在这里找到一些用于配置 WCF 服务的库,而无需 app.config 文件:WCF NetTcpBinding Bootcamp

我认为如果您不在配置文件中提供端点,则必须将端点添加到 ServiceHost。查看 AddServiceEndpoint 调用:

Uri baseAddr = new Uri("http://localhost:8000/WCFService1");
ServiceHost localHost = new ServiceHost(typeof(CalculatorService), baseAddr);

try
{
localHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "CalculatorService");

ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
localHost.Description.Behaviors.Add(smb);

localHost.Open();
Console.WriteLine("Service initialized.");
Console.WriteLine("Press the ENTER key to terminate service.");
Console.WriteLine();
Console.ReadLine();

localHost.Close();
}
catch (CommunicationException ex)
{
Console.WriteLine("Oops! Exception: {0}", ex.Message);
localHost.Abort();
}

http://www.programminghelp.com/dotnet/wcf-creating-and-implementing-a-service-in-c/

以上来自微软例子:

https://docs.microsoft.com/en-us/dotnet/framework/wcf/how-to-host-and-run-a-basic-wcf-service

这是一个很好的起点。尽管如此......仍然不清楚需要在代码中添加什么才能使下面的app.config内容变得多余:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" />
  </system.web>
  <!-- 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="GettingStartedLib.CalculatorService">
        <host>
          <baseAddresses>
            <add baseAddress = "http://localhost:8000/GettingStarted/CalculatorService" />
          </baseAddresses>
        </host>
        <!-- Service Endpoints -->
        <!-- Unless fully qualified, address is relative to base address supplied above -->
        <endpoint address="" binding="wsHttpBinding" contract="GettingStartedLib.ICalculator">
          <!-- 
              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="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, 
          set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="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>