I am new at WCF. I have created a new WCF service which has one method called SendFax(). It is running on windows service. I want other users to use this method but how? I installed the windows service with installutil.exe and it is running now. I guess my WCF service is listening. How can I reach this service? My windows service code is here:
public partial class WCFWinService : ServiceBase
{
ServiceHost serviceHost;
public WCFWinService()
{
InitializeComponent();
ServiceName = "Digiturk FaxPro WCF";
}
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
serviceHost = new ServiceHost(typeof(FaxPro.WCFWindowsService.WCFWinService));
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
}
WCF Interface code:
[ServiceContract]
public interface IWCFService
{
[OperationContract]
void SendFax(....);
}
WCF Service Code:
public class WCFService : IWCFService
{
public void SendFax(...)
{ ... }
Any suggestions?
App.Config is here
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IWCFService" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8733/Design_Time_Addresses/Digiturk.FaxPro.WcfServiceLibrary/Service1/"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IWCFService"
contract="localhost.IWCFService" name="BasicHttpBinding_IWCFService" />
</client>
</system.serviceModel>
</configuration>
You can connect to this service at the defined address:
http://example.com:8733/Design_Time_Addresses/Digiturk.FaxPro.WcfServiceLibrary/Service1/
It's a SOAP service - so you'll need a SOAP-capable testing tool, like SoapUI or the WCF Test Client (just a browser will not work). You can get the WSDL for the service at the above address by appending ?wsdl to the URL.
Related
I created a WCF service and client in same machine, the services address is wrote into Client's code, so I can easily find the service and create connection to service.
Then I try to deploy them into Intranet. The first problem is: how could Client find the address of server. In actual environment, customers can install service at any computer in Intranet, is there any way to let client find the server address?
WCF service could expose a specific endpoint as a discovery endpoint to all clients so that client could find where the service lies. You could even use UDP multicast to enable the service to be discovered by the client.
You could check the official document.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/wcf-discovery
I have made a demo, wish it is useful to you.
Server.
class Program
{
static void Main(string[] args)
{
using (ServiceHost sh=new ServiceHost(typeof(MyService)))
{
sh.Open();
Console.WriteLine("serivce is ready...");
Console.ReadLine();
sh.Close();
}
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
string SayHello();
}
public class MyService : IService
{
public string SayHello()
{
return "Hello, I am a Clown";
}
}
Server app.config
<system.serviceModel>
<services>
<service name="DiscoveryEndpoint20181024.MyService" behaviorConfiguration="mybehavior">
<endpoint address="http://10.157.18.188:4800" binding="wsHttpBinding" contract="DiscoveryEndpoint20181024.IService"></endpoint>
<endpoint kind="discoveryEndpoint" address="http://localhost:9999" binding="wsHttpBinding"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="mybehavior">
<serviceMetadata />
<serviceDiscovery />
</behavior>
</serviceBehaviors>
</behaviors>
Client.
class Program
{
static void Main(string[] args)
{
DiscoveryClient client = new DiscoveryClient("my_client");
client.ClientCredentials.Windows.ClientCredential.UserName = "administrator";
client.ClientCredentials.Windows.ClientCredential.Password = "abcd1234!";
FindCriteria crit = new FindCriteria(typeof(IService));
FindResponse resp = client.Find(crit);
if (resp != null && resp.Endpoints.Count > 0)
{
EndpointDiscoveryMetadata epaddrMtd = resp.Endpoints[0];
ChannelFactory<IService> factory = new ChannelFactory<IService>(new WSHttpBinding(), epaddrMtd.Address);
factory.Credentials.Windows.ClientCredential.UserName = "administrator";
factory.Credentials.Windows.ClientCredential.Password = "abcd1234!";
IService service = factory.CreateChannel();
var result=service.SayHello();
Console.WriteLine(result);
Console.ReadLine();
}
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
string SayHello();
}
class DemoService : IService
{
public string SayHello()
{
OperationContext context = OperationContext.Current;
return $"the address:{OperationContext.Current.Channel.LocalAddress.Uri}";
}
}
Client.config
<system.serviceModel>
<client>
<endpoint name="my_client" kind="discoveryEndpoint" address="http://10.157.18.188:9999" binding="wsHttpBinding"></endpoint>
</client>
</system.serviceModel>
I am unable to get WCF services to run on a shared server using IIS.
I have tried several tutorials:
http://technologyriver.blogspot.com/2012/02/prerequisites-check-windows-7.html
http://msdn.microsoft.com/en-us/library/ms733766.aspx
I've read blogs about executing command line instructions to enable WCF support on IIS.
However, the hosting company refuses to run the command on their box.
The services work fine on my dev machine.
However, I just cannot get the services to run on the remote server.
When clicking on an svc file I get the following error:
HTTP Error 404.3 - Not Found
The page you are requesting cannot be served because of the extension configuration. If the page is a script, add a handler. If the file should be downloaded, add a MIME map.*
svc file:
<% #ServiceHost Language=C# Debug="true" Service="MyService" Factory="MyServiceHostFactory" CodeBehind="~/App_Code/Service.cs" %>
Web.config:
<service name="MyService" behaviorConfiguration="MyServiceBehavior">
<endpoint contract="IMyService" binding="basicHttpBinding">
<identity>
<dns value="http://www.mydomain.com" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://www.mydomain.com:8732/Services/Service/" />
</baseAddresses>
</host>
</service>
Service.cs:
using System;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
// A WCF service consists of a contract (defined below as IMyService, DataContract1),
// a class which implements that interface (see MyService),
// and configuration entries that specify behaviors associated with
// that implementation (see <system.serviceModel> in web.config)
[ServiceContract()]
public interface IMyService
{
[OperationContract]
string MyOperation1(string myValue1);
[OperationContract]
string MyOperation2(DataContract1 dataContractValue);
}
public class MyService : IMyService
{
public string MyOperation1(string myValue1)
{
return "Hello: " + myValue1;
}
public string MyOperation2(DataContract1 dataContractValue)
{
return "Hello: " + dataContractValue.FirstName;
}
}
[DataContract]
public class DataContract1
{
string firstName;
string lastName;
[DataMember]
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
[DataMember]
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
}
public class MyServiceHostFactory : ServiceHostFactoryBase
{
protected virtual ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
// Specify the exact URL of your web service
Uri webServiceAddress = new Uri("http://www.mydomain.com/MyService.svc");
MyServiceHost webServiceHost = new MyServiceHost(serviceType, webServiceAddress);
return webServiceHost;
}
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
throw new NotImplementedException();
}
}
public class MyServiceHost : ServiceHost
{
public MyServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{ }
protected override void ApplyConfiguration()
{
base.ApplyConfiguration();
}
}
I had to switch hosts.
I was originally using DiscountASP.Net and they refused my request to ensure WCF settings were enabled and told me that I needed to hire a developer or follow the MS IIS specs.
(P.S. They didn't know that I'm actually an SDET.)
As a result, I had to switch to another provider (i.e. Winhost).
Things just work now without me having to do any crazy webconfig alterations or ServiceHostFactory coding crap that the previous host wanted me to do that had no success.
I spent 5 days reopening tickets with their tech support until I finally switched to a hosting company that actually supports WCF Services.
Thanks Winhost for ending this dreadful nightmare!
It seemed to be access/configurability problem on remote server then.
Try checking following areas for the deployed service.
Binding of the WCF service is configured correctly, DNS and port (default is 80)
Authentication Mode of service (Anonymous access should be allowed to browser through WSDL)
Permissions granted to the website (directory and user permissions)
If none of them work, then can you list down the steps you followed when service is deployed?
I have a WCF behavior extension that I would like to add to a WCF client. However, the client is constructed programmatically. The endpoint address may vary, but I know the type. I could add the behavior programmatically or in the config file (preferred), but I need to pass some configuration in the config file only.
I don't want this in Common behaviors (machine.config).
I can add the behavior programmatically
endpoint.Behaviors.Add(new MyCustomBehavior())
But I'd rather do it in config, so I can configure the extension there as well.
Is it possible to declaratively add and configure an endpoint behavior extension to a programmatically constructed endpoint knowing only the the type or interface while leaving the client endpoint to be constructed programmatically?
<system.serviceModel>
<client>
<!-- Created programmatically -->
</client>
<extensions>
<behaviorExtensions>
<add name="MyCustomBehavior" type="namespace.CustomBehaviors", MyAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior name="MyCustomBehavior">
<MyCustomBehavior MyImportantBehaviorParam1="foo" />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
Of course I could put the config in another section, and have my behavior read it there, but I'd rather use the WCF facilities if possible.
To do that you need to create a behavior configuration extension for your endpoint. For more information on how to do that, check https://learn.microsoft.com/en-us/archive/blogs/carlosfigueira/wcf-extensibility-behavior-configuration-extensions.
Update: I see your issue now. There's no direct way to add to an endpoint created via code a behavior declared in configuration. You can still do it, though, but you'll need to use some reflection to access the CreateBehavior method of the behavior configuration extension (the method is protected) to actually create the endpoint behavior to add it to the endpoint created via code. The code below shows how this can be done.
public class StackOverflow_10232385
{
public class MyCustomBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
Console.WriteLine("In {0}.{1}", this.GetType().Name, MethodBase.GetCurrentMethod().Name);
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
Console.WriteLine("In {0}.{1}", this.GetType().Name, MethodBase.GetCurrentMethod().Name);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
Console.WriteLine("In {0}.{1}", this.GetType().Name, MethodBase.GetCurrentMethod().Name);
}
public void Validate(ServiceEndpoint endpoint)
{
Console.WriteLine("In {0}.{1}", this.GetType().Name, MethodBase.GetCurrentMethod().Name);
}
}
public class MyCustomBehaviorExtension : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(MyCustomBehavior); }
}
protected override object CreateBehavior()
{
return new MyCustomBehavior();
}
}
[ServiceContract]
public interface ITest
{
[OperationContract]
string Echo(string text);
}
public class Service : ITest
{
public string Echo(string text)
{
return text;
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
var configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ServiceModelSectionGroup smsg = configuration.GetSectionGroup("system.serviceModel") as ServiceModelSectionGroup;
EndpointBehaviorElement endpointBehaviorElement = smsg.Behaviors.EndpointBehaviors["MyCustomBehavior_10232385"];
foreach (BehaviorExtensionElement behaviorElement in endpointBehaviorElement)
{
MethodInfo createBehaviorMethod = behaviorElement.GetType().GetMethod("CreateBehavior", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Type.EmptyTypes, null);
IEndpointBehavior behavior = createBehaviorMethod.Invoke(behaviorElement, new object[0]) as IEndpointBehavior;
endpoint.Behaviors.Add(behavior);
}
host.Open();
Console.WriteLine("Host opened");
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
ITest proxy = factory.CreateChannel();
Console.WriteLine(proxy.Echo("Hello"));
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
And the configuration for this code:
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="myCustomBehavior_10232385" type="QuickCode1.StackOverflow_10232385+MyCustomBehaviorExtension, QuickCode1"/>
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior name="MyCustomBehavior_10232385">
<myCustomBehavior_10232385/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
My goal is to reach a WCF service behind a firewall with no incoming ports opened.
The solution I chose is to host a duplex WCF service on the public side, that has as callback the same contract that was used if no firewall was involved.
It worked if I used netTcpBinding but since I need streamed communication I had to use the custom binding.
Everything works fine until I raise up the firewall. At that point, the direct call (from behind the firewall out) works fine, but the callback does not (firewall stops it).
The question is WHY? Shoudn't they use the same channel as for the predefined netTcpBinding?
Here is my channels stack in app.config:
<customBinding>
<binding name="ReversedServiceBinding">
<compositeDuplex />
<oneWay />
<binaryMessageEncoding />
<tcpTransport transferMode="Streamed" />
</binding>
</customBinding>
Actual behavior is correct. You have used compositeDuplex binding element - the meaning of composite word is exactly what you get - two separate channels each working for one direction. Composite duplex is needed only for transport channel which doesn't support duplex communication by default. That is not the case for TCP transport channel - check remarks. If you don't use compositeDuplex it should work like you have expected. Also there is no need to define whole new custom binding to allow streamed transport. NetTcpBinding also has TransportMode property which can be specified in configuration.
EDIT:
I have prepared working example with Net.TCP duplex communication. It doesn't use streaming. You are right that streaming is not possible when duplex TCP communication is used. You can try to combine duplex communication with chunking channel or check WCF Xtensions (commercial product).
Shared contracts
namespace NetTcpDuplexContracts
{
[ServiceContract(SessionMode = SessionMode.Required,
CallbackContract = typeof(IDuplexServiceCallback))]
public interface IDuplexService
{
[OperationContract(IsOneWay = true)]
void DoAction(string message);
}
public interface IDuplexServiceCallback
{
[OperationContract(IsOneWay = true)]
void ConfirmAction(string message);
}
}
Service and host
namespace NetTcpDuplexService
{
public class DuplexService : IDuplexService
{
public void DoAction(string message)
{
Console.WriteLine("DoAction: " + message);
var callbackChannel =
OperationContext.Current.GetCallbackChannel<IDuplexServiceCallback>();
callbackChannel.ConfirmAction("Ping back " + message);
}
}
class Program
{
public static void Main(string[] args)
{
try
{
using (var host = new ServiceHost(typeof(DuplexService)))
{
host.Open();
Console.ReadLine();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.ReadLine();
}
}
}
}
Service configuration
<configuration>
<system.serviceModel>
<services>
<service name="NetTcpDuplexService.DuplexService">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8800/NetTcpDuplexService"/>
</baseAddresses>
</host>
<endpoint address="" binding="netTcpBinding" contract="NetTcpDuplexContracts.IDuplexService" />
</service>
</services>
</system.serviceModel>
</configuration>
Callback and client
namespace NetTcpDuplexClient
{
public class DuplexServiceCallback : IDuplexServiceCallback
{
public void ConfirmAction(string message)
{
Console.WriteLine(message);
}
}
class Program
{
public static void Main(string[] args)
{
DuplexChannelFactory<IDuplexService> factory = null;
try
{
var callbackService = new DuplexServiceCallback();
var context = new InstanceContext(callbackService);
factory = new DuplexChannelFactory<IDuplexService>(context, "IDuplexService_NetTcp");
var channel = factory.CreateChannel();
channel.DoAction("Hello world");
factory.Close();
Console.ReadLine();
}
catch (Exception e)
{
if (factory != null && factory.State != CommunicationState.Closed)
{
factory.Abort();
}
Console.WriteLine(e.Message);
Console.ReadLine();
}
}
}
}
Client configration
<configuration>
<system.serviceModel>
<client>
<endpoint name="IDuplexService_NetTcp" address="net.tcp://localhost:8800/NetTcpDuplexService" binding="netTcpBinding"
contract="NetTcpDuplexContracts.IDuplexService" />
</client>
</system.serviceModel>
</configuration>
I am just trying with various WCF(in .Net 3.0) scenarios.
I am using self hosting.
I am getting an exception as "Service 'MyServiceLibrary.NameDecorator' has zero application (non-infrastructure) endpoints. This might be because no configuration file was found for your application, or because no service element matching the service name could be found in the configuration file, or because no endpoints were defined in the service element."
I have a config file as follows (which has an endpoint)
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="Lijo.Samples.NameDecorator"
behaviorConfiguration="WeatherServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8010/ServiceModelSamples/FreeServiceWorld"/>
</baseAddresses>
</host>
<endpoint address=""
binding="wsHttpBinding"
contract="Lijo.Samples.IElementaryService" />
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WeatherServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
And a Host as
using System.ServiceModel;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Runtime.Serialization;
namespace MySelfHostConsoleApp
{
class Program
{
static void Main(string[] args)
{
System.ServiceModel.ServiceHost myHost = new ServiceHost(typeof(MyServiceLibrary.NameDecorator));
myHost.Open();
Console.ReadLine();
}
}
}
My Service is as follows
using System.ServiceModel;
using System.Runtime.Serialization;
namespace MyServiceLibrary
{
[ServiceContract(Namespace = "http://Lijo.Samples")]
public interface IElementaryService
{
[OperationContract]
CompanyLogo GetLogo();
}
public class NameDecorator : IElementaryService
{
public CompanyLogo GetLogo()
{
CircleType cirlce = new CircleType();
CompanyLogo logo = new CompanyLogo(cirlce);
return logo;
}
}
[DataContract]
public abstract class IShape
{
public abstract string SelfExplain();
}
[DataContract(Name = "Circle")]
public class CircleType : IShape
{
public override string SelfExplain()
{
return "I am a Circle";
}
}
[DataContract(Name = "Triangle")]
public class TriangleType : IShape
{
public override string SelfExplain()
{
return "I am a Triangle";
}
}
[DataContract]
[KnownType(typeof(CircleType))]
[KnownType(typeof(TriangleType))]
public class CompanyLogo
{
private IShape m_shapeOfLogo;
[DataMember]
public IShape ShapeOfLogo
{
get
{
return m_shapeOfLogo;
}
set
{
m_shapeOfLogo = value;
}
}
public CompanyLogo(IShape shape)
{
m_shapeOfLogo = shape;
}
}
}
Could you please help me to understand what I am missing here?
Thanks
Lijo
You're self-hosting in a console app - how is your config set up??
Does your MySelfHostConsoleApp project have an app.config file?
Do you have the MySelfHostConsoleApp.exe.config in the same directory as the MySelfHostConsoleApp.exe file?
The error message just really means the config cannot be found and thus cannot be interpreted and used.
UPDATE: the other option is that WCF cannot interpret the config if it's present.
Check this out:
in your .NET code, your service class that implements the service is called MyServiceLibrary.NameDecorator
however, in your config, you call your service:
<service name="Lijo.Samples.NameDecorator"
That's not going to work! You're mixing up the .NET namespaces and the service namespaces here - and the name you need to put in your service-side config is the .NET fully qualified type name (including the .NET namespace - not the service namespace!).
Your service host will look for an entry <service name="MyServiceLibrary.NameDecorator"> based on your code - but it won't find it.
So you need to make sure to sync those two things up - the fully qualified service class name (including namespace and all) MUST match the name="...." attribute in your <service> tag in your config.