Запуск службы wcf без App.config не работает

Я создаю простой хост wcf в консольном приложении. Это не работает, и исключение не имеет смысла:/ Исключение выглядит очень странно:

"ContractDescription 'IFooService' не имеет операций; контракт должен иметь хотя бы одну операцию."

потому что вот код, и у меня есть операция:

[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>

EDIT: Небольшая подсказка, как это работает: я не менял службу или контракт, но переместил конфигурацию в 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();
    }

person Viktor    schedule 23.02.2016    source источник
comment
разве методы в вашем интерфейсе IFooService тоже не должны быть общедоступными?   -  person VDN    schedule 23.02.2016
comment
@VDN Нет, элемент интерфейса не может быть частным или общедоступным. это не так   -  person Viktor    schedule 23.02.2016


Ответы (3)


Зачем вам нужно использовать ContractDescription? Я полагаю, он ищет настройки в файле конфигурации. Вы можете сделать следующее (использовать метод AddServiceEndpoint без ContractDescription):

    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

person SashaDu    schedule 23.02.2016
comment
Спасибо! это работает! и спасибо за ссылку, я посмотрю внимательнее. - person Viktor; 23.02.2016

Я считаю, что вам нужно добавить конечную точку в 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/

person chief7    schedule 23.02.2016

Вышеприведенное взято из примера Microsoft:

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>
person John    schedule 28.12.2018