Reputation: 1409
I have a WCF service which exposes a Generic interface (and the service has a generic class implementing this interface).
Then i try to host this service in a managed console app (just for testing purposes right now). The ThreadStart line results in error saying type for T not found.
Now i cannot make Main generic by doing Main< T >(string[] args) where T: IComparable< T > because then it says, Main entry point not found.
My question is how to handle this case in general ?
// Service Hosting app
static void Main(string[] args)
{
new Thread(new ThreadStart(StartBSTService<T>)).Start();
}
static void StartBSTService<T>() where T : IComparable<T>
{
string baseAddress = "http://localhost:8080/bst";
StartAService(typeof(BSTService<T>), baseAddress);
}
EDIT: Adding the Service class as well
[ServiceContract(Namespace = "http://Microsoft.Samples.GettingStarted")]
public interface IBSTService<T> where T : IComparable<T> //: ICollection<T>
{
[OperationContract]
void Add(T toAdd);
// For brevity, not providing all other methods
// but they are similar IColleciton methods.
}
public class BSTService<T> : IBSTService<T> where T : IComparable<T>
{
BinarySearchTree<T> tree = new BinarySearchTree<T>();
public void Add(T toAdd)
{
tree.Add(toAdd);
}
}
Client will use it like you will use any generic type:
BSTService<string> client = new BSTService<string>;
// OR
BSTService<int> client = new BSTService<int>;
EDIT2: @asawyer's point seems logical, that Main is consumer of generic class, so it should provide the type, but then do i have to start a new endpoint for every type ? and how to handle that. Like i can write a service wrapper which exposes only one method say INIT(Type typeOfBST). client calls this to tell the service that he wants to initiate either int or string BST. and then client calls the real methods with given type and the service channels those calls to different endpoints each of which is exposing a differently typed BST.
How to handle such cases in general ?
Upvotes: 3
Views: 2738
Reputation: 364399
When you host the service you cannot use open generics. You must specify concrete type to host concrete service. If you want to host services for more generic arguments you must indeed create a new host for each argument type and expose an endpoint with an unique address for each of them. Once the service is hosted it must be able to say what types it accepts and describe them in the service description (source for WSDL).
WCF works on basis where you host the service which must be able to describe messages it accepts - because of that it generates service description. Service is able to serialize messages according to the description. Any client on any platform can use the description and send the correct message to the service - client will know about allowed content of the message from the description and because of that service host must use the concrete type - not T.
You can overcome this by specifying base type as generic argument but even after that your service must know about all derived types which can be used instead of the base type (there are multiple techniques for this but none of them offer random type).
Edit:
Technically what you ask for means: send the name of the type from the client to the main service. The main service will check if the service with the type already exists. If yes it will send the url of the service back to the client. If not it will creates the service via reflection and starts it. It will store information about new hosted service and sends the url back to the client.
Another variant is starting all services upfront and having single WCF Routing service which will route request to correct service.
Such solutions look like maintenance nightmare and the first one will have much worse performance because two network calls will be needed for each operation. Also it is not generally interoperable because your clients will have to get generic contract upfront to be able to call such services. Simply don't do it - define finite set of used classes and use KnownType
or DataContractResolver
with single service.
Upvotes: 5
Reputation: 17808
When you declare an instance of the generic type you have to provide a non generic type parameter, ie
interface ITest { }
class Test<T> where T : ITest { }
You can't just say:
var test = new Test<T>();
T doesn't many any sense in this context, you need a more concrete type:
class ImplementsITest : ITest { }
var test = new Test<ImplementsITest>();
In your example, you need to provide a type when declaring the instance in Main()
static void Main(string[] args)
{
new Thread(new ThreadStart(StartBSTService<SomeTypeThatActuallyExists>)).Start();
}
What does BSTService do with the generic type? That will determine which types are valid parameters.
Upvotes: 1