I've been reading up on how to do this but I'm having a hard time getting my head around it.
Synchronous and Asynchronous Operations
WCF: Working with One-Way Calls, Callbacks, An...
My goal is to return results from multiple functions in a Silverlight enabled WCF service as they are discovered.
A general overview of how this service is desired to work is as follows.
User enters a url that has many large csv files listed in hyperlinks. The service gets the initial user entered url, makes a web request of that url, gets the csv file names using regex, service downloads the csv files to server, files are converted to a different format.
Currently all of that works, but no response is shown until the entire operation is done. I would like to provide feedback during each function.
I'm using VB for this app but am fluent in C# if anyone has a code suggestion.
<ServiceContract(Namespace:="http://somemadeupurl")>
<SilverLightFaultBehavior()>
<AspNetCompatibilityRequirements(RequirementsMode:=
AspNetCompatibilityRequirementsMode.Allowed)>
Public Class GetCSV
<OperationContract()>
Public Function ProcessInitialLink(ByVal strInitialLink As String)
'download the source html
'do a webrequest and extract csv links
'since dates are in the filenames I would like to send back most
'recent to user here
Dim strMostRecentCSV As String=SomeRegexMatch
> 'problem here. Would like to return strMostRecentCSV and keep processing
GetAndConvertBigCSV(strMostRecentCSV)
Return strMostRecentCSV
End Function
'actually a list but for brevity..
Private Function GetAndConvertBigCSV(ByVal strMostRecentCSV as string)
'do a bunch of downloading
'call a function to do a bunch of converting
'call a function to clean up files
End Function
End Class
If it's done like this it will return strMostRecentCSV but has to wait until GetAndConvertBigCSV is done before returning.
I've tried spawning GetAndConvertBigCSV as a new thread and it works but returns nothing that I can bind to the Silverlight client (e.Result)
At a minimum I would like to provide feedback of the first function Return then have the service continue.
Thanks a million for help.
I think that what you probably want is a "polling duplex http service" - what this means is that WCF will fake up a duplex style service for you (by polling). The advantage of a duplex service over a regular asynchronous service is that it is easy to call back to the client multiple times (so you can provide feedback on the progress of your task).
It is very easy to implement. Let's say you have two projects a web application and a silverlight application...
Web Application
Create your service, for example:
[ServiceContract(CallbackContract = typeof(ICallback))]
public interface ILongRunningService
{
[OperationContract]
void StartLongRunningProcess(string initialParameter);
}
[ServiceContract]
public interface ICallback
{
[OperationContract(IsOneWay = true)]
void Update(string someStateInfo);
}
public class LongRunningService : ILongRunningService
{
public void StartLongRunningProcess(string initialParameter)
{
// Get hold of the callback channel and call it once a second
// five times - you can do anything here - create a thread,
// start a timer, whatever, you just need to get the callback
// channel so that you have some way of contacting the client
// when you want to update it
var callback = OperationContext
.Current
.GetCallbackChannel<ICallback>();
ThreadPool
.QueueUserWorkItem(o =>
{
for (int i = 0; i < 5; i++)
{
callback.Update("Step " + i);
Thread.Sleep(1000);
}
});
}
}
Then you need a svc file that has this in it (adjust the service attribute to be your service implementation class):
<%# ServiceHost Service="SilverlightApplication.Web.LongRunningService" %>
Finally you will need this configuration inside web.config (this goes inside the configuration root element):
<system.serviceModel>
<extensions>
<bindingExtensions>
<add name=
"pollingDuplexHttpBinding"
type="System.ServiceModel.Configuration.PollingDuplexHttpBindingCollectionElement,System.ServiceModel.PollingDuplex, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</bindingExtensions>
</extensions>
<services>
<service name="SilverlightApplication.Web.LongRunningService">
<endpoint
address=""
binding="pollingDuplexHttpBinding"
bindingConfiguration="multipleMessagesPerPollPollingDuplexHttpBinding"
contract="SilverlightApplication.Web.ILongRunningService">
</endpoint>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<pollingDuplexHttpBinding>
<binding name="multipleMessagesPerPollPollingDuplexHttpBinding"
duplexMode="MultipleMessagesPerPoll"
maxOutputDelay="00:00:07"/>
</pollingDuplexHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
The important parts are the name attribute on the service element and the contract attribute on the endpoint element. They should be the class and interface you defined (with the namespace).
IMPORTANT You need to add a reference to the C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Libraries\ Server\System.ServiceModel.PollingDuplex.dll assembly (remove the x86 if not 64 bit OS) to the web application project.
Silverlight Application
You need to firstly add a service reference to the service you created and then, let's say you want to call the service from a button you would have the following code:
private void button1_Click(object sender, RoutedEventArgs e)
{
// Create the client proxy with the URL of the service
var proxy = new LongRunningServiceClient(
new PollingDuplexHttpBinding(
PollingDuplexMode.MultipleMessagesPerPoll),
new EndpointAddress(
"http://localhost/WebApplication/LongRunningService.svc"));
// Attach the handler to be called periodically and start the process
proxy.UpdateReceived += Update;
proxy.StartLongRunningProcessAsync("blah");
}
private void Update(object sender, UpdateReceivedEventArgs e)
{
// Use the result from the e parameter here
}
IMPORTANT You need to add a reference to the C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Libraries\ Client\System.ServiceModel.PollingDuplex.dll assembly (remove the x86 if not 64 bit OS) to the silverlight client project.
And that is it - the Update method will get called, in this case once a second five times. but you can do whatever you like.
I would NOT recommend using a polling duplex to solve this business requirement, due to the load it places in the server. What I read was that you have a need to return several files back to the client, and provide feedback to the client as the files are being downloaded.
As downloading a file does not seem to be an issue (which should be a stream), I think you are asking is how to update the UI, while the files are being downloaded, perhaps capturing how much of the file is actually being downloaded. At the least, you should be updating the UI as each file arrives.
The latter is easy, simply download the download links to each file on the client, do them one by one, and update the UI between file downloads. That would be a single threaded approach.
Update the UI while a background thread is executing, is a more complicated approach, but a much better implementation, as the client "feels" that they remain in control while the files are being downloaded. Here is an approach for downloading a file async.
Remember in SilverLight, you really only have HTTP to transfer information to the application, which cannot do duplex. HTTP long pooling achieves the same result, but connections are left open, and greatly minimize the ability to scale.
Related
i get the following error when trying to start my service:
Could not start the Service: System.InvalidOperationException: This service has multiple endpoints listening at 'https://b2e.my.loc:8093/' which share the same initiating action 'http://localhost:8080/kestrel/AirService'. As a result, messages with this action would be dropped since the dispatcher would not be able to determine the correct endpoint for handling the message. Please consider hosting these Endpoints at separate ListenUris.
We got an application that is using a third party WSDL in order to search and book flight.
and we have another winform application that takes the generated reference.cs from the above wsdl
the idea is to create a "simulator" so instead of invoking the real WSDL we are actually invoking the simulator itself and generating the data we need (sort of mocking)
consider the following reference.cs file generated by the WSDL:
namespace FlightWCF
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace = "", ConfigurationName = "FlightWCF.ISearch")]
public interface ISearch
{
[System.ServiceModel.OperationContractAttribute(Action = "http://localhost:8080/kestrel/AirService", ReplyAction = "*")]
FlightWCF.serviceResponse1 service(FlightWCF.serviceRequest1 request);
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace = "", ConfigurationName = "FlightWCF.IReserve")]
public interface IReserve
{
[System.ServiceModel.OperationContractAttribute(Action = "http://localhost:8080/kestrel/AirService", ReplyAction = "*")]
FlightWCF.serviceResponse6 service(FlightWCF.serviceRequest6 request);
}
}
this is part of my app.config
<service name="MyFlightClass.ServiceFlight">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicSecureHttpBindingConfiguration" contract="FlightWCF.ISearch" />
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicSecureHttpBindingConfiguration" contract="FlightWCF.IReserve" />
</service>
and this is the service that is using the above code:
namespace MyFlightClass
{
class ServiceFlight : ISearch, IReserve
{
public FlightWCF.serviceResponse1 service(FlightWCF.serviceRequest1 request)
{
//DO SOMETHING
}
public FlightWCF.serviceResponse6 service(FlightWCF.serviceRequest6 request)
{
//DO SOMETHING
}
}
}
the problem is that both service uses that same "Action".
if i change the "Action" of one if them, it becomes unreachable.
and i can't find any data on how to configure a service with 2 endpoints that have different contracts but with the same action.
the suggestion "Please consider hosting these Endpoints at separate ListenUris" is unclear to me.
The main problem is that the double service endpoint address shall not be same. The configuration you provided has the same listening Uri.
<service name="MyFlightClass.ServiceFlight">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicSecureHttpBindingConfiguration" contract="FlightWCF.ISearch" />
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicSecureHttpBindingConfiguration" contract="FlightWCF.IReserve" />
</service>
So it results in that the operation has the same namespace since the operation name is duplicated. But the SOAP message is sent to the right endpoint depending on the soap operation namespace.
In a short, we shall have to change the service endpoint address in the configuration.
Feel free to let me know if there is anything I can help with.
I'm using two applications built using C# on 4.5 .Net Framework
WPF Desktop Application
Windows Service
and want them talk to each other using IPC(Inter Process Communication) approach as they need to frequently share some data/object state based on condition.
WCF with netNamedPipeBinding seems a very flexible solution. I've created a WCF Server and Client & tested successfully hosting in Console Application.
Since this solution worked, I wanted WCF Server to be hosted in Windows Service(which is my eventual requirement).
I could host the application successfully(guess because I don't see any visible error) but I cannot connect any client to it. I've used WcfTestClient.exe tool(Visual Studio default tool) as well as tried connecting from a console application, none of them seem working, as I keep on getting the error - Cannot obtain Metadata from net.pipe://localhost/TestWCFService/mex . Details added below.
I've registered the windows service with Admin privilege and running the console app test client & WcfTestClient.exe with the same user.
Naturally, I'm missing something, appreciate your help on fixing it.
Here is the code, I'm using in Windows Service to Host WCF netNamedPipeBinding Service:
protected override void OnStart(string[] args)
{
try
{
if (wcfServiceHostObj != null)
wcfServiceHostObj.Close();
wcfServiceHostObj = new ServiceHost(typeof(TestWCFService));
wcfServiceHostObj.Open();
EventLog.WriteEntry(ServiceName, "WCF Host - Started Successfully ", EventLogEntryType.Information);
}
catch (Exception ex)
{
EventLog.WriteEntry(ServiceName, "exception raised " + ex.InnerException, EventLogEntryType.Error);
throw;
}
}
Error: Cannot obtain Metadata from net.pipe://localhost/TestWCFService/mex 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: net.pipe://localhost/TestWCFService/mex Metadata contains a reference that cannot be resolved: 'net.pipe://localhost/TestWCFService/mex'. There was no endpoint listening at net.pipe://localhost/TestWCFService/mex that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details. The pipe endpoint 'net.pipe://localhost/TestWCFService/mex' could not be found on your local machine.
Here my WCF Server Config Setting:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="TestWCFServiceNetPipeBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="TestWCFServiceNetPipeBehavior"
name="WCFHostTest.WCFService.TestWCFService">
<endpoint address="net.pipe://localhost/TestWCFService" binding="netNamedPipeBinding" bindingConfiguration=""
name="TestWCFServiceNetPipeEndPoint" contract="WCFHostTest.WCFService.ITestWCFService" >
</endpoint>
<endpoint address="net.pipe://localhost/TestWCFService/mex" binding="mexNamedPipeBinding" bindingConfiguration=""
name="TestWCFServiceMexPipeEndpoint" contract="IMetadataExchange" />
<host>
<!--<baseAddresses>
<add baseAddress="net.pipe://localhost/TestWCFService" />
</baseAddresses>-->
</host>
</service>
</services>
</system.serviceModel>
For Client(which is in Console Application), I'm using inline.
Here the code
private static void testClient()
{
try
{
string address = "net.pipe://localhost/TestWCFService";
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
EndpointAddress ep = new EndpointAddress(address);
ITestWCFService channel = ChannelFactory<ITestWCFService>.CreateChannel(binding, ep);
using (channel as IDisposable)
{
channel.SendMessage("First Message");
}
Console.ReadLine();
}
catch (Exception ex)
{
Console.Write(ex.InnerException);
Console.ReadLine();
}
The most likely reason you can't connect is because there is no service address passed into the ServiceHost constructor.
Try this in your OnStart method in your Windows service:
wcfServiceHostObj = new ServiceHost(typeof(TestWCFService),
new Uri[] { "net.pipe://localhost/TestWCFService" });
Seeing the "WCF Host - Started Successfully" only means ServiceHost didn't throw an error; it doesn't guarantee that the WCF service is listening and ready to receive messages.
Also, using the using statement with WCF clients like this:
using (channel as IDisposable)
{
channel.SendMessage("First Message");
}
is considered bad practice.
I am referencing System::ServiceModel in my C++/CLI dll project (VS2012 Express). The following code fails with the following error and I can't find how to fix it.
error C2337: 'ServiceMetadataBehavior' : attribute not found
[System::ServiceModel::ServiceContractAttribute]
[System::ServiceModel::Description::ServiceMetadataBehavior]
public ref class PlaybackManager
{
public:
~PlaybackManager() { this->!PlaybackManager(); }
!PlaybackManager() { }
// Playback action methods
[System::ServiceModel::OperationContractAttribute]
void Play();
[System::ServiceModel::OperationContractAttribute]
void Stop();
[System::ServiceModel::OperationContractAttribute]
void Pause();
[System::ServiceModel::OperationContractAttribute]
void Previous();
[System::ServiceModel::OperationContractAttribute]
void Next();
[System::ServiceModel::OperationContractAttribute]
void Random();
};
EDIT1:
The caveat to this is that it is not possible to write a wcf service entirely with code, i.e without an app.config file. While the Service has the ServiceMetadataBehavior helper to create a metadata exchange behavior implementation, there is no such thing for the Endpoint. Is this "by design"?
How to: Publish Metadata for a Service Using Code
EDIT2:
OK, so the caveat above does not seem to be, necessarily, correct. Below is the app.config representing what I am trying to do in code and I get the same error if I remove the ServiceMetatdataBehavior attribute to the endpoint class implementation.
<configuration>
<system.serviceModel>
<services>
<service name="Engine.PlaybackManager">
<endpoint
address="net.tcp://localhost:7008/PlaybackManager"
binding="mexTcpBinding"
contract="IMetadataExchange"
/>
<endpoint
address="net.tcp://localhost:7008/PlaybackManager"
binding="netTcpBinding"
contract="Engine.PlaybackManager"
/>
</service>
</services>
</system.serviceModel>
</configuration>
The error is:
The contract name 'IMetadataExchange' could not be found in the list
of contracts implemented by the service PlaybackManager. Add a
ServiceMetadataBehavior to the configuration file or to the
ServiceHost directly to enable support for this contract.
The problem is, if I add the ServiceMetadataBehavior attribute to the PlaybackManager class I get the original error above, that it is not recognized. Any ideas?
I understand why nobody responded to this, "where do I begin" was the only possible response. So, in case someone falls on this with an equal amount of confusion that I had, here are some tips:
My main issue was with the mapping the xml config nomenclature (found in most examples online) with the code equivalents:
<services> maps to System::ServiceModel::ServiceHost
<behaviors> maps to "your instance of ServiceHost"->Description->Behaviors
<behavior> is type specific, the type being a nested element in the xml, thus:
<behavior> <serviceMetadata /> </behavior> maps to ServiceMetadataBehavior
<endpoint> maps to ServiceEndpoint
and finally:
the mex endpoint (the one with the ServiceMetadataBehavior added) needs it's own namespace, so add "/mex" to the end of your implementation endpoint uri address.
example:
implementation address = "net.tcp://localhost:5000/Engine"
mex address = "net.tcp://localhost:5000/Engine/mex"
Obviously these tips are not an explanation but I hope they might help someone as confused as I was when I asked the question.
***could you provide the app.config file according to my Program class please
if possible please provide app.config code i got your point but for that what you are telling i don't know how to do***
This code is not working because it's causing an error when reaching host.open(). Please help me solve the issue
public class Program
{
static void Main(string[] args)
{
// Base address
Uri baseServiceAddress = new Uri("http://localhost:8090/Welcome");
using (var host = new ServiceHost(typeof(WCFSelfHostedService), baseServiceAddress))
{
// Enable MetaData publishing.
ServiceMetadataBehavior serviceMetaDataBehaviour = new ServiceMetadataBehavior();
serviceMetaDataBehaviour.HttpGetEnabled = true;
serviceMetaDataBehaviour.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(serviceMetaDataBehaviour);
// Open the ServiceHost to start listening for messages. No endpoint are explicitly defined, runtime creates default endpoint.
host.Open();
Console.WriteLine("The service is ready at {0} and host at {1}", baseServiceAddress, DateTime.Now.ToString());
Console.WriteLine("The service and client is running in the same process.");
WCFSelfHostedService selfHostService = new WCFSelfHostedService();
Console.Write("Enter your name. : ");
Console.WriteLine(selfHostService.WelComeMessage(Console.ReadLine()));
Console.WriteLine("Host is running... Press <Enter> key to stop the service.");
Console.ReadLine();
//Close the service.
host.Close();
}
}
}
When I run this code I get this error:
An unhandled exception of type 'System.InvalidOperationException'
occurred in System.ServiceModel.dll
Additional information: Service
'WCFSelfHostedService.WCFSelfHostedService' 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.
My app.config is:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint
address ="localhost:8090/Welcome";
binding ="wsHttpBinding"
contract ="MyCalculatorService.ISimpleCalculator">
</endpoint>
</client>
</system.serviceModel>
</configuration>
The error is pretty clear: the service has no application endpoints defined.
Either you have a config file that you're not showing us (if so: please do show!), which would configure service endpoints - or then you need to set up at least one service endpoint in code.
So either create an app.config file for the app where the self-hosting is happening and add something like this to it:
<system.serviceModel>
<services>
<service name="YourNamespace.WCFSelfHostService" >
<endpoint name="Default"
address="http://yourServerName:8088/SomePlace/ServiceName"
binding="basicHttpBinding"
contract="YourNamespace.IWCFSelfHostService" />
</service>
</services>
</system.serviceModel>
or then change your code to set up at least one service endpoint in code - before you call host.Open():
// Base address
Uri baseServiceAddress = new Uri("http://localhost:8090/Welcome");
using (var host = new ServiceHost(typeof(WCFSelfHostedService), baseServiceAddress))
{
// Enable MetaData publishing.
ServiceMetadataBehavior serviceMetaDataBehaviour = new ServiceMetadataBehavior();
serviceMetaDataBehaviour.HttpGetEnabled = true;
serviceMetaDataBehaviour.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(serviceMetaDataBehaviour);
// Define AT LEAST one service endpoint
host.AddServiceEndpoint(typeof(IWCFSelfHostService), new BasicHttpBinding(), baseServiceAddress);
// Open the ServiceHost to start listening for messages. No endpoint are explicitly defined, runtime creates default endpoint.
host.Open();
Console.WriteLine("The service is ready at {0} and host at {1}", baseServiceAddress, DateTime.Now.ToString());
Console.WriteLine("The service and client is running in the same process.");
WCFSelfHostedService selfHostService = new WCFSelfHostedService();
Console.Write("Enter your name. : ");
Console.WriteLine(selfHostService.WelComeMessage(Console.ReadLine()));
Console.WriteLine("Host is running... Press <Enter> key to stop the service.");
Console.ReadLine();
// Close the service.
host.Close();
}
Update: the app.config you're showing us is defininig a client - a program that is calling a service. What you need, however, is an app.config that defines the SERVICE side of things - see my example. You need to define one or multiple <services> in your config, which in turn expose at least one application endpoint where a client can connect to.
WCF is always made up of a service (on a server), and one (or multiple) client(s) calling that service. See this article for a very basic intro to WCF architecture. The service is configured in your config file in the <services>/<service> section, while your client side needs to define their stuff in the <client> section.
I’m trying to run a very basic web service on the same IIS7 website that runs a MVC2 application. This is presenting a couple of different issues, and I believe it has to do with my system.serviceModel, but obviously I don’t know for sure (or I would fix it).
On the server side I can run my service just fine, the help operation works like a charm. I can execute the default WCF operation GetData and supply a value through the FireFox address bar.
http://localhost/services/service1/getdata?value=3 (example)
The first problem I’m having is that when I navigate to the base service URI it will display the message below. While this isn’t the end of the world because I can still execute code by manipulating the address; I do expect something else to be displayed. I expect the standard new web service message explaining that by appending “?wsdl” to the address you will receive the auto generated WSDL. I cannot access my auto generated WSDL.
“Endpoint not found. Please see the
service help page for constructing
valid requests to the service.”
Problem number two is in regard to client applications connecting to my web service. I created a console application in separate Visual Studio solution and added a web service reference to Service1. In the Visual Studio tool I can see and use the two methods that exist in my service, but when I run the code I get the following exception.
InvalidOperationException Could not
find default endpoint element that
references contract
'ServiceReference1.IService1' in the
ServiceModel client configuration
section. This might be because no
configuration file was found for your
application, or because no endpoint
element matching this contract could
be found in the client element.
Before I post my code (I’m sure readers are tired of reading about my struggles) I do want to mention that I’ve been able to run a WCF Service Library and Console application in the same solution flawlessly. There seems to be very few resources explaining WCF, WCF configuration, and working with MVC. I’ve read through several articles and either they were out-of-date or they were so simplistic they were nearly useless (e.g. click button receive web service named “Service1”).
To summarize; why am I not able to access the auto generated WSDL and how can I successfully connect my client and use the web service? Now the best part; the code.
Global.asax
//Services section
routes.Add(new ServiceRoute("services/service1", new WebServiceHostFactory(), typeof(Service1)));
Web.Config
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name="DefaultEndpoint" helpEnabled="true" automaticFormatSelectionEnabled="true" />
</webHttpEndpoint>
<mexEndpoint />
</standardEndpoints>
<services>
<service name="Project.Services.Service1" behaviorConfiguration="MetadataBehavior">
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint endpointConfiguration="DefaultEndpoint" kind="webHttpEndpoint" binding="webHttpBinding" contract="Project.Services.IService1" />
<!-- 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 name="MetadataBehavior">
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="false" /> <!-- httpGetEnabled="true" does not solve the problem either -->
<!-- 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>
</system.serviceModel>
IService1
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "GET")]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
// TODO: Add your service operations here
}
Service1
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
Client Program
class Program
{
static void Main(string[] args) {
Service1Client client = new Service1Client();
client.GetData(2);
}
}
Thanks for the help! The problem was inside of my Global.asax.cs.
Original:
routes.Add(new ServiceRoute("services/service1", new WebServiceHostFactory(), typeof(Service1)));
New:
routes.Add(new ServiceRoute("services/service1", new ServiceHostFactory(), typeof(Service1)));
The difference was chaing the host factory from "WebServiceHostFactory" to "ServiceHostFactory".
The second part of my question regarding client connections is because configuration settings are not being generated. I have to manually type them for each client. Yikes!
To avoid manually typing client configuration I had to change my endpoint
Original
<endpoint endpointConfiguration="DefaultEndpoint" kind="webHttpEndpoint" binding="webHttpBinding" contract="Project.Services.IService1" />
New
<endpoint binding="wsHttpBinding" contract="Project.Services.IService1" />
After making this change the service and client are working flawlessly.
A quick answer to one of your questions:
To summarize; why am I not able to
access the auto generated WSDL
<serviceMetadata httpGetEnabled="false" />
...needs to be
<serviceMetadata httpGetEnabled="true" />
...in order to be able to retrieve the WSDL over http. You have to tell WCF to generate service metadata, and you've told it not to.