I'm using 3-rd party COM service. It's exposed from .NET assembly. There are several interfaces this service provides that actually I can use in my C++ application (using early binding). Actually I would like to know if it's possible to pass custom data through using these interfaces, i.e. for me it's not enough what these interfaces provide and I want to add some additional data/methods there (though interface is not mine thus I can't change it). Please advice if it's possible, if not might be there're some workaround (example would be very helpfull)?
I'm trying to understand if it's possible to pass custom data from my producer to my consumer through 3-rd party COM service. Might be I need to create my own interface that includes my methods and that inherites 3-rd party ISomething and use it?
Below is the code that illustrates the problem. Many thanks for your help...
1) Class that I'm using to pass data from producer to consumer (through 3-rd party COM service):
//ISomething is 3-rd party interface with some limited # of data and methods
//Something is my class that will be used to pass data where ISomething is asked
//and it contains some methods that I need and they are not defined in ISomething
class Something: public CComObjectRootEx<CComSingleThreadModel>, public IDispatch
{
private:
bstr_t Name;
bstr_t MyData;
public:
//COM map omitted
//Method defined in ISomething
STDMETHOD(get_Name)(BSTR * pRetVal)
{
*pRetVal = ::SysAllocString(Name);
return S_OK;
}
//Method defined in ISomething
STDMETHOD(put_Name)(BSTR pRetVal)
{
Name = pRetVal;
return S_OK;
}
**//Method that is NOT defined in ISomething**
STDMETHOD(get_MyData)(BSTR * pRetVal)
{
MyData= pRetVal;
return S_OK;
}
**//Method that is NOT defined in ISomething**
STDMETHOD(put_MyData)(BSTR pRetVal)
{
MyData = pRetVal;
return S_OK;
}
}
2) My data producer fills the data and passes it to 3-rd party COM service
CComObject<Something> *Obj = NULL;
CComObject<Something>::CreateInstance(&Obj);
//Calling method defined in ISomething
Obj->put_Name(_bstr_t("Some data"));
**//Calling method that is NOT defined in ISomething**
Obj->put_MyData(_bstr_t("My data"));
//Passing data to COM service
CComPtr<ISomething> iObj;
Obj->QueryInterface(__uuidof(ISomething),(void **) &iObj);
CComPtr<ICommand> command = //init omitted, it's another 3-rd party object;
//Setting data
command->do(iObj);
3) My data consumer tries to get both defined and non-defined data but succeeds only in getting defined one, non-defined contains garbage
class SomethingEventSink : public CComObjectRootEx<CComSingleThreadModel>,
public IDispatch
{
//COM map omitted
STDMETHOD(SomethingEventHandler)(VARIANT sender, struct _SomethingEventArgs *args)
{
ISomething* obj;
Something* extObj;
args->get_Something(&obj);
BSTR Name, Name1, MyData;
//Works fine
obj->get_Name(&Name);
//Casting to my object pointer
extObj = reinterpret_cast<Something*>(obj)
//Works fine
extObj->get_Name(&Name1);
**//Works, but NO DATA I've set at producer step**
**//HOW TO MAKE IT WORK?**
extObj->get_MyData(&MyData);
return S_OK;
}
}
What your trying to do isn't possible the way you are doing it. However you may be able to get it to work if you can declare your own new interface?
In this case your object can implement ISomething & IMyInterface and you can define IMyInterface to have any new methods you want.
Related
I am trying to create a service that with an operation that accepts, as a parameter, an any object that implements a specific interface. I would have thought this would be easy to accomplish, but I am running into problems (what I am guessing to be serialization problems but I am not certain). I have the following contract:
//Unsustainable because I would need a method for each of the (currently)
//3 student types, plus I have 2 more root categories that have multiple subtypes
public interface IEmailTemplateAccess
{
[FaultContract(typeof(ValidationFault))]
[FaultContract(typeof(ErrorResponse))]
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
TemplateResponse GetStudentTemplate(ITemplateRequest request);
}
And this is what I would like it to look like:
public interface IEmailTemplateAccess
{
[FaultContract(typeof(ValidationFault))]
[FaultContract(typeof(ErrorResponse))]
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
TemplateResponse GetTemplate(ITemplateRequest request);
}
In my service I use an abstract factory to return the correct template based on the type of request that comes in. In addition, I have created concrete ITemplateRequests for the different kinds of templates that could be returned. For example, I have Template Request types A and B. Template Request Type A can have one of 3 sub types, SubType1, SubType2 and SubType3. I then created a SubType3 request that implemented the ITemplateRequest interface (SubType3Request).
I would hate to have to create a method for each request type I have (i.e. GetSubType1Template, GetSubType2Template, GetSubType3Template, GetTypeBTemplate, etc) as this would quickly become unwieldy as the types of templates I can get will be changing occasionally.
Is there a way to have a contract method accept anything that implements ITemplateRequest as a parameter and let my factory do the work of figuring out what type of template to get?
So far, I have the following methods in my service:
//Not a part of the contract right now although I would like it to be
public IEmailTemplate GetTemplate(ITemplateRequest request)
{
TemplateFactoryBuilder builder = new TemplateFactoryBuilder();
ITemplateFactory factory = builder.GetTemplateFactory(request.Type);
var template = factory.GetTemplate(request);
return template;
}
//contract method --This would be my Parent Request Type (RequestTypeA) from above.
//There are 3 subtypes of the Student type
public TemplateResponse GetStudentTemplate(StudentEmailTemplateRequest request)
{
var response = new TemplateResponse
{
RequiresProcessing = true
};
response.Template = (EmailMergeTemplate) GetTemplate(request);
return response;
}
Sorry for the link-ish answer, but it's pretty long.. What you're after (I think) is here: http://blogs.msdn.com/b/morgan/archive/2009/08/05/polymorphism-in-wcf.aspx
It boils down to using known types. Something like this;
[ServiceContract]
[ServiceKnownType("GetKnownTypes", typeof(CommandServiceHelper))]
public interface ICommandService
One of my WCF functions returns an object that has a member variable of a type from another library that is beyond my control. I cannot decorate that library's classes. In fact, I cannot even use DataContractSurrogate because the library's classes have private member variables that are essential to operation (i.e. if I return the object without those private member variables, the public properties throw exceptions).
If I say that interoperability for this particular method is not needed (at least until the owners of this library can revise to make their objects serializable), is it possible for me to use WCF to return this object such that it can at least be consumed by a .NET client?
How do I go about doing that?
Update: I am adding pseudo code below...
// My code, I have control
[DataContract]
public class MyObject
{
private TheirObject theirObject;
[DataMember]
public int SomeNumber
{
get { return theirObject.SomeNumber; } // public property exposed
private set { }
}
}
// Their code, I have no control
public class TheirObject
{
private TheirOtherObject theirOtherObject;
public int SomeNumber
{
get { return theirOtherObject.SomeOtherProperty; }
set { // ... }
}
}
I've tried adding DataMember to my instance of their object, making it public, using a DataContractSurrogate, and even manually streaming the object. In all cases, I get some error that eventually leads back to their object not being explicitly serializable.
Sure, write a wrapper class that has all of the same public properties available and simply put "get { return internalObject.ThisProperty; }. Decorate the wrapper class so that it works with WCF.
Another option is to write a Proxy class which mirrors the properties of the type you wish to use exactly, and return that via WCF.
You can use AutoMapper to populate the proxy object.
This approach has the advantage that your service's consumers don't need to take a dependency on the third party library in trying to use it.
I have a WCF service that will be called from a various clients.
Internally the WCF service uses an ISomething. There are multiple implementations of this interface and I need some clients to use one implementation and other clients to use a different implementation.
In addition, I am using Unity and an IoC container. I would typically set up a custom factory to allow the wcf service itself to be resolved along with its dependency graph, but if I have multiple implementations of a dependency, I do not think I can go with this approach and would have to resort to resolving the ISomething within the service (effectively using Unity as a service locator) which is not ideal.
So I need to work out
(1) how to specify which implementation of ISomething a client needs (eg. use a header, pass implementation string in each method, host multiple endpoints etc.)
(2) how Unity fits in?
One option is to write a Decorator that performs the selection for you:
public class RoutingSomething : ISomething
{
private readonly ISomeContext ctx;
private readonly ISomething s1;
private readonly ISomething s2;
private readonly ISomething s3;
public RoutingSomething(ISomeContext ctx)
{
this.ctx = ctx;
// An even better design would be to inject these too
this.s1 = new BarSomething();
this.s2 = new BazSomething();
this.s3 = new QuxSomething();
}
// Assuming ISomething has a Foo method:
public void Foo()
{
if(this.ctx.Bar())
{
this.s1.Foo();
return;
}
if(this.ctx.Baz())
{
this.s2.Foo();
return;
}
if(this.ctx.Qux())
{
this.s3.Foo();
return;
}
}
}
You could generalize this so that ISomeContext is simply an Abstract Factory of ISomething. This then begins to turn into the general solution to varying dependencies based on run-time context.
You can now register RoutingSomething in Unity in addition to your other components. When the container resolves the service, it'll inject an instance of RoutingSomething into it.
I have three WCF services (.svc) which generate .wsdl references for SOAP messages.
Given that part of the namespace needs to change for all ServiceContract, OperationContract, DataContract attributes, for example
[DataContract(Namespace = "http://old.com.au/types/")]
to
[DataContract(Namespace = "http://new.com.au/types/")]
How is it that I can still support clients which have the old service reference (without them needing to update, because maybe they wont have time to update immediately) and allow clients getting a new service reference to get the new namespace? None of the service is changing, just the namespace.
So far I have read a lot of stuff but the following article suggests it is possible to change the service type from the ServiceHostFactory : http://blog.ranamauro.com/2008/07/hosting-wcf-service-on-iis-site-with_25.html
Which would mean creating two of every contract (putting as much of the implementation as possible in one place), and figuring out at runtime which serivce type to use. This would create some mess in my scenario.
Q. Is there an alternative, nice way to accomplish this or is it expected that this kind of thing should not be done and the client made to update to the new namespace.
(If there is a namespace mismatch from the client I get the error : The message with Action "..." cannot be processed at the receiver, due to a ContractFilter mismatch)
IMO, you need to host old services for your previous clients at (preferably) old end points and have new services at new end points. You can take out old services when all your old clients migrate to newer version.
Perhaps, you can use inheritance to reduce your efforts, for example
[DataContract(OldNameSpace)]
ClassA {
...
}
[DataContract(NewNameSpace)]
ClassB : ClassA {
}
Similarly, create new service contract from inheriting from new one. Service implementation need not change expect it needs to implement new contract. Now you have to configure two end point - one for old contract and another for new contract.
Edit: Put sample interfaces and implementation
Let's say your old contract was something like
public interface IOldContract
{
ClassA GetFoo();
void DoBar(ClassA a);
}
Now you can choose the new contract either as
public interface INewContract
{
ClassB GetFoo();
void DoBar(ClassB b);
ClassB GetMix(ClassB a);
}
or as
public interface INewContract2 : IOldContract
{
ClassB GetFoo2();
void DoBar2(ClassB b);
ClassB GetMix2(ClassB b);
}
I tend to go with later variation (as new contract remains compatible with old one). But in your case, you can choose former as you will be anyway exposing two endpoints.
Now you need modify service implementation as follows:
public class ServiceImplementation : INewContract2
{
#region INewContract2 Members
public ClassB GetFoo2()
{
// Your old implementation goes here
}
public void DoBar2(ClassB b)
{
DoBar(b);
}
public ClassB GetMix2(ClassB b)
{
return GetMixHelper(b);
}
#endregion
#region IOldContract Members
public ClassA GetFoo()
{
return GetFoo2();
}
public void DoBar(ClassA a)
{
// You old implementation goes here
}
public ClassA GetMix(ClassA a)
{
return GetMixHelper(a);
}
#endregion
private ClassB GetMixHelper(ClassA a)
{
// Your old implementation goes here
}
}
I hope that you get the idea. Even here also you have multiple choices of code organization. You can have two skeleton service implementation classes - one for old contract and another for new contract. Both will delegate actually functionality to a helper class (which is your current implementation).
I know that a private parameterless constructor works but what about an object with no parameterless constructors?
I would like to expose types from a third party library so I have no control over the type definitions.
If there is a way what is the easiest? E.g. I don't what to have to create a sub type.
Edit:
What I'm looking for is something like the level of customization shown here: http://msdn.microsoft.com/en-us/magazine/cc163902.aspx
although I don't want to have to resort to streams to serialize/deserialize.
You can't really make arbitrary types serializable; in some cases (XmlSerializer, for example) the runtime exposes options to spoof the attributes. But DataContractSerializer doesn't allow this. Feasible options:
hide the classes behind your own types that are serializable (lots of work)
provide binary formatter surrogates (yeuch)
write your own serialization core (a lot of work to get right)
Essentially, if something isn't designed for serialization, very little of the framework will let you serialize it.
I just ran a little test, using a WCF Service that returns an basic object that does not have a default constructor.
//[DataContract]
//[Serializable]
public class MyObject
{
public MyObject(string _name)
{
Name = _name;
}
//[DataMember]
public string Name { get; set; }
//[DataMember]
public string Address { get; set; }
}
Here is what the service looks like:
public class MyService : IMyService
{
#region IMyService Members
public MyObject GetByName(string _name)
{
return new MyObject(_name) { Address = "Test Address" };
}
#endregion
}
This actually works, as long as MyObject is either a [DataContract] or [Serializable]. Interestingly, it doesn't seem to need the default constructor on the client side. There is a related post here:
How does WCF deserialization instantiate objects without calling a constructor?
I am not a WCF expert but it is unlikely that they support serialization on a constructor with arbitrary types. Namely because what would they pass in for values? You could pass null for reference types and empty values for structs. But what good would a type be that could be constructed with completely empty data?
I think you are stuck with 1 of 2 options
Sub class the type in question and pass appropriate default values to the non-parameterless constructor
Create a type that exists soley for serialization. Once completed it can create an instance of the original type that you are interested in. It is a bridge of sorts.
Personally I would go for #2. Make the class a data only structure and optimize it for serialization and factory purposes.