I have a WCF service library project. I am trying to generate a wsdl file by launching WCF Test Client by running it in Visual studio (pushed F5). It launched WCF Test Client but it says "Failed to add a service. Service metadata may not be accessible. Make sure your service is running and exposing metadata.". It also gives me the below error message.
c:\Users\xxx\AppData\Local\Temp\Test Client Projects\10.0\354421b1-b65e-45fc-8d98-ac87254a5903\Client.cs(911,26) : error CS0644: 'System.ComponentModel.PropertyChangedEventHandler' cannot derive from special class 'System.MulticastDelegate'
I added servive behavior to expose Metadata as follows. I am not sure what else I am missing here to be able to generate a wsdl file. Thanks for any help!
<services>
<service name="CU.Customer" behaviorConfiguration="Metadata">
<endpoint address="" binding="wsHttpBinding" contract="CU.ICustomer">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint name="mex" address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/CustomerService/Service1/"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Metadata">
<!-- 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>
There is nothing wrong with your metadata bindings, but you have a compiler error in your service. This is preventing WCF from building your service class, which is needs to do to expose the metadata endpoint.
Fix this error first:
'System.ComponentModel.PropertyChangedEventHandler' cannot derive from special class 'System.MulticastDelegate'
The error (note that it's in a temp file) is happening when WCF is trying to compile the service contracts locally into classes it can use to access the service. This means that you're running into something that is legal in C#, but not legal in WCF. Most likely, given the error, you have a class that implements INotifyPropertyChanged being used as a data contact in your operation contract.
Note that every class that gets serialized across a WCF channel is a data contract. Typically you would decorate your class with DataContract and each field with DataMember attributes, which directs the serializer how to handle your class. But if you don't, and you include your class as a parameter or return value in an OperationContract, WCF just pretends like you put those attributes on every public field in your class.
In this case, my guess is you have a class, that you are passing in or out of a service call, that has:
public event PropertyChangedEventHandler PropertyChanged;
That is a public field, so unless you tell WCF otherwise, it will try to serialize it as part of the implicit data contract. But there are certain types that cannot be serialized this way, and MulticastDelegate is one of them.
To fix, and in the future avoid, this problem, always decorate the types you use for services with DataContract and DataMember explicitly. It's perfectly safe to put those attributes on any class -- if you never try to serialize it, the attributes are simply ignored.
Related
Background
I have created ASMX web services in the past and have been able to access the service from the web browser and Ajax GET requests using the address convention: MyService.asmx/MyMethod?Param=xxx
I just got started using WCF and created a new web service in my ASP.NET project. It creates a file with the .svc extension such as MyService.svc.
Current Situation
I am able to consume the service using the WcfTestClient that comes with VS2008. I am also able to create my own WCF Client by either adding a service reference in another project or using the svcutil.exe commandline to generate the proxy and config file.
The Problem
When I try to use the service from a browser using MyService.svc/MyMethod?MyParam=xxx, I get a blank page without any errors.
What I have tried
I have already added a basicHttpBinding to the web.config and made it HttpGetEnabled in the behavior configuration. I also added the [WebGet(UriTemplate = "MyMethod?MyParam={MyParam}")] attribute to my operation contract.
I have already followed the information in this other stack overflow question:
REST / SOAP EndPoints for a WCF Service
However, I either get a blank page or an HTTP 404 Error after following those steps. There's nothing special about the code. I am just taking in a string as a parameter and returning "Hello xxx". This is a basic "Hello WCF World" proof-of-concept type thing.
UPDATE - Here's the relevant code
[ServiceContract]
public interface IMyService
{
[WebGet(UriTemplate = "MyMethod/MyParam={MyParam}")]
[OperationContract]
string MyMethod(string MyParam);
}
Web.Config - system.serviceModel Section
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MyServiceBehavior" name="MyService">
<endpoint address=""
binding="wsHttpBinding" contract="IMyService" />
<endpoint address="MyService.svc"
binding="basicHttpBinding" contract="IMyService" />
<endpoint address="mex"
binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
Looking at your web.config serviceModel section, I can see that you need to add a webHttpBinding and associate an endPointBehavior that includes webHttpGet.
Your operation contract is correct. Here's how your system.serviceModel config section should look in order for you to be able to consume the service from a GET HTTP request.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="WebBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MyServiceBehavior" name="MyService">
<endpoint address="ws" binding="wsHttpBinding" contract="IMyService"/>
<endpoint address="" behaviorConfiguration="WebBehavior"
binding="webHttpBinding"
contract="IMyService">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
Be sure to assign a different address to your wsHttpBinding endpoint, otherwise you will get an error saying that you have two endpoints listening on the same URI.
Another option is to leave the address blank in the wsHttpBinding, but assign a different address to the webHttpBinding service. However, that will change your GET address as well.
For example, if you assign the address as "asmx", you would call your service with the address "MyService.svc/asmx/MyMethod?MyParam=xxxx".
The normal WCF requests are always SOAP requests - you won't be able to get this going with just your browser, you'll need the WCF Testclient for that.
There is an add-on for WCF called the WCF REST Starter Kit (which will also be included in WCF 4.0 with .NET 4.0), which allows you to use GET/POST/PUT/DELETE HTTP commands to query WCF services and such. You need to write your services specifically for REST, though - you can't have SOAP and REST on the same service call.
Marc
As marc_s says, the REST Starter Kit can help, but you should also be aware that .NET 3.5 has support for REST services directly in it. It's not quite as complete as what you can do with the starter kit, but it is useful.
The way it works is that you put a [WebGet] attribute on your operations to indicate where in the URL the various parameters should come from:
[WebGet(UriTemplate = "helloworld/{name}")]
string Helloworld(string name);
See this portal for tons of information.
Note, you can have the same service exposed as both SOAP and REST if you specify multiple endpoints/bindings in the configuration.
I have created and hosted a service http://www.royalbatteriesws.somee.com/Default.svc
I want to test my service for its functionality.
I have added a service reference in my Asp.Net web site called RoyalBatteriesWS
As no endpoint was added automatically in the web.config file, I had to add it manually.
web.config file:
System.ServiceModel and ServiceBehaviors sections:
<service name="RoyalBatteriesWS" behaviorConfiguration="HelloServiceBehavior">
<endpoint
address ="http://www.royalbatteriesws.somee.com/Default.svc"
binding="basicHttpBinding"
contract="RoyalBatteriesWS.IService">
</endpoint>
</service>
<serviceBehaviors>
<behavior name="HelloServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
I get an exception
Could Not find default Endpoint that references contract 'RoyalBatteriesWS.Iservice' in the ServiceModel client configuration section
Please can anybody point out my mistake?
I went through previous posts and I couldn't find what works for me.
Thanks
The name="..." attribute of your <service> must match exactly the fully-qualified name of the .NET class that implements that service.
This means: it has to be the exact class name and all namespaces of that class.
So most likely, your service class is called RoyalBatteriesWS - but there's a good chance it's stored in some namespace - so add that namespace to that attribute and you should be good to go!
On the other hand, since you said you added a service reference - do you really want to configure a service here - that's the server-side of things (where the actual service class is coded).
Don't you want to configure a class that consumes / uses that service - a client ??
If so - use the <client> tag (instead of <service>):
<client name="RoyalBatteriesWS">
<endpoint
address ="http://www.royalbatteriesws.somee.com/Default.svc"
binding="basicHttpBinding"
contract="RoyalBatteriesWS.IService">
</endpoint>
</client>
I have a WCF service on IIS that a few .net web applications are using. I was tasked with writing a new WCF service, with the requirement that the existing web apps could use the new service without changing anything but their web.config.
So my new service needs 2 interfaces, I think? I've done that, I have three interfaces - ILocationsWCF (same name as the interface in the old service) ILocationDW (has new methods) and
ILocationService : ILocationsWCF, ILocationDW.
Then public class LocationService : ILocationService. I can write a new web app that uses ILocationService just fine - but I can't figure out how to make this new service have 2 endpoints, one for the old apps and one for the new ones (doing this because the old service is a bit awkward so I would like to keep them separated, then redeploy the old apps with the new service if the opportunity arises). Mostly, this change is driven by new source data - but I digress.
Here is the error I get:
A binding instance has already been associated to listen URI http://localhost:10737/LocationService.svc. If two endpoints want to share the same ListenUri, they must also share the same binding object instance. The two conflicting endpoints were either specified in AddServiceEndpoint() calls, in a config file, or a combination of AddServiceEndpoint() and config.
My attempt at web.config service model:
<system.serviceModel>
<services>
<service name="PPS.Services.Location.LocationService" behaviorConfiguration="LocationServiceBehavior">
<endpoint address=""
binding="basicHttpBinding" name="PPS.Services.Location.LocationService"
bindingNamespace="PPS.Services.Location"
contract="PPS.Services.Location.ILocationService"
bindingConfiguration="BasicHttpBinding_ILocationService"
behaviorConfiguration="HttpBehavior">
</endpoint>
<endpoint address=""
binding="basicHttpBinding" name="PPS.Services.Location.LocationsWCF"
bindingNamespace="PPS.Services.Location"
contract="PPS.Services.Location.ILocationsWCF"
bindingConfiguration="BasicHttpBinding_ILocationsWCF"
behaviorConfiguration="HttpBehavior">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="LocationServiceBehavior">
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="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>
<endpointBehaviors>
<behavior name="HttpBehavior" />
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ILocationService" receiveTimeout="00:05:00" sendTimeout="00:05:00" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"></binding>
<binding name="BasicHttpBinding_ILocationsWCF" receiveTimeout="00:05:00" sendTimeout="00:05:00" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"></binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
My Interfaces:
namespace PPS.Services.Location
{
[ServiceContract(Name = "LocationService")]
public interface ILocationService : ILocationsWCF, ILocationServiceDW
{...
namespace PPS.Services.Location
{
[ServiceContract(Name = "LocationsWCF")]
public interface ILocationsWCF
{...
namespace PPS.Services.Location
{
[ServiceContract(Name = "LocationServiceDW")]
public interface ILocationServiceDW
{...
Any help with these endpoints, or have I gone off in the wrong direction?
EDIT -- NEW PROBLEM!
Thanks for the help, marc_s got me over that hump. Now, my goal is to replace the existing service with the new service, by changing the endpoint in web.config only. I cannot get this to work, I get the error like:
...cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher...
If I remove the old service from the application and replace it with the new one, then compile and run it works - but I don't want to have to re-deploy all my old apps, I would rather just replace the endpoint in the web.config. Can I even do this? There are differences in the 2 services, mainly a new database (our student data is now with a new vendor -- out of my control) plus I've learned a lot and was able to write a much better service.
Can I do what I want here, or will I need to run 2 services until I can move all the old apps to the new service?
Note, when I'm certain the contracts etc are identical, but if you need to see files just let me know which ones.
thanks.
One endpoint = one contract. If you've combined your two sets of service methods into a single service contract (ILocationService), you cannot have two separate endpoints.
What you should do is have one service implementation class (LocationService) that implements the two interfaces:
public class LocationService : ILocationsWCF, ILocationDW
Now, you have one service implementation, but you can define two separate endpoints:
<services>
<!-- the name= must exactly match the name of the concrete service implementation class -->
<service name="PPS.Services.Location.LocationService"
behaviorConfiguration="LocationServiceBehavior">
<!-- the contract= must exactly match the name of an existing service contract -->
<endpoint name="PPS.Services.Location.LocationService"
address=""
behaviorConfiguration="HttpBehavior">
binding="basicHttpBinding" bindingNamespace="PPS.Services.Location"
bindingConfiguration="BasicHttpBinding_ILocationService"
contract="PPS.Services.Location.LocationServiceDW" />
<!-- the contract= must exactly match the name of an existing service contract -->
<endpoint name="PPS.Services.Location.LocationsWCF"
address="someother"
behaviorConfiguration="HttpBehavior"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ILocationsWCF"
bindingNamespace="PPS.Services.Location"
contract="PPS.Services.Location.ILocationsWCF" />
</service>
</services>
Now you have two endpoints - each one exposing one service contract - and mind you: they have to have different address=..... values! You cannot have two different endpoints on the same address
I have an existing web service (ASMX) that needs to be exposed as WCF as well. ASMX must remain and preferably with no change on the client. As per this I have configured as follows. The service layer is generated with CodeSmith and whilst I didn't write these services I know they are fine as they have been used in the wild for many years. The names have been changed to protect the innocent .. grin.
In the service layer there is an XXX.YYY.MyService class generated by CodeSmith which is double decorated with
[ServiceContract( Namespace = "http://XXX.YYY" )]
and
[WebService( Namespace = "http://XXX.YYY", Name = "MyService" )]
I have also created an empty interface XXX.YYY.IMyService which is implemented by MyService. At this point I can consume the ASMX service with no issues.
Now I add a .svc file to the service layer which contains ...
<%# ServiceHost Language="C#" Debug="true" Service="XXX.YYY.MyService" %>
... and I configure the service layer's web.config with ...
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MyServiceBehavior" name="XXX.YYY.MyService">
<endpoint binding="basicHttpBinding" contract="XXX.YYY.IMyService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
If I build and then try and make a service reference in Visual Studio 2010 to the service, I see both .ASMX and .SVC versions of MyService. Expanding the .svc branch in the Add Service Reference dialog results in an error referring to an empty XML document.
If I examine the event log I get ...
WebHost failed to process a request.
Sender Information: System.ServiceModel.ServiceHostingEnvironment+HostingManager/39449526
Exception: System.ServiceModel.ServiceActivationException: The service '/System/MyService.svc' cannot be activated due to an exception during compilation. The exception message is: The contract name 'XXX.YYY.IMyService' could not be found in the list of contracts implemented by the service 'MyService'.. --->
... but MyService is marked as implementing IMyService ...
public partial class MyService : IMyService
I have also tried changing the contract attribute for the service to MyService instead of the interface. That works but for the client code breaks as any attempt to create an instance of the service fails as it is now an interface.
I hope that makes sense. Please feel free to ask anything extra. I have tried to be as detailed as possible.
(No IIS involved .. this is purely in Visual Studio 2010).
Thanks.
Your code implements IMyService are you sure that it is XXX.YYY.IMyService.
The answer for me was to move the [ServiceContract] and [OperationContract] declarations to the interface. This has fixed the issue for me.
HTH.
I'm trying to create an in-process unit test for my service to client interactions using net.pipe binding. Like a good WCF service it uses FaultContractAttribute on service operations to expose possible faults (wrapped exceptions) to metadata. I would like to have the client and service endpoints configured thru XML (App.config). However, whenever a fault is thrown, it's just a CommunicationException "pipe has closed", and not the typed Fault I was expecting.
System.ServiceModel.CommunicationException: There was an error reading from the pipe: The pipe has been ended. (109, 0x6d).
I tried Adding IMetadataExchange endpoint for net.pipe, but that didn't work. I also tried . Which being on Vista required me to netsh the ACL for the http endpoint. That too did not work.
The custom exception class:
public class ValidationException : ApplicationException { }
This is the latest attempt at a config, but it pumps out "The contract name 'IMetadataExchange' could not be found in the list of contracts implemented by the service"
Any Links to examples or recommendations for how to get this done would be appreciated.
<system.serviceModel>
<client>
<endpoint name="Client"
contract="IService"
address="net.pipe://localhost/ServiceTest/"
binding="netNamedPipeBinding"
bindingConfiguration="netPipeBindingConfig" />
</client>
<services>
<service
name="Service"
behaviorConfiguration="ServiceFaults">
<host>
<baseAddresses>
<add baseAddress="net.pipe://localhost/ServiceTest/"/>
<add baseAddress="http://localhost/ServiceTest/"/>
</baseAddresses>
</host>
<endpoint
address=""
binding="netNamedPipeBinding"
bindingConfiguration="netPipeBindingConfig"
name="ServicePipe"
contract="IService" />
<endpoint
address="MEX"
binding="mexNamedPipeBinding"
bindingConfiguration="mexNetPipeBindingConfig"
name="MexUserServicePipe"
contract="IMetadataExchange" />
</service>
</services>
<bindings>
<netNamedPipeBinding>
<binding name="netPipeBindingConfig"
closeTimeout="00:30:00"
sendTimeout="00:30:00" />
</netNamedPipeBinding>
<mexNamedPipeBinding>
<binding name="mexNetPipeBindingConfig"></binding>
</mexNamedPipeBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceFaults">
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
<behavior name="MEX">
<serviceMetadata
httpGetEnabled="true"
httpGetUrl="http://localhost/ServiceTest/MEX"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
If the ValidationException class you describe above is the class you are using for faults, it may be the source of your problem. You should derive your fault exceptions from FaultException because it is Serializable. ApplicationException is not.
Wagner is right, you need to decorate your operation definition with a FaultContract attribute giving it the type of your contract. You should also to decorate your FaultContract with DataContract and DataMember attributes as well.
I got that same error a few days ago.
I solved creating my own class (MyFault) and throwing FaultException from the server and catching those in the client. MyFault has a string member wich is the Exception Message I want the client to see.
I hope I made myself clear... I'll try to look for a nice sample and I'll post it here
The problem is most likely an error deserializing or serializing the request or response. Enable trace and view the log with svctraceviewer for the exact error.
Also, make sure your fault exception is marked with [DataContract] and does not inherit and non [DataContract] classes.
One last thing to add. Do your operation contracts define the ServiceFault they are using?.
My understanding is that you have to define which ServiceFaults your're using at the operation layer, and your business logic throw a FaulException where T is the ServiceFault you defined.