wcf exposing generics

不羁的心 提交于 2019-12-07 04:51:02

问题


I have an application where client and server share types, and interoperability is not one of our concerns. I am planning to have a single repository for all web enabled objects, and i was thinking of a generic interface for my exposed service.

something like T GetObject(int id)

but wcf doesnt like it since its trying to expose its schema (which i dont really care about)

is it possible to do such a thing with WCF ?, i can use any type of binding doesnt have to be httpbinding or wsbinding...


回答1:


I suppose this is possible, though I'm not sure you'd want this. I'd take the following approach (untested, not sure if it works). First create the following project structure in your solution:

  • ServiceInterfaces
  • ServiceImplementations (references ServiceInterfaces and ModelClasses)
  • ModelClasses
  • Host (references ServiceInterfaces and ServiceImplementations)
  • Client (references ServiceInterfaces and ModelClasses)

In ServiceInterfaces you have an interface like this (I skipped the namespaces, etc to make the example shorter):

[ServiceContract]
public interface IMyService<T>
{
    T GetObject(int id);
}

In ServiceImplementations you have a class that implements IMyService<T>:

public class MyService<T> : IMyService<T>
{
    T GetObject(int id)
    {
        // Create something of type T and return it. Rather difficult
        // since you only know the type at runtime.
    }
}

In Host you have the correct configuration for your service in an App.config (or Web.config) file and the following code to host your service (given that it is a stand-alone app):

ServiceHost host = new ServiceHost(typeof(MessageManager.MessageManagerService))
host.Open();

And finally in Client you use a ChannelFactory<TChannel> class to define a proxy:

Binding binding = new BasicHttpBinding(); // For the example, could be another binding.
EndpointAddress address = new EndpointAddress("http://localhost:8000/......");
IMyService<string> myService =
    ChannelFactory<IMyService<string>>.CreateChannel(binding, address);
string myObject = myService.GetObject(42);

Again, I'm not sure if this works. The trick is to share your service interfaces (in ServiceInterfaces) and domain model objects (in ModelClasses) between the host and the client. In my example I use a string to return from the service method but it could be any data contract type from the ModelClasses project.




回答2:


No, you can't. Whether or not you want or need interoperability, the most basic foundation of WCF is message exchange.

The client send the server a message and gets back a response. That message is all that passes between client and server, and needs to be serializable into a XML or binary format. That's why any data being passed around must be atomic (like int, string) or a DataContract - a description for the WCF service stack about how to serialize and deserialize such objects.

You cannot pass any interfaces, or other "trickery" - all that goes between client and server must be expressable in XML schema, basically.

So I'm afraid what you're trying to achieve is quite contrary to what WCF offers. The world and paradigms of SOA (Service-Oriented Apps) are quite different and not always 100% in sync with the idea and mechanisms of OOP.

Marc




回答3:


You CAN DO that if you use ServiceKnownTypesDiscovery.

For example:

[ServiceKnownType("GetKnownTypes", typeof(ServiceKnownTypesDiscovery))]
public interface ISomeService
{
    [OperationContract]
    object Request(IRequestBase parameters);
}

where GetKnownTypes could be declared like so:

public static class ServiceKnownTypesDiscovery
{
    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
    {
        var types = new List<Type>();

        foreach (var asmFile in Directory.GetFiles(AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory, "*.dll"))
        {
            Assembly asm = Assembly.LoadFrom(asmFile);
            types.AddRange(asm.GetTypes().Where(p=> Attribute.IsDefined(p,typeof(DataContractAttribute))));
        }

        return types;
    }
}

In this case everything declared with [DataContract] (as long as they are discoverable on the server AND the client side) can be serialized.

I hope this helped!




回答4:


Following the previous example, you could declare a DataContract with an object as DataMember. Then you could add an extension method to get and set a generic type on the object data member. You could also make this internal, this way you would be obliged to use the extension methods to get and set the value.

Of course, it only works if you generate the client using svcutil (or Visual Studio) and you reference the assembly containing the data contract and the class with the extensions methods.

Hope this helps...



来源:https://stackoverflow.com/questions/1359056/wcf-exposing-generics

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!