How to publish wcf service metadata when the wcf is self-hosted? - c#

I googled for 2 days and tried almost everything, but I still can't get this stuff working.
I have 2 WCF services. I use self-hosting, not IIS(for some reasons IIS isn't working for me). One is duplex, another is standart. Here are their contracts:
Duplex:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IServiceCallback))]
public interface IClientService
{
[OperationContract(IsOneWay = true)]
void SolveTask(string pipelineName, string data);
[OperationContract(IsOneWay = true)]
void GenerateTask(List<GeneratorMethod> parameters);
[OperationContract]
bool Ping();
}
public interface IServiceCallback
{
[OperationContract(IsOneWay = true)]
void SendResult(SampleAnswer[] answers);
[OperationContract(IsOneWay = true)]
void RequestGeneratorParameters();
[OperationContract(IsOneWay = true)]
void SendGenerationResult(string text);
}
Classic:
[ServiceContract]
public interface IServerManagementService
{
[OperationContract]
[FaultContract(typeof(XmlError))]
[FaultContract(typeof(UnknownError))]
[FaultContract(typeof(InitializationError))]
void InitializeServer();
[OperationContract]
void StartServer();
[OperationContract]
void StopServer();
[OperationContract]
void RestartServer();
}
I have following config:
<configuration>
<services>
<service behaviorConfiguration="Service" name="LinProgWebServer.ClientService">
<endpoint address="net.tcp://localhost:8078/LinProgWebServer/ClientService"
binding="netTcpBinding" bindingConfiguration="netTcpEventBinding"
contract="LinProgWebServer.IClientService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" bindingConfiguration=""
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8731/Design_Time_Addresses/LinProgWebServer/ClientService" />
</baseAddresses>
</host>
</service>
<!--сервис управления сервером-->
<!--<service behaviorConfiguration="Service" name="LinProgWebServer.ServerManagementService">
<endpoint address="net.tcp://localhost:8079/LinProgWebServer/ManagementService"
binding="netTcpBinding" bindingConfiguration="netTcpEventBinding"
contract="LinProgWebServer.IServerManagementService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" bindingConfiguration=""
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/LinProgWebServer/ManagementService" />
</baseAddresses>
</host>
</service>-->
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Service">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
Now i have a big trouble: I CAN find classic service via add service reference and CANNOT find duplex service. I tried netstat and it says that both services are listening on their ports. What am i doing wrong?
Here is exception i get:
There was an error downloading 'http://localhost:8731/Design_Time_Addresses/LinProgWebServer/ClientService/_vti_bin/ListData.svc/$metadata'.
The request failed with HTTP status 405: Method Not Allowed.
Metadata contains a reference that cannot be resolved: 'http://localhost:8731/Design_Time_Addresses/LinProgWebServer/ClientService'.
There was no endpoint listening at http://localhost:8731/Design_Time_Addresses/LinProgWebServer/ClientService that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
The remote server returned an error: (404) Not Found.
If the service is defined in the current solution, try building the solution and adding the service reference again.
I'll be grateful for any help.

Make sure you .svc file has the correct name of the class you added in your Service Reference
if you added a service called 'Foo' it should look like:
<%# ServiceHost Language="C#" Debug="true" Service="Foo" CodeBehind="Foo.svc.cs" %
Also, make sure you have
In your web.config

I'm not sure whether this is going to be usefull. All my configs and services were fine, but i had a mistace in types, which were involved in work of wcf services, i haven't marked one of the types as datacontract. U'm very surprised why service started without erros and showed me such not informative messages. Also, thanks Yuval for reminding about InstanceContextMode attribute.

Add this to the area where you setup you set up your endpoint and reference your service classes:
//config service metadata
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
ServiceMetadataBehavior mb = new ServiceMetadataBehavior();
ServiceHost.Description.Behaviors.Add(mb);
if (bUseSSL) {
mb.HttpsGetEnabled = true;
mb.HttpGetEnabled = false;
ServiceHost.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpsBinding(), "mex");
} else {
mb.HttpsGetEnabled = false;
mb.HttpGetEnabled = true;
ServiceHost.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
}

You should not be using the same URL that you were using to host it in the dev environment. Localhost means nothing outside of the machine, anyway. Use the IP address of the machine and also -- you might have to use netsh to open the port on that machine.

Related

WCF error - Can't get service endpoint up

I started working with WCF recently, and I'm having a problem that I just don't have a clue how to solve.
I start a WCF Service using Service Host, but when I use the URI in a browser it doesn't show the contract of the service, and it gives an exception when I try to connect to it using a ChannelFactory.
I created the project in Visual Studio 2017, and didn't do anything to the config file, excpet changing the base address. Both the service interface and implementation are in the root project "folder", and I've tried disabling the firewall and even my antivirus, but nothing seems to work.
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="TaskExecutor.Exec">
<endpoint address="" binding="basicHttpBinding" contract="TaskExecutor.IExec">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8001/TaskExecutor/Exec/" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
Service interface:
namespace TaskExecutor
{
[ServiceContract]
public interface IExec
{
[OperationContract]
void DoWork();
}
}
Service implementation:
namespace TaskExecutor
{
public class Exec : IExec
{
public void DoWork()
{
Console.WriteLine("Doing work.");
}
}
}
Program launching the service:
using (ServiceHost host = new ServiceHost(typeof(Exec)))
{
host.Open();
Console.WriteLine("exec service started at {0}", host.BaseAddresses[0]);
}
Console.WriteLine("Press any key to end...");
Console.ReadLine();
After launching the program display the message:
exec service started at http://localhost:8001/TaskExecutor/Exec/
Press any key to end...
The service client code is the following:
EndpointAddress endpoint = new EndpointAddress("http://localhost:8001/TaskExecutor/Exec/");
BasicHttpBinding binding = new BasicHttpBinding();
ChannelFactory<IExec> channelFactory = new ChannelFactory<IExec>(binding, endpoint);
IExec proxy = channelFactory.CreateChannel();
proxy.DoWork();
And it gives the exception:
System.ServiceModel.EndpointNotFoundException occurred
HResult=0x80131501
Message=There was no endpoint listening at http://localhost:8001/TaskExecutor/Exec/ that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
Inner Exception 1:
WebException: Unable to connect to the remote server
Inner Exception 2:
SocketException: No connection could be made because the target machine actively refused it
I seriously don't know what to do, and any help would be amazing.
Thank you very much!
You have exposed metadata but didnt bind it to the service.Here's how you have to.
<behaviors>
<serviceBehaviors>
<behavior name="metadadiscovery">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
Now bind the behavior to the service.
<services>
<service name="TaskExecutor.Exec" behaviorConfiguration="metadadiscovery">
<endpoint address="" binding="basicHttpBinding" contract="TaskExecutor.IExec">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8001/TaskExecutor/Exec/" />
</baseAddresses>
</host>
</service>
</services>
Now when you type the address in the browser you should be able to see wsdl.
http://localhost:8001/TaskExecutor/Exec/
So I figured out what was wrong, It was the code starting the service. instead of what I have It should be:
using (ServiceHost host = new ServiceHost(typeof(Exec)))
{
host.Open();
Console.WriteLine("exec service started at {0}", host.BaseAddresses[0]);
Console.WriteLine("Press any key to end...");
Console.ReadLine();
}

Error creating wcf .svc service

I have created following svc service given below-
public class NewsRest : INewsRest
{
public string getHomePageNews1()
{
DataTable dt = new DataTable();
try
{
dt = new ManageNews().getHomePageNews1();
string json = new Utills().dataTableToJsonString(dt);
json = json.Replace("task-photo-846b6edc-3b2e-4ff6-ba10-734d64143c1d.png", "task-photo-8d5feed4-d6a1-4ae9-9a72-387ccfda1dc5.jpg");
return json;
}
catch (Exception ex)
{
return "{}";
}
}
}
[ServiceContract]
public interface INewsRest
{
[OperationContract]
[WebGet(ResponseFormat=WebMessageFormat.Json)]
string getHomePageNews1();
}
and web config configuration is-
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="NewsRestBehavior">
<serviceMetadata httpGetEnabled="true" policyVersion="Policy15" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="UPNews.WebServices.NewsRest" behaviorConfiguration="NewsRestBehavior">
<endpoint address=""
binding="basicHttpBinding"
contract="UPNews.WebServices.INewsRest" />
<endpoint address="mex" binding="mexHttpBinding" name="MetadataEndpoint"
contract="IMetadataExchange" />
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
but when I am testing this service on WCF test client it gives following error.-
Error: Cannot obtain Metadata from http://localhost:57358/WebServices/NewsRest.svc/getHomePageNews1
If this is a Windows (R) Communication Foundation service to which you have access,
please check that you have enabled metadata publishing at the specified address.
For help enabling metadata publishing,
please refer to the MSDN documentation at http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata Exchange Error
URI: http://localhost:57358/WebServices/NewsRest.svc/getHomePageNews1 Metadata contains a reference that cannot be resolved:
'http://localhost:57358/WebServices/NewsRest.svc/getHomePageNews1'. Content Type application/soap+xml;
charset=utf-8 was not supported by service http://localhost:57358/WebServices/NewsRest.svc/getHomePageNews1.
The client and service bindings may be mismatched. The remote server returned an error:
(415) Unsupported Media Type.HTTP GET Error URI: http://localhost:57358/WebServices/NewsRest.svc/getHomePageNews1 There was an error downloading
'http://localhost:57358/WebServices/NewsRest.svc/getHomePageNews1'. The request failed with HTTP status 400: Bad Request.
Please tell whats wrong happening here.
You must add to your server configuration to allow MEX (meta data exchange) so that the client can retrieve the generated WSDL. Something like this:
<service name="UPNews.WebServices.NewsRest" behaviorConfiguration="NewsRestBehavior">
<endpoint address=""
binding="basicHttpBinding"
contract="UPNews.WebServices.INewsRest" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>

invoke WCF service method from web browser

I want to run my service from the web browser: http://localhost:443/TestService//RunTest/data/test
It doesn`t work for me
This page can’t be displayed
•Make sure the web address http://localhost:443 is correct.
•Look for the page with your search engine.
•Refresh the page in a few minutes.
How to solve that - redefine endpoint - how?
The WCF service:
//TestService.svc.cs
public class TestService : ITestService
{
public string RunTest(string data)
{
return string.Format("You entered: {0}", data);
}
}
//ITestService.cs
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json, UriTemplate = "/RunTest/data/{data}")]
string RunTest(string data)
{
return string.Format("You entered: {0}", proxyDomain);
}
//Web.config
<system.serviceModel>
<services>
<!-- This section is optional with the default configuration introduced
in .NET Framework 4.5.1 -->
<service
name="TestService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:443/TestService/"/>
</baseAddresses>
</host>
<endpoint address="http://localhost:443/TestService"
binding="wsHttpBinding"
contract="ITestService" />
</service>
</services>
</system.serviceModel>
Also when I run it a WCF client is opened with port 54388
In my experience, you wouldn't be able to test directly via the browser.
Instead you should use a WCF Test Client:
http://msdn.microsoft.com/en-us/library/bb552364(v=vs.110).aspx
What you can do using your browser, is to see if you can reach the WSDL.
An example of a WSDL call in a browser:
http://localhost:8080/DecisionService/ws/PreTradeChecksRuleApp/1.0/PreTradeChecks/1.0?WSDL
You should add/change the endpoint "binding" attribute to "webHttpBinding" like this:
<endpoint address="http://localhost:443/TestService"
binding="webHttpBinding"
contract="ITestService" behaviorConfiguration="web" />
Or
<endpoint address="http://localhost:443/TestService"
binding="wsHttpBinding"
contract="ITestService" />
<endpoint address="http://localhost:443/TestService/web"
binding="webHttpBinding"
contract="ITestService" behaviorConfiguration="web"/>
In Both Cases you Have to Add:
<behaviors>
...
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
...
</behaviors>
notes:
1) You have to add the attribute behaviorConfiguration to the webBinding and Add the behavior configuration
2) In the second solution, You have to change the name of the baseAddress because you can't have two endpoints configured to the same baseAddress (if anyone knows how to do it, please it would help me too)
Best Regards

Two WCF services, hosted in one console application

I have one console app as a hosting for WCF service. Now, I'm going to add another one WCf service for administer purposes. So, here is my code:
[ServiceContract]
public interface IServiceAdmin
{
[OperationContract]
int GetCount();
}
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
public class ServiceAdmin : IServiceAdmin
{
public int GetCount()
{
// It's just a stub to go on
return 1;
}
}
Here is excerpt of App.config applied to services:
<serviceBehaviors>
<behavior name="MyService.ServBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MyService.ServBehavior" name="MyService.MyServ">
<endpoint address="MyServ" behaviorConfiguration="" binding="netTcpBinding" contract="MyService.IMyServ" isSystemEndpoint="false" />
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
<service behaviorConfiguration="MyService.ServBehavior" name="MyService.MyServAdmin">
<endpoint address="MyServ" behaviorConfiguration="" binding="netTcpBinding" contract="MyService.IServiceAdmin" isSystemEndpoint="false" />
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
And here is how I get services started:
static void Main(string[] args)
{
ServiceHost myserviceHost = new ServiceHost(typeof(MyServ), new Uri("net.tcp://192.168.1.40:8730/"));
myserviceHost.Open();
ServiceHost myAdminHost = new ServiceHost(typeof(AServiceAdmin), new Uri("net.tcp://192.168.1.40:31337/");
myAdminHost.Open();
Console.ReadLine();
}
The issue is that regular service working good (metadata exchanging can provide info on service methods) and another service (which I mentioned at the beginning, administer service) is not working at all.
That is the reason of it?
Thanks in advance!
The issue was in wrong name of service in App.Config. The right line is
<service behaviorConfiguration="MyService.ServBehavior" name="MyService.ServiceAdmin">

WCF multiple named pipe endpoints

I have two services I want to interact with through named pipes. I tried this two ways, both by creating two separate ServiceHosts, and by creating multiple endpoints on a single service. The first service works perfectly whether I have the second service or not. For the second service in both cases, I either get an endpoint not found error due to it not finding the named pipe (separate services) or an address filter problem (which setting to Any does not fix). I've checked and double checked my settings, but I'm stumped.
Both the server and client both use the same assembly that has the contract:
[ServiceContract(CallbackContract = typeof(IServiceCallback1), SessionMode = SessionMode.Required)]
public interface IService1
{
....
}
[ServiceContract]
public interface IService2
{
...
}
Here's the server side:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Reentrant, IncludeExceptionDetailInFaults = true)]
class Service1Impl : IService1
{
...
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, IncludeExceptionDetailInFaults = true)]
class IService2Impl : IService2
{
...
}
...
serviceHost1 = new ServiceHost(typeof(Service1Impl));
serviceHost2 = new ServiceHost(typeof(Service2Impl));
try
{
serviceHost2.Open();
serviceHost1.Open();
}
(Yes, I open them in the opposite order, since the client process assumes that Service2 is available if it can connect to Service1)
Here's my configuration for the services:
<system.serviceModel>
<services>
<service name="Service1Impl" behaviorConfiguration="myServiceBehavior">
<endpoint address="" binding="netNamedPipeBinding" contract="IService1"/>
<host>
<baseAddresses>
<add baseAddress="net.pipe://localhost/Service1"/>
</baseAddresses>
</host>
</service>
<service name="Service2Impl" behaviorConfiguration="myServiceBehavior">
<endpoint address="" binding="netNamedPipeBinding" contract="IService2"/>
<host>
<baseAddresses>
<add baseAddress="net.pipe://localhost/Service2"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="myServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Client-side I don't use configuration and use this for both:
public class Service2Client: ClientBase<IService2>, IService2
{
public Service2Client()
: base(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/Service2"))
{
}
}
Is there something I'm missing here? Like I said, I can connect and make calls on the first service just fine, but the second gets EndpointNotFoundException complaining that it couldn't find the named pipe.

Categories