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.
Related
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.
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 have an asp.net mvc application and need to call wcf service in it. I've added service reference to the project. I use unity for dependency injection and want to inject wcf client. But it's not so simple because of System.ServiceModel.ClientBase. I did it this way.
This is an autogenerated proxy:
public partial class WcfServiceClient :
System.ServiceModel.ClientBase<WcfUnity.IWcfServiceClient>,
WcfUnity.IWcfServiceClient
{
//autogenerated constructors and methods
}
I created interface:
public interface ISimpleProxy : WcfUnity.IWcfServiceClient
{
//duplication of methods' signatures
void CloseConnection();
}
I extended WcfServiceClient using partial class:
public partial class WcfServiceClient : ISimpleProxy
{
public void CloseConnection()
{
try
{
Close();
}
catch (Exception)
{
Abort();
}
}
}
And inject it like this:
container.RegisterType<ISimpleProxy>(new InjectionFactory(c => new WcfServiceClient()));
So I don't have dependecies from ClientBase and there is no wcf stuff inside classes which use this wcf proxy. Does this solution have some disadvatages?
No, it doesn't, I use (mostly) the same approach.
I would recommend you making your interface inherit from IDisposable, because underlying ClientBase<T> is disposable. This way you won't need CloseConnection.
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.
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