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
Related
I'm trying to create an abstract proxy for several interfaces. Obviously both a concrete proxy implementation and the concrete proxied class it 'fronts' must implement the same interface. The proxy accepts the proxied class (to proxy to). Ideally I wouldn't constrain the interfaces at all but I don't believe C# allows constraining a generic type to being an interface. As such, my sample below uses IProxiableInterface to enforce.
Here's some sample code that all appears fine except for this problem:
Without the parent class, Rider complains "'T': type name expected"
With the parent class, Rider says "'T': interface name expected".
For both, the compiler says "error CS0689: Cannot derive from 'T' because it is a type parameter"
Both of them allow the concrete proxy to fail to implement the interface.
abstract class AbstractProxy<T> : /*MonoBehaviour,*/ T // <-- Error: "'T': type name expected" or "'T': interface name expected"
where T : IProxiableInterface
{
protected T impl;
public AbstractProxy(T impl) {
this.impl = impl;
}
}
interface IProxiableInterface {}
interface IFriendly : IProxiableInterface {
string sayHi();
}
sealed class HiSayer : IFriendly {
public string sayHi() => "Hi";
}
sealed class HiProxy : AbstractProxy<IFriendly> {
public HiProxy(IFriendly impl) : base(impl) {}
public string sayHi() => impl.sayHi(); // <-- _should_ be an error when omitted but not because the interface constraint is ignored
}
sealed class User {
public User() {
IFriendly friendlyToBeProxied = new HiSayer();
IFriendly friendlyProxy = new HiProxy(friendlyToBeProxied);
Console.WriteLine(friendlyProxy.sayHi());
}
}
So it seems C# disallows this approach (which I learnt after typing all of this into StackOverflow and getting hinted with this question :) ).
For now I've had to remove the constraint on AbstractProxy so it doesn't have to implement the interface. As a workaround I've added an assertion to a factory method that takes an extra generic type indicating the type being built:
Assert.IsTrue(typeof(T1).IsAssignableFrom(typeof(T2)), "T2 \"{1}\" must implement T1 \"{2}\" for {0}", go, typeof(T2), typeof(T1));
So what's a better solution The Right Way to solve this, please?
This is the kind of scenario that requires meta-programming; specifically, you need to implement a specific interface only known at runtime, which isn't something you can express against a pre-compiled type. Typically, you would end up using TypeBuilder to create a new type at runtime, implementing the type you need, and then using reflection to inspect the interface you want looking for the members you need, adding those onto your new type (MethodBuilder etc), and writing an implementation (ILGenerator) that invokes whatever proxy logic you need (which may involve writing a constructor via ILGenerator that takes the proxy instance as a parameter and stores it in a field, then access the field in each method for the proxy step). You'd then create the concrete type, and store that somewhere as a cache (because all this TypeBuilder work is expensive). This is a lot of work! As a starting point: here's the proxy emitter for protobuf-net.Grpc
Looks like you want your AbstractProxy to use composition rather than inheritance, so you don't need it to derive from anything:
abstract class AbstractProxy<T> where T : IProxiableInterface
{
protected T impl;
public AbstractProxy(T impl)
{
this.impl = impl;
}
}
IProxiableInterface defines no behaviour so it seems that you are using it simply to constrain the generic types.
This would then be fine:
sealed class HiProxy : AbstractProxy<IFriendly>
{
public HiProxy(IFriendly impl) : base(impl) {}
public string sayHi() => impl.sayHi();
}
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.
This error comes as result of This previous question. I'm trying to call a polymorphic method from WCF client. This is my contract:
public interface IOhmioService
{
[OperationContract]
IEnumerable<Enumerador> GetEnumerador<T>() where T : IEnumerador, new();
}
This is my class implementation:
public class OhmioService : IOhmioService
{
public IEnumerable<Enumerador> GetEnumerador<T>() where T : IEnumerador, new()
{
T _obj = new T();
return _obj.Enumerar();
}
}
And call it from client like this:
public IEnumerable<Enumerador> Clients { get; set; }
Clients = this.serviceClient.GetEnumerador<Clientes>();
If i call this method from within the class everything works fine. But if i call it from WCF client a get this error:
The non generic Method 'Ohmio.Client.OhmioService.OhmioServiceClient.GetEnumerador()'
cannot be used with types arguments
What i'm i doing wrong? Thanks!
UPDATE
Ok. I try suggested solution, and get this Horrible error:
Type 'System.RuntimeType' wasn't spected with the contract name RuntimeType:http://schemas.datacontract.org/2004/07/System'. Trye to use DataContractResolver or add the unknown types staticaly to the list of known types (for instance, using the attribute KnownTypeAttribute or adding them to the list of known types to pass to DataContractSerializer)
Maybe using generic types over wcf is not such a good idea after all. I was trying to reduce repetitive code on the WCF service.
You cannot have generic OperationContract methods in a WCF ServiceContract. See here for further details: WCF. Service generic methods
You need to pass the type as a method parameter:
public interface IOhmioService
{
[OperationContract]
IEnumerable<Enumerador> GetEnumerador(string typeName);
}
public class OhmioService : IOhmioService
{
public IEnumerable<Enumerador> GetEnumerador(string typeName)
{
var type = Type.GetType(typeName);
var _obj = (IEnumerador)Activator.CreateInstance(type);
return _obj.Enumerar();
}
}
UPDATE
See update above; pass the fully qualified name of the type. That won't cause a serialization issue.
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.