I want to refactor service into multiple sub-services, separated by their business scope:
[ServiceContract]
public interface IMyService
{
[OperationContract]
int Method1();
[OperationContract]
int Method2();
}
And some users already using it, so I can't just bash in and say "goodbye" to them, refactoring everything on my way.
So, to avoid duplication, I use abstractions and interfaces beforehand and in this case I tried to separate contract to multiple interfaces and leaving main one as aggregator:
[ServiceContract]
public interface IMyService : IMySubService1, IMySubService2
{
}
[ServiceContract]
public interface IMySubService1
{
[OperationContract]
int Method1();
}
[ServiceContract]
public interface IMySubService2
{
[OperationContract]
int Method2();
}
I thought this will do the thing, but NO - it's breaking those clients, because now those methods located on different paths in WSDL, even though Im hosting only IMyService:
It was: net.tcp://foobar/IMyService/Method1
It became: net.tcp://foobar/IMySubService1/Method1
And that's a problem. I can't separate my contract into interfaces without duplication of code (one for implementation, and one explicitly aggregated for contract), any way I can solve it?
Managed to do it this way:
[ServiceContract(Name = nameof(IMyService))]
public interface IMyService : IMySubService1, IMySubService2
{
}
[ServiceContract(Name = nameof(IMyService))]
public interface IMySubService1
{
[OperationContract]
int Method1();
}
[ServiceContract(Name = nameof(IMyService))]
public interface IMySubService2
{
[OperationContract]
int Method2();
}
Now WSDL generated correctly.
Related
I return various types from my service:
[ServiceContract]
public interface IService
{
[OperationContract]
void Initialize();
[OperationContract]
Settings GetSettings(); // returns custom type Settings
[OperationContract]
void SetSettings(Settings settings);
[OperationContract]
bool SettingsAccepted();
}
But I want to introduce status codes for my service that is not built on WCF infrastructure but on my service's inner logic, like this:
[DataContract]
public enum ServiceStatus
{
[EnumMember]
NormalWork = 0,
[EnumMember]
TimeOut,
[EnumMember]
DenialOfService
};
And I want my service to return not just void, bool or custom type, but them with status code, like this (pseudo code):
[ServiceContract]
public interface IService
{
[OperationContract]
(ServiceStatus) Initialize();
[OperationContract]
(ServiceStatus, Settings) GetSettings();
[OperationContract]
(ServiceStatus) SetSettings(Settings settings);
[OperationContract]
(ServiceStatus, bool) SettingsAccepted();
}
Client's logic will be like this: check the status code in returned message and if it is ServiceStatus.NormalWork then do work with the rest part of returned message.
How best to organize it? Have I introduce a base class to return (with DataContract attribute) and then create new derived class from it per each return value (per each operation contract)? Or is there a better approach? Maybe there is a built in infrastructure in WCF for task like this - to return custom status codes together with custom return types?
Client's logic will be like this: check the status code in returned message and if it is ServiceStatus.NormalWork then do work with the rest part of returned message.
If you really want this, the other answer has all the details to create such a beast. However, please do not do this. If your service is not working normally, throw an exception. It will be translated to a fault automatically.
Return codes are so 1980. I already have to have exception handling. Your service may be unavailable, the network may be down or there may be any other failure. So I already have exception handling and now with your proposed method, I need exception handling and return code handling. With every single call. That sucks. In addition, people may make mistakes easier. They might just take the delivered values and forget to check your return code. With exceptions, that mistake will never happen.
If you want your service to fail with an error that says "DenialOfService", then please create a DenialOfServiceException and throw that. Don't use return codes. That's not the WCF way to report errors.
If you do want to have a fixed structure, you can use the template approach of the other answer, or you can use inheritance:
[DataContract]
public class ServiceResponse
{
[DataMember]
public ServiceStatus Status { get; set; }
}
[DataContract]
public class SettingsAcceptedResponse : ServiceResponse
{
[DataMember]
public bool Result { get; set; }
}
[ServiceContract]
public interface IService
{
// [...]
[OperationContract]
ServiceResponse SetSettings(Settings settings);
[OperationContract]
SettingsAcceptedResponse SettingsAccepted();
}
You can try to create class called ServiceResponse<T> and with properties you need to have status and property of type T where will be real returned object.
Of course in this approach all your methods will return ServiceResponse<bool> when result will be of type bool
It may looks like this:
[DataContract]
public class ServiceResponse<T>
{
[DataMember]
ServiceStatus Status { get; set; }
[DataMember]
T Payload { get; set; }
}
This class could contain also messages to user, exceptions, erros and anything that could be usefull to handle properly response from WCF.
Then usage in WCF would be:
[OperationContract]
ServiceResponse<bool> SettingsAccepted();
I have a big MVC solution with multiple projects. I am planning to create a separate solution with WCF services and move some highly resource hungry projects. Idea is that the MVC application will communicate with WCF for any computational requirements.
The problem is I dont know how do I call the existing class and interfaces which already have interfaces to services. My class/interface:
public interface IHelloWorld
{
string SayHello(string name);
}
public class HelloWorld : IHelloWorld
{
public string SayHello(string name)
{
return string.Format("Hello, {0}", name);
}
}
There are 100s of methods in the class. Not all will be exposed to WCF only a few of them.
Now I have to call this class in newly created WCF service. I am not sure:
Do I have modify the existing classes to convert to svc.cs (service) or I can create a separate service file and call the existing methods there?
The service class also needs an interface which will be defined in web.config (endpoint contract). Do I have to create a separate interface with only methods I need to expose OR I have to use the existing interface in the class library? If I use the class interface, then I have to mention the same in web.config.
I am bit confused what should be the best way to doing it. I dont want to modify the existing class but want to add a new service which I can just hook up and call from there. new svc.cs files are:
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract]
string SayHello(string name);
}
public class HelloWorldService : IHelloWorldService
{
private IHelloWorld helloWorld = new HelloWorld();
public string SayHello(string name)
{
return helloWorld.SayHello(name);
}
}
This current design seems I am repeating the existing class/interface. Not sure if this is the correct way. Please help.
Do I have modify the existing classes to convert to svc.cs (service) or I can create a separate service file and call the existing methods there?
No, because you say that not all methods need to be exposed.
This current design seems I am repeating the existing class/interface. Not sure if this is the correct way. Please help.
Yes, it's repeating if you are doing like the code you show in the question.
You can write the code of your service like this;
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract]
string SayHello(string name);
}
public class HelloWorldService : IHelloWorldService
{
private IHelloWorld helloWorld = new HelloWorld();
public string SayHello(string name)
{
return helloWorld.SayHello(name);
}
}
By using the IHelloWorld contract on your service, you are not duplicating logics and only needed method will be exposed through HelloWorldService contracts.
I recently added a ping method to my service which calls a pong method on the callback channel:
public partial class myService
{
public void Ping()
{
OperationContext.Current.GetCallbackChannel<IKeepAliveEvents>().Pong();
}
}
I also added in the pong method to the callback interface:
namespace myService
{
[ServiceContract]
public interface IKeepAliveEvents
{
[OperationContract(IsOneWay = true)]
void Pong();
}
}
Which is inherited in my WCF service's main interface definition:
[ServiceContract]
public interface IMyServiceEvents : IEvents1, IEvents2, ..., IEvents9, IKeepAliveEvents
{
[OperationContract(IsOneWay = true)]
void TestEvent(string s);
}
And then used as follows:
[ServiceContract(CallbackContract=typeof(IMyServiceEvents)]
public interface IMyService : ISomething1, ISomething2, ..., ISomething13
{
...
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, MaxItemsInObjectGraph = 2147483647)]
public partial class myService : IMyService, IDisposable, IServiceBehavior, IErrorHandler {
...
}
The problem is...when my WCF service is running, it won't let me implement the pong method in my client application from the interface definition because it doesn't seem to exist each time I try to update the service...and for sure I am updating the correct service at the correct URL, and for sure I am using the latest build's code as I have been able to attach the debugger to my service and put a break-point into the Ping method where it calls Pong. Even more strange is that the Ping method does exist for my client to consume it, but the Pong method does not seem to want to show up here on the client:
public partial class myClientEndpoint : myServiceCallback {
// I would expect Pong to be implementable here.
}
What could the problem be?
The answer was actually that my ServiceContract for IKeepAlive (that encompasses the Ping method) did not reference its own callback contract to be IKeepAliveEvents...like so:
[ServiceContract(CallbackContract=typeof(IKeepAliveEvents))]
public interface IKeepAlive
{
[OperationContract(IsOneWay = true)]
public void Ping();
}
It wasn't enough to specify [ServiceContract(CallbackContract=typeof(IMyServiceEvents)] on MyServiceContract. Inheritance just doesn't work this way with WCF.
In my solution there's a few WCF services, each of them implementing it's own callback interface. Let's say they are called: Subscribe1, with ISubscribe1 and ICallback1, etc.
It happens there are a few methods shared among ICallbacks, so I made a following interface:
interface ICallback
{
[OperationContract]
void CommonlyUsedMethod();
}
and i inherited it in all: ICallback1 : ICallback, ICallback2 : ICallback, etc. And deleted the CommonlyUsedMethod() from all callback interfaces.
Now, on the service-side code, everything compiles fine and services can start working as usual. But, when I updated the service references for the client, CommonlyUsedMethod() dissapeared from the reference.cs file (the ISubscribeCallback part), and could no longer be used to send data to back to the client.
try to set the ServiceContract attribute on the base interface also.
Ok, this is the exact code, I condensed it as much as I can. Just start a new console application and copy/paste it. Start it and add a service reference to it. CommonlyUsedMethod() is not present in the reference, while the other methods are. Could it be framework 4?
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
namespace TestService
{
class Program
{
static void Main()
{
var serviceHost=new ServiceHost(typeof(Subscribe1), new Uri("net.tcp://localhost:8888"));
serviceHost.Description.Behaviors.Add(new ServiceMetadataBehavior());
serviceHost.AddServiceEndpoint(typeof(ISubscribe1), new NetTcpBinding(SecurityMode.None), string.Empty);
serviceHost.AddServiceEndpoint("IMetadataExchange", MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
serviceHost.Open();
Console.WriteLine("Working!");
while(Console.ReadKey(true).Key!=ConsoleKey.Escape) { }
}
}
[ServiceContract]
interface ICallbackBase
{
[OperationContract]
void CommonlyUsedMethod();
}
[ServiceContract]
interface ICallback1 : ICallbackBase
{
[OperationContract]
void SpecificMethod();
}
[ServiceContract(CallbackContract=typeof(ICallback1))]
interface ISubscribe1
{
[OperationContract]
void TestMethod();
}
[ServiceBehavior]
class Subscribe1 : ISubscribe1
{
[OperationBehavior]
public void TestMethod()
{
}
}
}
Does this reflect what you have in your code?
[ServiceContract]
public interface ICallbackBase
{
[OperationContract]
void CommonlyUsedMethod();
}
[ServiceContract]
public interface ICallback1 : ICallbackBase
{
[OperationContract]
void SpecificMethod();
}
This is essentially the structure I have in my production solution, and then I use the proxies that are generated when I add a Service Reference to access my methods from the client.
For reference, the generated interface then looks like this:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="MyNamespace.ICallback1")]
public interface ICallback1 {
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ICallbackBase/CommonlyUsedMethod", ReplyAction="http://tempuri.org/ICallbackBase/CommonlyUsedMethodResponse")]
void CommonlyUsedMethod();
}
Note the "ICallbackBase" in the OperationContractAttribute - it really does know where the method came from.
I'm not sure that what you are trying to do using WCF is possible. When you use inheritance in WCF you need to apply the KnownType attribute to the DataContract so that the DataContractSerializer will know to serialize it and make it available on the other end. Since you cannot put the KnownType attribute on interfaces, there is no way to tell the serializer that this is needed on the other end. Thus is does not show up when you implement it on the client.
I'm experimenting with WCF Services, and have come across a problem with passing Interfaces.
This works:
[ServiceContract]
public interface IHomeService
{
[OperationContract]
string GetString();
}
but this doesn't:
[ServiceContract]
public interface IHomeService
{
[OperationContract]
IDevice GetInterface();
}
When I try to compile the client it fails on the GetInterface method. I get an Exception saying that it can't convert Object to IDevice.
On the clientside the IHomeService class correctly implements GetString with a string as it's returntype, but the GetInterface has a returntype of object. Why isn't it IDevice?
You need to tell the WCF serializer which class to use to serialize the interface
[ServiceKnownType(typeof(ConcreteDeviceType)]
Thanks, it works when I changed it like this:
[ServiceContract]
[ServiceKnownType(typeof(PhotoCamera))]
[ServiceKnownType(typeof(TemperatureSensor))]
[ServiceKnownType(typeof(DeviceBase))]
public interface IHomeService
{
[OperationContract]
IDevice GetInterface();
}
I also got help from this site: http://www.thoughtshapes.com/WCF/UsingInterfacesAsParameters.htm
I initially tried to pass an interface to a WCF method but couldn't get the code to work using the answers provided on this thread. In the end I refactored my code and passed an abstract class over to the method rather than an interface. I got this to work by using the KnownType attribute on the base class e.g.
[DataContract]
[KnownType(typeof(LoadTypeData))]
[KnownType(typeof(PlanReviewStatusData))]
public abstract class RefEntityData : EntityData, IRefEntityData