I have a very strange and obscure issue with WCF services that I was hoping to get some insight on:
I am working a WCF service that we are building to replace one that we no longer have source code for. For some reason, in the new WCF service, everything is forced through a single paramater called "request". Using the WCF test client, this is what it looks like
On the "correct" service, this is what it looks like:
Is there any reason why this would be happening? I've defined all of the requests as follows:
[ServiceContract]
public interface IMyService
{
[OperationContract]
string SomeRequest();
}
Which seems correct, but there may be something I've overlooked that is causing this.
In your original WCF service, there is a request function parameter, and it has a definition similar to the following:
[ServiceContract]
public interface IMyService
{
[OperationContract]
Request SomeRequest(Request request);
}
[DataContract]
public class Request
{
string documentId;
[DataMember]
public string DocumentId
{
get { return documentId; }
set { documentId = value; }
}
}
In the new wcf service:
[ServiceContract]
public interface IMyService
{
[OperationContract]
string SomeRequest(string documentId);
}
So this is because the function parameters are different. Originally your parameter was class, but later changed to string, so the display in WCFTestClient is different.
Related
My interface look like this:
[ServiceContract]
public interface IMyService
{
[OperationContract]
myConnectedService.SomeComplexResponseType someMethod(myConnectedService.SomeComplexRequestType request);
}
My implementation look like this:
public class MyService : IMyService
{
myConnectedService_client client = new myConnectedService_client();
public myConnectedService.SomeComplexResponseType someMethod(myConnectedService.SomeComplexRequestType request)
{
myConnectedService.SomeComplexResponseType response = client.connectedServiceMethod(request);
return response ;
}
}
The error i get when i am trying to run my service:
Failed to add a service. Service metadata may not be accessible. Make sure your service is running and exposing metadata.
and
error CS0644: 'System.ComponentModel.PropertyChangedEventHandler' cannot derive from special class 'System.MulticastDelegate'
I have a strange problem I have been pulling my hair out over. I am trying to create a TFS event handler service in WCF, and part of the requirement is to generate a SOAP 1.2 envelope with specific namespaces and actions.
The basic interface looks like this:
[ServiceContract(Namespace="http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
public interface ITfsNotificationService
{
[OperationContract(Action="http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", ReplyAction="*")]
[XmlSerializerFormat(Style = OperationFormatStyle.Document)]
void Notify(string eventXml, string tfsIdentityXml, SubscriptionInfo SubscriptionInfo);
}
However, when I attempt to access this service with the WcfTestClient I get an error, as well as no Methods show up in the interface:
The contract 'ITfsNotificationService' in client configuration does not
match the name in service contract, or there is no valid method in this
contract.
However, if I remove the action property from the operation contract, it runs fine (but will have the wrong Action method, which includes the interface name) and without any error. Clearly the error is referring to the second half of the message (Or there is no valid method in this contract)
When I look at the generated WSDL, there are no operation elements generated when using the action property, but there is when I just specify an empty [OperationContract].
Any clues as to what I'm doing wrong here?
FYI, this is based on the sample here: http://www.ewaldhofman.nl/post/2010/08/02/how-to-use-wcf-to-subscribe-to-the-tfs-2010-event-service-rolling-up-hours.aspx
I was curious about this, so I've tried here and worked.
Here is what I did:
[ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
public interface ITfsNotificationService
{
[OperationContract(Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", Name = "Notify", ReplyAction = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/ResponstToNotify")]
[XmlSerializerFormat(Style = OperationFormatStyle.Document)]
void Notify(string eventXml, string tfsIdentityXml, SubscriptionInfo SubscriptionInfo);
}
[ServiceBehavior(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
public class Service1 : ITfsNotificationService
{
public void Notify(string eventXml, string tfsIdentityXml, SubscriptionInfo SubscriptionInfo)
{
throw new NotImplementedException();
}
}
Hope it helps.
I currently am running some WCF REST services in a Windows Service (not IIS), using the WebServiceHost. I have a separate interface and class defined for each service, but I'm having some issues understanding how WebServiceHost, ServiceEndpoint and ServiceContracts can be used together to create a selfhosted solution.
The way that I currently set things up is that I create a new WebServiceHost for each class which implements a service and use the name of the class as part of the URI but then define the rest of the URI in the interface.
[ServiceContract]
public interface IEventsService
{
[System.ServiceModel.OperationContract]
[System.ServiceModel.Web.WebGet(UriTemplate = "EventType", ResponseFormat=WebMessageFormat.Json)]
List<EventType> GetEventTypes();
[System.ServiceModel.OperationContract]
[System.ServiceModel.Web.WebGet(UriTemplate = "Event")]
System.IO.Stream GetEventsAsStream();
}
public class EventsService: IEventsService
{
public List<EventType> GetEventTypes() { //code in here }
public System.IO.Stream GetEventsAsStream() { // code in here }
}
The code to create the services looks like this:
Type t = typeof(EventService);
Type interface = typeof(IEventService);
Uri newUri = new Uri(baseUri, "Events");
WebServicesHost host = new WebServiceHost(t, newUri);
Binding binding = New WebHttpBinding();
ServiceEndpoint ep = host.AddServiceEndpoint(interface, binding, newUri);
This works well and the service endpoint for each service is created at an appropriate url.
http://XXX.YYY.ZZZ:portnum/Events/EventType
http://XXX.YYY.ZZZ:portnum/Events/Event
I then repeat for another service interface and service class. I would like to remove the Events in the Url though but if I do that and create multiple WebServiceHosts with the same base URL I get the error:
The ChannelDispatcher at 'http://localhost:8085/' with contract(s) '"IOtherService"' is unable to open its IChannelListener
with the internal Exception of:
"A registration already exists for URI 'http://localhost:8085/'."
I'm trying to understand how the WebServiceHost, ServiceEndpoint and ServiceContract work together to create the ChannelListener.
Do I need a separate WebServiceHost for each class which implements a service? I don't see a way to register multiple types with a single WebServiceHost
Secondly, I'm passing in the interface to the AddServceEndpoint method and I assume that method checks the object for all of the OperationContract members and adds them, the problem is how does the WebServiceHost know which class should map to which interface.
What I would love would be an example of creating a WCF self hosted service which runs multiple services while keeping the interface and the implementation classes separate.
Sounds to me like the problem that you are having is you are trying to register more than one service on the same service URI. This will not work, as you have noticed, each service must have a unique endpoint.
Unique By
IP
Domain
Port Number
Full URL
Examples
http://someserver/foo -> IFoo Service
http://someserver/bar -> IBar Service
http://somedomain -> IFoo Service
http://someotherdomain -> IBar Service
http://somedomain:1 -> IFoo Service
http://somedomain:2 -> IBar Service
You get the idea.
So to directly address your question, if you want more than once service to be at the root url for you site, you will have to put them on different ports. So you could modify your code to be something like
public class PortNumberAttribute : Attribute
{
public int PortNumber { get; set; }
public PortNumberAttribute(int port)
{
PortNumber = port;
}
}
[PortNumber(8085)]
public interface IEventsService
{
//service methods etc
}
string baseUri = "http://foo.com:{0}";
Type iface = typeof(IEventsService);
PortNumberAttribute pNumber = (PortNumberAttribute)iface.GetCustomAttribute(typeof(PortNumberAttribute));
Uri newUri = new Uri(string.Format(baseUri, pNumber.PortNumber));
//create host and all that
I think it might be useful for you to re-think about your URI approach. Uri is a unique resource identifier.
Each your endpoint says that you try to expose outside a different kind of resource it's "Events" and "OtherResource". Thus you need to change your UriTemplates a bit.
I would make it so:
[ServiceContract]
public interface IEventTypesService
{
[OperationContract]
[WebGet(UriTemplate = "", ResponseFormat=WebMessageFormat.Json)]
IList<EventType> GetEventTypes();
[OperationContract]
[WebGet(UriTemplate = "{id}")]
EventType GetEventType(string id);
}
[ServiceContract]
public interface IEventsService
{
[OperationContract]
[WebGet(UriTemplate = "")]
Stream GetEventsAsStream();
[OperationContract]
[WebGet(UriTemplate = "{id}")]
Event GetEvent(string id);
}
public class EventsService: IEventsService, IEventTypesService
{
public IList<EventType> GetEventTypes() { //code in here }
public EventType GetEventType(string id) { //code in here }
public Stream GetEventsAsStream() { // code in here }
public EventType GetEventType(string id) { // code in here }
}
Type t = typeof(EventService);
Type interface1 = typeof(IEventsService);
Type interface2 = typeof(IEventTypesService);
var baseUri = new Uri("http://localhost");
Uri eventsUri= new Uri(baseUri, "Events");
Uri eventTypesUri= new Uri(baseUri, "EventTypes");
WebServicesHost host = new WebServiceHost(t, baseUri);
Binding binding = New WebHttpBinding();
host.AddServiceEndpoint(interface1, binding, eventsUri);
host.AddServiceEndpoint(interface2, binding, eventTypesUri);
And yes, you are right - you have to have different addresses, but it's really different resources. To understand it better you can refer: RESTful API Design, best-practices-for-a-pragmatic-restful-api
To finish, there is a way to use the same address, but the approach a bit weird:
Using the same address
The following solution:
allows a single object to handle a specific endpoint
no part of the path is in the URI template
uses the same port for all of the services
It does requires more than one WebServiceHost - one per object that handles requests. Another difficulty is that adding deeper endpoints (like /events/2014) means they either need to have unique parameters or the URI template must include part of the path, if you go convention over configuration that shouldn't be a problem.
A WebServiceHost can only host one thing (class) but that object can have multiple interfaces to handle multiple different types of requests on different URLs. How can different WebServiceHosts bind to the same domain:port? They can't so I guess WebServiceHost wraps an underlying static object that routes requests to the right object. This doesn't technically answer your question but I think this implementation allows you to do what you want right?
A console app that hosts the web services.
public class Program
{
static void Main (string[] args)
{
var venueHost = new WebServiceHost (typeof (Venues));
venueHost.AddServiceEndpoint (typeof (IVenues), new WebHttpBinding (), "http://localhost:12345/venues");
venueHost.Open ();
var eventHost = new WebServiceHost (typeof (Events));
eventHost.AddServiceEndpoint (typeof (IEvents), new WebHttpBinding (), "http://localhost:12345/events");
eventHost.Open ();
while (true)
{
var k = Console.ReadKey ();
if (k.KeyChar == 'q' || k.KeyChar == 'Q')
break;
}
}
}
The Venues class implements IVenues and handles any requests to http://localhost:12345/venues/
[ServiceContract]
public interface IVenues
{
[WebInvoke (Method = "GET", UriTemplate = "?id={id}")]
string GetVenues (string id);
}
public class Venues : IVenues
{
public string GetVenues (string id)
{
return "This would contain venue data.";
}
}
The Events class implements IEvents and handles any requests to http://localhost:12345/events/
[ServiceContract]
public interface IEvents
{
[WebInvoke (Method = "GET", UriTemplate = "?venue={venue}")]
string GetEvents (string venue);
}
public class Events : IEvents
{
public string GetEvents (string venue)
{
return "This would contain event data.";
}
}
WCF self hosting can be done in many ways like Console application hosting, Windows service hosting, etc.
I had tried to host two services using a single console application. The structure of the services was similar to what you mentioned, that is, separate classes and interfaces for both the services.
You might want to have a look at this link:
Hosting two WCf services using one console app
I've a WCF web service method (over 3.5 NET Framework) which needs to be refactored to use optional input parameters. Mi investigation concluded optional parameteres as a concept is being introduced on 4.0 so I need to do some workaround to solve my issue. My code update looks like this:
partial class Class1: IService {
public int MethodName ( int param1, string param2 )
{
// code here
}
public int MethodName ( int param1)
{
// code here
string param2 = FillInInternally();
return this.MethodName(param1, param2);
}
I've also updated my operation contract:
[ServiceContract]
public interface IService
{
[OperationContract(Name = "Alias1")]
int MethoName(int param1, string param2);
[OperationContract(Name = "Alias2")]
int MethoName(int param1);
}
public partial class ServiceClient : ClientBase <IService>, IService
{
public int MethoName(int param1, string param2)
{
return Channel.MethodName(param1, param2);
}
public int MethoName(int param1)
{
return Channel.MethodName(param1);
}
}
Having that explained, I was able to get the Web Service correctly build. Besides oh that Integration Tests also ran perfectly. After that, I needed to install on the server and when trying to test the WSDL, I've faced an issu indicating an error on the svc file at column 1, row 1 ( please note I'm not including the exact error message because I rolled back the WS to the previous version to avoid prod issue during the weekend).
My question is: does somebody think I'm missing something from development? Or will I be able to get my WCF service method correctly overloaded when the "installation?" issues is solved?.
Any comments will be welcome.
Thanks,
.NET Framework 3.5
Visual Studio 2008 Standard Edition
C#
Are you manually constructing the ServiceClient class? I recommend you to use the svcutil.exe tool to generate the proxy and don't encourage yourself to do the modifications directly in the generated proxy code.
If you have generated the proxy through the tool or VS add service reference you should see the IService and the ServiceClient should look something like this,
[ServiceContract]
public interface IService
{
int Alias1(int param1, string param2);
int Alias2(int param1);
}
public partial class ServiceClient : ClientBase <IService>, IService
{
// other stuff
public int Alias1(int param1, string param2)
{
return base.Channel.Alias1(param1, param2);
}
public int Alias2(int param1)
{
return base.Channel.Alias2(param1);
}
}
Note that your client have the methods as Alias1 and Alias2 not MethodName. Please make sure yourself you have the right proxy to talk to service.
recently have been successful getting my IIS hosted WCF service to work with basic authentication.
Since successfully implementing that. I have noticed that property values are not remembered.
Here is some code:
[ServiceContract]
public interface IEcho
{
string Message { [OperationContract]get; [OperationContract]set; }
[OperationContract]
string SendEcho();
}
public class EchoProxy : IEcho
{
public string Message { get; set; }
public string SendEcho()
{
return string.Concat("You said: ", Message);
}
}
public class EchoService : System.ServiceModel.ClientBase<IEcho>, IEcho
{
//-- ..... CONSTRUCTORS OMITTED ....
public string Message
{
get { return base.Channel.Message; }
set { base.Channel.Message = value; }
}
public string SendEcho()
{
return base.Channel.SendEcho();
}
}
Here is the console and the result:
EchoService client = new EchoService("SecureEndpoint");
client.ClientCredentials.UserName.UserName = "test";
client.ClientCredentials.UserName.Password = "P#ssword1";
client.Message = "Hello World";
Console.WriteLine(client.SendEcho());
Expected Result: You said: Hello World
Actual Result: You said:
I have Uploaded the sandbox project to my skydrive. I have included a SETUP.txt in the API project.
Click here to download.
How can I get properties to work?
thank you
I have never seen WCF contract used with a property to transfer data. i.e. the Message property. AFAIK its just not possible.
My recommendation would be to keep the concerns that are part of the contract separate, i.e. Operation and Data.
[ServiceContract]
public interface IEcho
{
[OperationContract]
string SendEcho(string Message);
}
Or
[ServiceContract]
public interface IEcho
{
[OperationContract]
string SendEcho(Message message);
}
[DataContract]
public class Message
{
[DataMember]
public string Message {get; set;}
}
At some later point you may wish to change the Message Object.
[DataContract]
public class MessageV2 : Message
{
[DataMember]
public DateTime Sent {get; set;}
}
While this changes the contract, changes like this can be backwardly compatible if managed carefully.
To understand what's happening, you need to know how the lifetime of the service object you're connecting to is configured. A good starting point is the MSDN article on Sessions, Instancing, and Concurrency.
For example, with InstanceContextMode.PerCall, a new service object will be created for each call, so no properties of the service object will be remembered between calls.
At the other end of the scale, InstanceContextMode.Single means a single instance handles all client requests for the lifetime of the application. In this case properties set by one client will be visible to all clients, not usually desirable.
In general, I would recommend using a stateless service object. But if you want a stateful service object (e.g. one with properties), you should use InstanceContextMode.PerSession, and (important) use a binding that supports sessions.
While I agree with #JTew that you shouldn't generally expose operations as properties, you will have the same problem if you try to use an object that stores state between calls in another way (such as a private field). I.e. the following would have exactly the same problem:
[ServiceContract]
public interface IEcho
{
[OperationContract]
void SetMessage(string message);
[OperationContract]
string GetMessage();
... etc ...
}