I am trying to pass an object into a WCF web service, the object I am passing in is a Server object, I then want to be able to call TestConnection();
The issue I am having is that Server is the base class and there are several derived classes of Server, i.e. SqlServer2005Server, OracleServer and ODBCServer that I want to use
I want to be able to pass in a Server Object and then determine its type, cast it and then use the method
public string TestServerConnection(Server server)
{
if (server.ConnectionType == "SqlServer")
{
SqlServer2005Server x = (SqlServer2005Server)server;
// Tests connection to server and returns result
return x.TestConnection();
}
return "";
}
'Server' the base class implements IServer
I am unable to cast it, can you advise?
Much Appreciated
Phill
As Daniel Pratt said, in the end, you are only shuttling XML (not always the case, but most of the time you are) across the wire.
If you used a proxy generator to generate the definition of the Server type, then you aren't going to be able to make calls on the methods of Server, because only properties (semantically at least) are used in the proxy definition. Also, you can't cast to the derived types because your instance is really a separate type definition, not the actual base.
If the Server type is indeed the same type (and by same, I mean a reference to the same assembly, not just in name and schema only), then you can do what Steve said and use the KnownType attribute on the Server definition, adding one attribute for each derived class.
However, like he said, that convolutes your code, so be careful when doing this.
I thought that using inversion of control would work here, but you run into the same situation with generic references to specific providers.
You need to add the KnownType declaration to your service contract for each derived class. There are ways to automate this (since it obviously convolutes code and breaks inheritance), but they require a lot of work.
Does the object you're passing represent a "live" connection to a DBMS? If the answer is yes, there is no hope of this ever working. Keep in mind that despite the pretty wrapper, the only thing your web service is getting from the caller is a chunk of xml.
Related
this is my first post, and I really have tried hard to find an answer, but am drawing a blank thus far.
My implementation of IDataContractSurrogate creates surrogates for certain 'cached' objects which I maintain (this works fine). What doesn't work is that in order for this system to operate effectively, it needs to access the service instance for some properties of the instance which it is maintaining from the interaction with its client. Also, when my implementation of IDataContractSurrogate works in its 'client mode' it needs access to the properties of the client instance in a similar way. Access to the information from the client and service instance affects how I create my surrogate types (or rather SHOULD do if I can answer this question!)
My service instancing is PerSession and concurrent.
On the server side, calls to GetDataContractType and GetDeserializedObject contain a valid OperationContext.Current from which I can of course retreive the service instance. However on the client side, none of the calls yield an OperationContext.Current. We are still in an operation as I am translating the surrogate types to the data contract types after they have been sent from the server as part of its response to the client request so I would have expected one? Maybe the entire idea of using OperationContext.Current from outside of an Operation invocation is wrong?
So, moving on, and trying to fix this problem I have examined the clientRuntime/dispatchRuntime object which is available when applying my customer behaviour, however that doesn't appear to give me any form of access to the client instance, unless I have a message reference perhaps... and then calling InstanceProvider. However I don't have the message.
Another idea I had was to use IInstanceProvider myself and then maybe build up a dictionary of all the ones which are dished out... but that's no good because I don't appear to have access to any session related piece of information from within my implementation of IDataContractSurrogate to use as a dictionary key.
I had originally implemented my own serializer but thats not what I want. I'm happy with the built in serializer, and changing the objects to special surrogates is exactly what I need to do, with the added bonus that every child property comes in for inspection.
I have also looked at applying a service behavior, but that also does not appear to yield a service instance, and also does not let me set a Surrogate implementation property.
I simply do not know how to gain access to the current session/instance from within my implementation IDataContractSurrogate. Any help would be greatly appreciated.
Many thanks,
Sean
I have solved my problem. The short answer is that I implemented IClientMessageFormatter and IDispatchMessageFormatter to accomplish what I needed. Inside SerializeReply I could always access the ServiceInstance as OperationContext.Current is valid. It was more work as I had to implement my own serialization and deserialization, but works flawlessly. The only issue remaining would be that there is no way to get the client proxy which is processing the response, but so far that is not a show stopper for me.
Bit confused with specifying a namespace for the service contract. Can understand with respect to a normal class,
My understanding about namespace
In normal OOPs model, say Employee class is part of Microsoft name space as well as Google name space. But since we may add reference to Google as well as Microsoft assembly in our project; hence to differentiate Employee's we have namespace, since when we say
Employee emp = new Employee()... compiler really doesn't really know which employee we are referring to?
Similarly, with respect to web service how does it matter? May I request an explicit example to explain the case please? For example
[ServiceContract(Namespace="Company.Matching.Algo")]
It's used - just like regular .NET namespaces - to keep things apart.
Having a namespace helps when you have multiple services that might end up all having similar methods exposed. With a namespace, they can all have a method called GetVersion or something, and the WSDL document will be able to keep them apart based on their namespace.
Also, namespaces are often used for versioning, so your first WCF service might have a service namespace of http://yourcompany.com/MyService/2011/08 and have five methods. If you later on introduce a v2 of your service, which might have 10 methods, and you put it into a separate namespace of http://yourcompany.com/MyService/2011/12 then you can keep those things separate - and an "old" client can still call the "old" service with (/2011/08) and use its method, while new clients can already call the new service with more capabilities.
From RebuildAll:
A note on namespaces: namespaces ARE NOT URLS!. They might look like one, like in my examples, but there is no such subdomain as schemas actually in existence. Namespaces follow the URI format, but are not actual addresses. They can be used to identify schemas, because usually a company owns a domain name. Thus using that as the schema namespace creates something unique. And that is exactly what namespaces should be: unique.
The namespace is important for serializing and deserializing objects.
In your example you can have the same Employee class on the server and client, and send an Employee object from one to the other over a web service. If the namespace is different it will be null when you deserialize on the otherside.
Suppose this simple scenario:
My client has an already working .net application and he/she wants to expose some functionality through WCF. So he gives me an assembly, containg a public class that exposes the followig method.
OrderDetail GetOrderDetail (int orderId) // Suppose OrderDetail has {ProductId, Quantity, Amount)
Now, I want some members of OrderDetail (Amount) not to be serialized.
According to http://msdn.microsoft.com/en-us/library/aa738737.aspx, the way to do this is by means of the [DataContract] and [DataMember]/[IgnoreDataMember] attributes. However, that's not an option for me because I can not modify client's source code. So I'm looking for a way to specify which members I want to serialize out, outside the type's definition. Something that should look like this:
[OperationContract]
[IgnoreMember(typeof(OrderDetail), "Amount" )]
OrderDetail QueryOrder(int orderId){
return OrderDetail.GetOrderDetail(orderId)
}
Is there any way to to this?
Thanks,
Bernabé
Don't send the clients objects across the wire, create a DTO from the clients object containing only the information that you want to send and send that instead.
This allows you to control exactly what information gets sent, and is in keeping with the WCF intentions of passing messages and not objects
So create an OrderDetailDto class and populate this with the data from the OrderDetail returned by the call to the method in the clients code. Decorate The OrderDetailDto with the DataContract and DataMember attributes (you can rename the class in here so that when it is returned by WCF it is returned with the name OrderDetail)
Repeat this for all objects in the client code, so that at the service boundary you basically convert from DTO->Client objects and Client Objects->DTO
EDIT
Whilst there might be an option which allows what you have asked for (I am not aware of one, but hopefully someone else might be) consider that when you send use your client objects as DTOs you are using them for two purposes (the client object and the message contract), which is against the Single Responsibility Principle and when you get them on the client side they will not be the same client side objects, just DTOs with the same properties, you will not be able to get behaviour in the client side objects (at least not without sharing libraries on the server side and client side).
By binding the data contract to the objects you also end up having to manage the changes to client objects and data contracts as one thing. When they are separate you can manage the changes to client side objects without neccessarily changing the DTOs, you can just populate the differently.
Whilst it seems like it is a lot of work to create the DTOs, in the end I think it will be worth it.
You will have to write a wrapper class that only exposes the desired properties and simply calls the class your client provided to gets its values.
The only other option would be to emit a new dynamic class using reflection and serialize that (see http://msdn.microsoft.com/en-us/library/system.reflection.emit.typebuilder.aspx), but its probably not worth the effort unless you need to build a lot of wrapper classes.
I am trying to use Generic DataContract class so that I don't have to implement several types for a collection of different objects.
Exp :
I have a Profile object which contains a collection of objects.
So I want to have one Profile<Foo> and Profile<Foo1> where profile contains a collection of Foo or Foo1 objects.
I have been reading that WCF does not support generic classes and actually the error that I get is the following.
Type 'GL.RequestResponse.ProfileResponse1[T]' cannot be exported as a schema type because it is an open generic type. You can only export a generic type if all its generic parameter types are actual types.`
Now the ProfileResponse is this Profile object that I am trying to use.
Now in my host I am doing the following. :
ServiceConfig(typeof(ProfileHandler<EducationResponse>).Assembly,
typeof(ProfileRequest).Assembly,
typeof(Container)).Initialize();
This is dhe definition of the handler with the datacontract.
public class ProfileHandler<T> : RequestHandler<ProfileRequest,
ProfileResponse<T>>
The Container is using Windsor Container to register the objects.
The registration works fine but after I instantiated the Service Host for WCF processor, and call Open Method of the host I get the above error.
Is there really no way for me to write generic response requests for wcf with agatha ?
It feels like such a waste to have to define a Profile container class for each type being contained in that collection.
thanks.
One cannot have open generic handlers, because the server side needs to know what the type is.
One can use so called closed generic methods. This way the server side knows the types for witch to load the handler.
Also, one could potentially configure Agatha so that it allows to receive extra information related to the request. In this case, it would be the type wrapped in the response.
One could do this by defining a a BaseRequest class and having all the request extend this class. This class can have a property which takes the type of the response. Or the type to be wrapped in the response.
In the process, when examining the request, the process can get the type to be wrapped in the Response, so that i knows how to load the class.
I have not implemented this, since it would take too much time and I am not sure I want to be responsible for maintaining Agatha for our application, but this is how I would do it.
If I have an object that holds the parameters for my method. I need to change the Object to have an additional property. I have full control over the server, but not over all of the clients. Will this change make those clients break?
I am using a self-hosted service with a binary endpoint.
I am new to WCF so my apologies if this is a silly question.
I guess you are asking about a class that represents your DataContract.
Learn about DataContract versioning and how various changes in your DataContract affect the compatibility in MSDN
In short the answer is No, it will not break the client code. The serialized graph of the data contract will deserialize to the available data members matching by their names and assigned through the property setter method. Obviously in this case, your newly added data member will not have value. Since you have full control on the server side code, you just have to make sure this newly added member need to be dealt in such a way that it is meaningful in the new implementation and allow for default/unassigned value.