I'm just learning how to use WCF and I am trying to write a little HelloWorld program from scratch (both the host and client sides). I've been getting a ProtocolException Unhandled whenever my client tries to use the service, and I can't figure out why. I'm hosting the service using IIS.
Regarding the way I have things set up: I'm doing my best to separate the client, proxy, host, service, and contract as detailed in this video and as outlined in this article. Basically I've got different projects within the solution for each of those.
Here are some different files showing what I'm talking about:
Service
namespace HelloWorld
{
public class HelloWorldService : IHelloWorldService
{
public String GetMessage(String name)
{
return "Hello World from " + name + "!";
}
}
}
Contract
namespace HelloWorld
{
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract]
String GetMessage(String name);
}
}
Proxy
namespace HelloWorld
{
public class Proxy : ClientBase<IHelloWorldService>, IHelloWorldService
{
#region IHelloWorldService Members
public String GetMessage(String name)
{
return Channel.GetMessage(name);
}
#endregion
}
}
Client
namespace Client
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click_1(object sender, EventArgs e)
{
Proxy proxy = new Proxy();
MessageBox.Show(proxy.GetMessage(textBox1.Text));
}
}
}
The client is just a form with a textbox and a button, and it tries to execute GetMessage() using whatever is in the textbox as a parameter. There is another class that actually creates an instance of the form.
Here's my web.config for the website:
Web.config
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="HelloWorld.HelloWorldService" behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address="http://localhost:8002/" binding="basicHttpBinding" contract="HelloWorld.IHelloWorldService"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex"/>
</service>
</services>
</system.serviceModel>
</configuration>
And here's my app.config that goes with the client:
app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:8002/" binding="basicHttpBinding" contract="HelloWorld.IHelloWorldService" />
</client>
</system.serviceModel>
</configuration>
My svc file is very short, just:
HelloWorldService.svc
<%#ServiceHost Service="HelloWorld.HelloWorldService"%>
I know the service is running, because when I navigate to http://localhost:8002/HelloWorldService.svc in my browser I get the screen that says
You have created a service.
To test this service, you will need to create a client and use it to
call the service.
So here's where the snag happens: the service is running using IIS, I start an instance of the client, the window with the textbox and the button come up, I type in some letters, hit the button, and then the program crashes and I get the ProtocolException Unhandled, (405) Method not allowed. The error happens on this line of the Proxy class:
return Channel.GetMessage(name);
I've been trying to figure this out for hours and hours, and I haven't made much progress. If someone could at least point me in the right direction, I would be very appreciative.
Last thing: I want to write the client and proxy from scratch, without using svcutil.exe.
The reason it works when you go to the base address (.svc) is that this is an HTTP GET operation to get the metadata for the service. When you call a method on your service contract, you're doing a POST operation and more than likely you just don't have this feature enabled. Depending on the .NET version you're targeting, it will be one of these highlighted in red.
You have to specify full address for your service in the endpoint tag of Client configuration.
Like this:
<endpoint address="http://localhost:8002/HelloWorldService.svc" binding="basicHttpBinding" contract="HelloWorld.IHelloWorldService" />
Do not forget to add '.svc' extension after your service name in address attribute of endpoint tag. It worked for me. Hope you will get the solution now.
Client config will look like this:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService"/>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:61569/Service1.svc" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService" contract="WcfServiceApp.IService1" name="WSHttpBinding_IService"/>
</client>
Ok, found a solution, although I'm not entirely sure why it works. I guess when you are using Cassini or IIS or whatever to host the website, you're not supposed to specify an address in the endpoint in the web.config file. All I had to do was change it to address="" and it started working properly. Be sure to make sure the port your server is hosting the service on matches the code in your app.config file.
You have to specify full address for your service in the endpoint tag of Client configuration
address="http://localhost:8002/HelloWorldService.svc", where you put same endpoint configurations.
It did work for me while I trapped in hell...
Enabling below two components, worked for me.
Related
So I have some Issue regarding a WCF Service that is hosted in a Managed Windows Service.
Basically what I did is the following:
I created a WCF Service Lib (the WCF Service template ) using a simple test, like this
[ServiceContract]
public interface IExample
{
[OperationContract]
string HelloWorld();
}
public class Example : IExample
{
public string HelloWorld()
{
return "HelloWorld";
}
}
I also created a corresponding app.config which is this
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<!-- This section is optional with the new configuration model introduced in .NET Framework 4. -->
<service name="Peripherie.WCFService" behaviorConfiguration="ServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8067/PeripherieService"/>
</baseAddresses>
</host>
<endpoint address="" binding="wsHttpBinding" contract="Peripherie.WCFService.Interfaces.IExample" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
</configuration>
After that I added a Win Service project (again with the Win Service template) which references the above lib and the other needed libs.
In the Service class i do the basic stuff to create the servicehost
public partial class Service : ServiceBase
{
public ServiceHost serviceHost = null;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
if(serviceHost!=null)
serviceHost.Close();
serviceHost = new ServiceHost(typeof(Service));
serviceHost.Open();
}
protected override void OnStop()
{
if(serviceHost!=null)
{
serviceHost.Close();
serviceHost = null;
}
}
}
I also added the needed Installer for the Service and set the account to localSystem.
The whole project compiles just fine and I am also able to install the service (using the installutil approach) and start it as well. However when ever I try to open the the Service in the browser I get the error that the side could not be loaded, I am also not able to use the WCF Test Client as it tells me that there are is no metadata to be retrieved.
I dont really get why the whole think does not work, as it seems that everything is setup correctly.
So any advice would be nice.
Edit:
After fixing the mistake pointed out by SouthShoreAK I also found an error in the config, where this:
<service name="Peripherie.WCFService" behaviorConfiguration="ServiceBehavior">
should have been this:
<service name="Peripherie.WCFService.Services.Example" behaviorConfiguration="ServiceBehavior">
Now I get the error that the url could not be registered,
System.ServiceModel.AddressAccessDeniedException: HTTP konnte URL "http://+:8067/PeripherieService/" nicht registrieren. Der Prozess weist keine Zugriffsrechte für diesen Namespace auf
I already tried the tool described HERE however that did not solve the error. Still can start the Service because of the error.
Edit:
Okay that issue was resolved as well, I have the service process installer still set to networkService. After setting it to local system I can start the service now.
but still I get an error 400 now when calling the url via IE.
Final Edit:
Okay now it works, last error was because of a missing / at the end of the base address. So it should have been
<add baseAddress="http://localhost:8067/PeripherieService/"/>
And since SouthShoreAK pretty much pointed me towards the mistakes I made in my config I will accept his answer, because it got me on track.
Your contract should be IExample, not IMain
<endpoint name="ServiceHttpEndpoint" address="http://localhost:8067/PeripherieService" binding="wsHttpBinding" contract="Peripherie.WCFService.Interfaces.IMain" />
Should be changed to:
<endpoint name="ServiceHttpEndpoint" address="http://localhost:8067/PeripherieService" binding="wsHttpBinding" contract="Peripherie.WCFService.Interfaces.IExample" />
Also, this:
serviceHost = new ServiceHost(typeof(Service));
Should be this:
serviceHost = new ServiceHost(typeof(Example));
You're trying to register and instance of your Windows service in the service host. You should be registering your WCF service.
Sometimes I've found that your windows service will start and run even when the Service Host encounters an error. You may want to check your Windows Event Log (just type "Event Viewer" in the start menu) to see if anything went wrong.
I'm just learning how to use WCF and I am trying to write a little HelloWorld program from scratch (both the host and client sides). I've been getting a ProtocolException Unhandled whenever my client tries to use the service, and I can't figure out why. I'm hosting the service using IIS.
Regarding the way I have things set up: I'm doing my best to separate the client, proxy, host, service, and contract as detailed in this video and as outlined in this article. Basically I've got different projects within the solution for each of those.
Here are some different files showing what I'm talking about:
Service
namespace HelloWorld
{
public class HelloWorldService : IHelloWorldService
{
public String GetMessage(String name)
{
return "Hello World from " + name + "!";
}
}
}
Contract
namespace HelloWorld
{
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract]
String GetMessage(String name);
}
}
Proxy
namespace HelloWorld
{
public class Proxy : ClientBase<IHelloWorldService>, IHelloWorldService
{
#region IHelloWorldService Members
public String GetMessage(String name)
{
return Channel.GetMessage(name);
}
#endregion
}
}
Client
namespace Client
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click_1(object sender, EventArgs e)
{
Proxy proxy = new Proxy();
MessageBox.Show(proxy.GetMessage(textBox1.Text));
}
}
}
The client is just a form with a textbox and a button, and it tries to execute GetMessage() using whatever is in the textbox as a parameter. There is another class that actually creates an instance of the form.
Here's my web.config for the website:
Web.config
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="HelloWorld.HelloWorldService" behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address="http://localhost:8002/" binding="basicHttpBinding" contract="HelloWorld.IHelloWorldService"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex"/>
</service>
</services>
</system.serviceModel>
</configuration>
And here's my app.config that goes with the client:
app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:8002/" binding="basicHttpBinding" contract="HelloWorld.IHelloWorldService" />
</client>
</system.serviceModel>
</configuration>
My svc file is very short, just:
HelloWorldService.svc
<%#ServiceHost Service="HelloWorld.HelloWorldService"%>
I know the service is running, because when I navigate to http://localhost:8002/HelloWorldService.svc in my browser I get the screen that says
You have created a service.
To test this service, you will need to create a client and use it to
call the service.
So here's where the snag happens: the service is running using IIS, I start an instance of the client, the window with the textbox and the button come up, I type in some letters, hit the button, and then the program crashes and I get the ProtocolException Unhandled, (405) Method not allowed. The error happens on this line of the Proxy class:
return Channel.GetMessage(name);
I've been trying to figure this out for hours and hours, and I haven't made much progress. If someone could at least point me in the right direction, I would be very appreciative.
Last thing: I want to write the client and proxy from scratch, without using svcutil.exe.
The reason it works when you go to the base address (.svc) is that this is an HTTP GET operation to get the metadata for the service. When you call a method on your service contract, you're doing a POST operation and more than likely you just don't have this feature enabled. Depending on the .NET version you're targeting, it will be one of these highlighted in red.
You have to specify full address for your service in the endpoint tag of Client configuration.
Like this:
<endpoint address="http://localhost:8002/HelloWorldService.svc" binding="basicHttpBinding" contract="HelloWorld.IHelloWorldService" />
Do not forget to add '.svc' extension after your service name in address attribute of endpoint tag. It worked for me. Hope you will get the solution now.
Client config will look like this:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService"/>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:61569/Service1.svc" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService" contract="WcfServiceApp.IService1" name="WSHttpBinding_IService"/>
</client>
Ok, found a solution, although I'm not entirely sure why it works. I guess when you are using Cassini or IIS or whatever to host the website, you're not supposed to specify an address in the endpoint in the web.config file. All I had to do was change it to address="" and it started working properly. Be sure to make sure the port your server is hosting the service on matches the code in your app.config file.
You have to specify full address for your service in the endpoint tag of Client configuration
address="http://localhost:8002/HelloWorldService.svc", where you put same endpoint configurations.
It did work for me while I trapped in hell...
Enabling below two components, worked for me.
I have a simple web service. This is consumed in a website using VS 2010. I added the service reference using “Add Service Reference” option in VS 2010. It works fine. It prints the service address as http://localhost:3187/Service1.svc/MyFolder. But when I type this service address in a browser it says HTTP Error 400.
Note: When I replace the address="MyFolder" with address="" in service’s end point, http://localhost:3187/Service1.svc shows the result.
What is the correct address that I should type in the browser to get the service with “MyFolder” in address?
The page:
namespace ClientWebApp
{
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Service1Client myClientService = new Service1Client();
Response.Write(myClientService.Endpoint.Address);
string result = myClientService.GetData(7);
lblName.Text = result;
}
}
}
The contract:
namespace MyWCFServiceApplication
{
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
public class MyService : IService1
{
public string GetData(int value)
{
return string.Format("Now entered: {0}", value);
}
}
}
The configuration:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="MyWCFServiceApplication.MyService"
behaviorConfiguration="WeatherServiceBehavior">
<endpoint address="MyFolder"
binding="wsHttpBinding"
contract="MyWCFServiceApplication.IService1" />
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WeatherServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Please take a look at the answer to this question: WCF Endpoints & Binding Configuration Issues
Quote:
When hosting a WCF service in IIS, the base address of the service is formed using the following format:
{protocol}://{host}:{port}/{applicationName}/{svcFileName}. This is
the address you can browse to get the WCF help page and/or the
metadata (on a default configuration).
To form the actual address of the endpoint (the one your client needs
to use), the following format is used:
{serviceBaseAddress}/{endpointAddress}
In your case the {endpointAddress} is MyFolder which explains why you're able to add service reference using http://localhost:3187/Service1.svc/MyFolder address. However this is not the address where your help page and metadata info gets rendered so the fact that you get HTTP Error 400 on http://.../*.svc/MyFolder is no surprise.
try adding "?wsdl" to the end of the url you are trying with.
I am having some trouble hosting a WCF service inside a Windows Service.
I can start my WCF service in VS2008 and by navigating to the base address in my app.config
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service behaviorConfiguration="WCF.IndexerBehavior"
name="WCF.Indexer">
<endpoint address="" binding="wsHttpBinding" contract="WCF.IIndexer">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost/WCFService/Action/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCF.IndexerBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
I can see it works fine, I get the page saying I created a service and code samples on how to use it are shown.
Now my next step was to create a Windows Service to host my WCF shown above.
I just used te windows service template, it gave me a Program.cs and Service1.cs which I renamed to WindowsServiceHost.cs. In it I have:
private ServiceHost host;
public WindowsServiceHost()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
var serviceType = typeof(Indexer.WCF.Indexer);
host = new ServiceHost(serviceType);
host.Open();
}
catch (Exception ex)
{
}
}
protected override void OnStop()
{
if (host != null)
{
host.Close();
}
}
Everything compiles fine, I can run InstallUtil (I defined an installer).
The service used to start and stop immediately but disabling Windows Defender got rid of this.
Now the service starts (As a network service) and stays up (I think), but when I navigate to the base address, I get the not found page.
Another weird thing is when I try to stop the service (which is still displayed as running) I get:
Error 1061: The service cannot accept control messages at this time
I've tried everything but am at a loss.
Not 100% sure what the reason really is - just to confirm, we self-host WCF services in Windows services all the time and it generally works perfectly fine.
Two points you could try - just to get a feeling for the behavior and a potential clue for the problem:
1) I notice you open the ServiceHost with just the type of the service - that works, but you might still want to add a base address even to the call of the new ServiceHost() - like this:
host = new ServiceHost(serviceType,
new Uri("http://localhost:8181/WCFService/Action/");
Can you navigate to that address and get the service page??
2) The other thing I noticed is that your service seems to be called Indexer.WCF.Indexer as specified in the typeof() before opening the host, but in the config file, the name= on the <service> tag is only "WCF.Indexer".
Could you possibly try to change that tag to read:
<service behaviorConfiguration="WCF.IndexerBehavior"
name="Indexer.WCF.Indexer">
Does that help? Are you now able to see the service page when navigating to it in the browser?
Marc
Self-hosting HTTP in a Windows service may require registering the endpoint with HttpCfg.exe. Take a look here.
Try removing the catch statement, there may be an error that you are not seeing
I am trying to get my svc file working under IIS. In my project, when I press F5 I got the svc working. So I know everything is okay, right? Except for IIS.
I am working on a Windows XP Pro machine and in IIS I've added a virtual directory.
Here's my code:
IcarePlanActions (project: A)
namespace WcfServiceLibrary
{
[ServiceContract]
public interface ICarePlanActions
{
[OperationContract]
List<string> GetAllClients();
}
}
Client: (project: A)
namespace WcfServiceLibrary
{
public class Client : ICarePlanActions
{
public List<string> GetAllClients()
{
List<string> clients = new List<string>();
clients.Add("Hendrik de Jong");
clients.Add("Miep de Berg");
clients.Add("Jaap Jongeneel");
clients.Add("Joop Prakman");
clients.Add("Pieter Schaakman");
return clients;
}
}
}
Web.config (project: B)
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="CarePlanService.Service1Behavior"
name="WcfServiceLibrary.Client">
<endpoint address="" binding="wsHttpBinding" contract="WcfServiceLibrary.ICarePlanActions">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="CarePlanService.Service1Behavior">
<!-- 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="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
CarePlan.svc
<%# ServiceHost Language="C#" Debug="true" Service="WcfServiceLibrary.Client" %>
When I run this service (which is on IIS) with wfctestclient I get this error
Error: Cannot obtain Metadata from
http://localhost/CarePlanService/CarePlan.svc
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.
What am I doing wrong?
SOLUTION
I didn't get the service working under IIS. First I manually create a virtual directory and pointed to the directiry where the svc is located. This didn't work. I don't know why.
Then I went to Visual Studio and changed the server setting (Right mouse on the project, properties, tab Web, click Use local IIS Web Server and click Create Virtual Directory. When I did this, it worked under IIS with the code above.
First, remove the [DataContract] attribute in Client.
Then, recompile and make sure that you have the WcfServiceLibrary.dll in the /bin directory for your virtual directory.
Your config should use this endpoint for metadataexchange:
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
SOLUTION
I didn't get the service working under IIS. First I manually create a virtual directory and pointed to the directiry where the svc is located. This didn't work. I don't know why.
Then I went to Visual Studio and changed the server setting (Right mouse on the project, properties, tab Web, click Use local IIS Web Server and click Create Virtual Directory. When I did this, it worked under IIS with the code above.
You reference the data contract as the implementation of the service. That's invalid.
[DataContract]
public class Client : ICarePlanActions
{
<service behaviorConfiguration="CarePlanService.Service1Behavior"
name="WcfServiceLibrary.Client">
Change this to reference the implementation of your service! What does the implementation of your service look like?
Maybe you should just remove the DataContract attribute from the Client class. Also this is not your "Client", it is the implementation of the service.
Run "\%windir%\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\ServiceModelReg.exe" -i
Remove Virtual Directory and create it again.
Just check the service name in Service.svc file
<ServiceHost Language="C#" Debug="true" Service="SvcCalculator.**Calculator**"
CodeBehind="**Calculator.svc.cs**" %>
Hope it'll work.
Ensure that your service namespace, and service class names correspond to the App.config file.
<system.serviceModel>
<services>
<service name="WcfCustomLibrary.Service1">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary/Service1/" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
namespace WcfCustomLibrary
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
public class Service1 : IService1
{