Configure WCF kind="webHttpEndpoint" via code - wcf

I have a WCF service, which implements interface PosData.ISampleService in class PosData.SampleService. The service is self hosted and the start up code looks like this:
ServiceHost serviceHost = new ServiceHost(typeof(SampleService), new Uri("http://localhost:8080/sample"));
serviceHost.Open();
Console.WriteLine("Service started.");
Console.ReadLine();
The app.config contains the following lines:
<services>
<service name="PosData.SampleService">
<endpoint address="http://localhost:8080/sample" contract="PosData.ISampleService" kind="webHttpEndpoint"/>
</service>
</services>
I would like to get rid of the App.config configuration, but I have no idea how to configure webHttpEndpoint via code. How can I do that?

Use WebServiceHost instead of ServiceHost.

Related

WCF Exception : ServiceHost only supports class service types -- when run from windows service

i am new in wcf. i am facing this error ServiceHost only supports class service types.
here i will say i am doing & running my win service & wcf together.
i added windows service project and also add few reference like System.ServiceModel for wcf in win service project. when i am trying to run wcf service from win service then i am getting error called ServiceHost only supports class service types
i search & got many answer like
ServiceHost host = new ServiceHost(
typeof(subservice.ISubService), new Uri("someuri"));
If this is your usage, change it to use the implemented service class type of ISubService
ServiceHost host = new ServiceHost(
typeof(subservice.SubService), new Uri("someuri"));
If configuring the service in .svc then:
<%#ServiceHost Service="subservice.SubService"%>
Also in you config file, change service name to the service instead of the service contract as:
<services>
<service name="subservice.SubService">
...
other search result also said very similar things to get rid of this problem.
i have no svc file for my wcf service. i have just one file where i have contract and service classes. i also have config file.
here i am giving the brief of my service code
namespace SageDataImportWCF
{
[ServiceContract]
public interface ISagePart
{
[OperationContract]
string SageInsertionProcess(string SQLConnectionString, string CountryCode);
// TODO: Add your service operations here
}
public class SagePartInsertion : ISagePart
{
public string SageInsertionProcess(string SQLConnectionString, string CountryCode)
{
}
}
}
here i am giving the code by which i am trying to run from win service
namespace SageDataImportWCF
{
public partial class SageDateInsertionService : ServiceBase
{
#region Local Variables
ServiceHost serviceHost;
#endregion
#region Constructor
public SageDateInsertionService()
{
InitializeComponent();
serviceHost = null;
ServiceName = "Sage DataInsertion Service";
}
#endregion
protected override void OnStart(string[] args)
{
string strAdrHTTP = "http://192.168.6.2:11000/SagePartInsertion";
if (serviceHost != null)
{
serviceHost.Close();
}
serviceHost = new ServiceHost(typeof(SageDataImportWCF.SagePartInsertion));
serviceHost.AddServiceEndpoint(typeof(SageDataImportWCF.ISagePart), new BasicHttpBinding(), strAdrHTTP);
ServiceMetadataBehavior behaviour = new ServiceMetadataBehavior();
behaviour.HttpGetEnabled = true;
serviceHost.Description.Behaviors.Add(behaviour);
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
}
}
here is my config entry for wcf service
<configuration>
<system.serviceModel>
<services>
<service name="SageDataImportWCF.SagePartInsertion" behaviorConfiguration="SageBehavior">
<endpoint address="http://localhost:9001/SagePartInsertion" contract="SageDataImportWCF.ISagePart" binding="basicHttpBinding"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="SageBehavior">
<!-- 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="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
here i have pasted all the relevant code and i like to request some one please have a look at my code and tell me why i am getting the error message like ServiceHost only supports class service types when try to run it from windows service. did i miss anything in code ?
should i have a separate project for wcf class library and another separate project for windows service because i have one project there i have files for wcf & windows service both.
so looking for suggestion like what i need to rectify in code as a result win service can start the wcf service. please help.
Check the definition of the service in the Markup:
Right click on the SagePartInsertion.svc file and select "View Markup".
Make sure the service is the implementation of the interface, like this:
<%# ServiceHost Language="C#" Debug="true" Service="SageDataImportWCF.SagePartInsertion" CodeBehind="SagePartInsertion.svc.cs" %>
In the past it failed because I was referencing the interface.

connect programmatically to a WCF service through HTTPS

I am working on a project that uses WCF service. I have built the service, configured the web.config file, deployed it on a IIS 7 server. The service is accesed through HTTPS (on my dev machine, i have self-created the certificate).
Everything is fine when a create the ServiceReference in Visual Studio 2010, it creates the client and it works fine.
What i need is to create a client programatically (need a little flexibility), so when i try to connect "manually", it gives me a error like this:
The provided URI scheme 'https' is invalid; expected 'http'.
Parameter name: via
The code for web.config is: (i hope there is nothing wrong in it)
<system.serviceModel>
<services>
<service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="TransportSecurity" contract="WcfService1.IService1" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WcfService1.Service1Behavior">
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
The procedure i wrote to access the WCF service is:
void proc()
{
string ADRESASSL = "https://localhost/ServiciuSSLwsBind/Service1.svc";
WSHttpBinding bind= new WSHttpBinding();
EndpointAddress ea = new EndpointAddress(ADRESASSL);
var myChannelFactory = new ChannelFactory<IService1>(bind, ea);
IService1 client = null;
try
{
client = myChannelFactory.CreateChannel();
client.RunMethod1();
client.Close();
//((ICommunicationObject)client).Close();
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
if (client != null)
client.Close();
}
}
The code for IService1
[ServiceContract]
public interface IService1 : IClientChannel
{
[OperationContract]
int RunMethod1();
//....................................
}
It seems i am doing something wrong here, the procedure raises the Exception i mentioned. Something more i must do to work, but i didn't figured it out.
Thanks in advance for any advice you can give me.
I haven't tested this, but I believe you need to set the security mode for the binding before you create the factory. The default mode for security for WSHttpBinding is SecurityMode.Message, and you want SecurityMode.Transport.
You can resolve this one of three ways, as follows.
First, you can use the overloaded version of the WSHttpBinding constructor to specify the security mode, like this:
WSHttpBinding bind= new WSHttpBinding(SecurityMode.Transport);
bind.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
Secondly, you can use the parameterless constructor and specify the security mode (and the client credential type) like this:
WSHttpBinding bind= new WSHttpBinding();
bind.Security.Mode = SecurityMode.Transport;
bind.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
Third, you can place a binding configuration section in the client config and reference that section in the constructor, like this:
WSHttpBinding bind = new WSHttpBinding("TransportSecurity");
The third example assumes a wsHttpBinding section with the name "TransportSecurity" in the client config file.
For more information, check these MSDN articles:
How to: Set the Security Mode
WSHttpBinding Constructor
Well, solved the problem with the self created certificate.
I have changed the endpoint adress for both the programatically connection and the service reference in Viosual Studio 2010.
string ADRESASSL = "https://localhost/ServiciuSSLwsBind/Service1.svc";
now is
string ADRESASSL = "https://eu-pc/ServiciuSSLwsBind/Service1.svc";
I have changed the adress from localhost to the name of pc "eu-pc". It has to do with the domain the certificate was issued.
Using localhost or 127.0.0.1 worked only for one method or the other.
Hope this will help other guys who might run into this.

Not getting the expected results from WCF REST Service (Newbie)

I'm new to WCF Web Services. I'm trying to test my simple hello world web service.
For now, I'm doing self hosting. I'm at the point where I've started the host application, opened my browser and typed in the address to my resource. I've also run Fiddler and created a Request by using the Composer. In both cases, I get the "You have created a service." page that has a link to my .wsdl.
I was expecting to see the "Hello World" text in my Response or a web page that has "...Hello world".
What am I missing? or am I just misunderstanding the process?
App.Config
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="My.Core.Services.GreetingService" behaviorConfiguration="MyServiceTypeBehaviors">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/greeting"/>
</baseAddresses>
</host>
<endpoint name="GreetingService" binding="webHttpBinding" contract="My.Core.Services.IGreetingService"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors" >
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
Host code
using System;
using System.ServiceModel;
using My.Core.Services;
namespace My.Service.Host
{
class Program
{
static void Main(string[] args)
{
using (var host = new ServiceHost(typeof(GreetingService)))
{
host.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
host.Close();
}
}
}
}
Hello World Contract and Service
using System.ServiceModel;
using System.ServiceModel.Web;
namespace My.Core.Services
{
[ServiceContract]
public interface IGreetingService
{
[OperationContract]
[WebGet(UriTemplate = "/")]
string GetGreeting();
}
}
using System.Collections.Generic;
namespace My.Core.Services
{
public class GreetingService : IGreetingService
{
public string GetGreeting()
{
return "Greeting...Hello World";
}
}
}
If I understand you correctly, you can see your wsdl link at the following url
http://localhost:8080/greeting
In order to now call your endpoint, you need to add it to the url like this
http://localhost:8080/greeting/GetGreeting/
I'm not entirely sure why you have the UriTemplate thing in there though other than my guessing that you probably just copy pasted it from an example. Unless you have specific query string parameters that you want defined, you don't really need it and it kind of tends to complicate things so I'd recommend taking it out. That means your Interface would look something like this...
[ServiceContract]
public interface IGreetingService
{
[OperationContract]
[WebGet]
string GetGreeting();
}
...and you can then lose the final "/" on the url.
I figure out the problem. When I use the url: "http://localhost:8080/greeting" the server sends the temp page. When I add the backslash "/" on the end of the url it execute my service.
so, "http://localhost:8080/greeting/" works and sends me the "...Hello World" back.

Edit System.Servicemodel values programmatically?

When using WCF, there is a section in the web.config as below.
<system.serviceModel>
<services>
<service name="abc">
<endpoint /> <---this
</service>
</services>
</system.serviceModel>
Is it possible to edit the area I've marked programmatically?
I can see there is a sytem.serviceModel namespace, but other than that I'm a bit lost.
If you want to change these parameters at runtime you can override ServiceHost.OnOpening()
E.g. to change port:
protected override void OnOpening()
{
foreach (ServiceEndpoint endpoint in Description.Endpoints)
{
string uriString = string.Format("{0}://{1}:{2}{3}",
endpoint.Address.Uri.Scheme,
endpoint.Address.Uri.Host,
endpoint.Address.Uri.Port + _basePort,
endpoint.Address.Uri.LocalPath);
endpoint.Address = new EndpointAddress(uriString);
}
base.OnOpening();
}
To complement Mike Mozhaev's answer, since your service is hosted in IIS you'll need a ServiceHostFactory to get a reference to the service host (or to use your own host). There's some information about it at http://blogs.msdn.com/b/carlosfigueira/archive/2011/06/14/wcf-extensibility-servicehostfactory.aspx.

Accessing self hosted WCF service from Silverlight 4

I have a self hosted WCF 4 service, catering the same contract via basicHttpBinding for Silverlight 4 clients and wsHttpBinding for the others. The code is very short and simple and provided here.
I get the following error when trying to access the a service method from WCF:
Message=An error occurred while trying to make a request to URI
http://localhost:8008/WCF4Silverlight.MyService/SL. This could be
due to attempting to access a service in a cross-domain way without a
proper cross-domain policy in place, or a policy that is unsuitable
for SOAP services. You may need to contact the owner of the service to
publish a cross-domain policy file and to ensure it allows
SOAP-related HTTP headers to be sent. This error may also be caused by
using internal types in the web service proxy without using the
InternalsVisibleToAttribute attribute. Please see the inner exception
for more details.
I do have the method, GetClientAccessPolicy() serving the cross-domain policy using WebGet attribute, and I am kind of sure that there is a problem with it getting exposed properly. Your insight into the problem will be highly appreciated. If I type http://localhost:8008/WCF4Silverlight.MyService/clientaccesspolicy.xml in the browser, I do get the xml for the same, but the call from Silverlight always fails with the above error.
Here is the code for the WCF service:
namespace WCF4Silverlight
{
[ServiceContract(SessionMode = SessionMode.NotAllowed)]
public interface IClientAccessPolicy
{
[OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
Stream GetClientAccessPolicy();
}
}
namespace WCF4Silverlight
{
public class MyService: IMyService, IClientAccessPolicy
{
public Stream GetClientAccessPolicy()
{
const string result = #"<?xml version=""1.0"" encoding=""utf-8""?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers=""*"">
<domain uri=""*""/>
</allow-from>
<grant-to>
<resource path=""/"" include-subpaths=""true""/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>";
if (WebOperationContext.Current != null)
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml"; return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
}
//Other service methods....
}
Here is code that publishes the service:
class Program
{
static void Main(string[] args)
{
ServiceHost myServiceHost = new ServiceHost(typeof(MyService));
myServiceHost.Open();
//Wait for client action.
myServiceHost.Close();
}
}
Here is the app.config for the WCF service host:
<service name="WCF4Silverlight.MyService" behaviorConfiguration="MyServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8008/MyService/"/>
</baseAddresses>
</host>
<endpoint address="general" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IMyService" contract="WCF4Silverlight.IMyService"/>
<endpoint address="SL" binding="basicHttpBinding" bindingConfiguration="basicHttpBinding_IMyService" contract="WCF4Silverlight.IMyService"/>
<endpoint address="" binding="webHttpBinding" bindingConfiguration="webHttpBinding_IMyService" behaviorConfiguration="webHttpBehavior" contract="WCF4Silverlight.IClientAccessPolicy" />
</service>
And here is the ServiceReferences.ClientConfig for the Silverlight client:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMyService" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
<customBinding>
<binding name="WSHttpBinding_IMyService">
<textMessageEncoding messageVersion="Default" writeEncoding="utf-8" />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://localhost:8008/MyService/SL"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyService"
contract="myWCFService.IMyService" name="BasicHttpBinding_IMyService" />
</client>
</system.serviceModel>
This is what I did to resolve the issue:
1) Used Fiddler to see where the WCF calls were directed. Fiddler told that the calls were failing to HOST - http:/localhost:8008 and URL - /clientaccesspolicy.xml.
2) Created a different class ClientAccessPolicy implementing IClientAccessPolicy (with WebGet for /clientaccesspolicy.xml).
3) Added another section in app.config of the host for a new service hosting the Clientaccesspolicy class. This one had its base address as http:/localhost:8008/
<service name="WCF4Silverlight.ClientAccessPolicy" behaviorConfiguration="ClientAccessPolicyBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8008/"/>
</baseAddresses>
</host>
<endpoint address="" binding="webHttpBinding" bindingConfiguration="webHttpBinding_IMyService" behaviorConfiguration="webHttpBehavior" contract="WCF4Silverlight.IClientAccessPolicy" />
</service>
4) In the hosting code, created another instance of ServiceHost and launched the new service with Clientaccesspolicy
ServiceHost clientAccessPolicyHost = new ServiceHost(typeof(ClientAccessPolicy)); clientAccessPolicyHost.Open();
5) In the Silverlight client, deleted the existing reference to the WCF and added the one to the newly hosted service.
The WCF calls from Silverlight are now going through.
Self hosted services on machines without IIS where the clientaccesspolicy can't be served up from the root, can instead use this method to dynamically serve up the policy on Port 80:
http://blogs.msdn.com/b/carlosfigueira/archive/2010/07/25/enabling-cross-domain-calls-for-sl-apps-on-self-hosted-tcp-services.aspx
The easiest way to debug this kind of issues is by using Fiddler (www.fiddler2.com) to intercept the HTTP traffic. You'll immediately see if clientAccessPolicy.xml is requested, where it is expected to be, and what is the result.
If you get a 404 (resource not found) the file is not at the expected location (but your webGet annotation looks good to me), otherwise the issue is within the xml itself.
This is a very permissive clientAccessPolicy.xml that I usually use for development/testing purposes:
<?xml version="1.0" ?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>
If you're using a self-hosted web service, you need to throw your ClientAccessPolicy.xml into the root of a website that can be reached on port 80 of your machine (e.g., http://localhost:80/ClientAccessPolicy.xml). This was new in Silverlight 4, and unfortunately, I haven't found it clearly explained in the MS docs. (It's mentioned, but it's not terribly clear.)