I am designing a WCF service with callback, but my implementation of the callback function never gets called. And I am confused about the generated service proxy, so please help.
Here is the scenario: in the server side, I defined the service interface IMyService and callback interface IMyServiceCallback, I also implemented the IMyService in the server project. Besides the server project, I surely have another client project, to which I added the service reference in VS. And I implemented the IMyServiceCallback interface on the client side. So here comes the problem: when I am debugging it, the function never goes into my implementation of IMyServiceCallback and of course the desired result never comes out.
And this is I where I got confused: when I added the service reference in the client side, it actually generated three interfaces on the local: IMyService, IMyServiceCallback, and IMyServiceChannel plus the client proxy class. And in my local implementation of IMyServiceCallback, I declared the class to implement the local IMyServiceCallback interface, not the one from service side. Could this be the problem? Why is there two declarations of the interface under different projects(and hence different namespaces)? The reason I implement the client side interface is, if I implemented from the server side interface, it would give the error: "InstanceContext provided to the ChannelFactory contains a UserObject that does not implement the CallbackContractType error" when I tried to call the service. And another confusing part is, on the server side if I declare the callback interface name as IMyCallback, or anything else, instead of IMyServiceCallback, the generated interface on the client side would still be IMyServiceCallback, which is the name of the service interface plus the suffix "Callback". And in this situation I also got the "InstanceContext provided to the ChannelFactory contains a UserObject that does not implement the CallbackContractType error".
I guess there is something that I misunderstood about the "add service reference" and how I should implement the interface(which one to implement). Could anyone help me? Thanks!
Updated:
I somehow fixed the problem. Firstly, the two declarations is fine is desired. The local client will need to implement the local interface, which is generated when adding the service reference. And my problem was that I also defined a DataContract but the generated reference file didn't have it. It could either because I had added the assembly of the service project as reference(somebody said in this case add service reference will not generate the Datacontract) or because I was missing DataMember attribute. But anyway, after I fixed both parts, the function is working now.
When you "Add Service Reference" and generate a proxy, it is totally separate from your service implementation. Remember, you may be consuming a service that you have not written and do not have access to the service source code.
The client code should use the client generated interfaces. If you change your service, you need to regenerate the proxy.
If you find this too messy, and you know you will always control both ends, you can share the service interfaces in a common assembly and generate a proxy class at runtime using DuplexChannelFactory.CreateChannel().
As for your problem, I can only assume you are not registering your callback properly. This is covered here.
if you want publish , you must implement IMyServiceCallback and IMyService together in same project.
if only subscribe , you must implement IMyServiceCallback interface
I fixed the issue when my callback instruction was embedded in a function call.
I learned that placing the callback in just a method that does not return a result works fine.
However, when the callback instruction is placed within a function I ran into timeout issue.
I resolved it by using a backgroundworker thread within the function being invoked:
public static IMyServiceCallback Callback;
.
.
.
TaskStateData taskStateData = GetSomeData();
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += (se, ev) =>
{
Tuple<OperationContext, TaskStateData> data = ev.Argument as Tuple<OperationContext, TaskStateData>;
var operationContext = data.Item1;
if (operationContext != null)
{
Callback = operationContext.GetCallbackChannel<IMyServiceCallback>();
Callback.OnCallBack();
}
};
Tuple<OperationContext, TaskStateData> payload = new Tuple<OperationContext, TaskStateData>(OperationContext.Current, taskStateData);
backgroundWorker.RunWorkerAsync(payload);
Related
I'm consuming a WCF service in my project for which I've added the reference using 'Add Service Reference...'. I expected it to generate a clean proxy with a ServiceClient entity and the Interface. Instead, I see that it has created a MethodNameRequest, MethodNameRequestBody, MethodNameResponse, MethodNameResponseBody entities for each OperationContract method.
So while invoking the service methods, the proxy passes to the service method an instance of MethodNameRequest with the input parameters of the method as the properties of the RequestBody. See below an example of a call to AboutInformationGet() method which doesn't accept any parameters.
public WCFDynamicInvocation.PostingService.AboutModel AboutInformationGet() {
WCFDynamicInvocation.PostingService.AboutInformationGetRequest inValue = new WCFDynamicInvocation.PostingService.AboutInformationGetRequest();
inValue.Body = new WCFDynamicInvocation.PostingService.AboutInformationGetRequestBody();
WCFDynamicInvocation.PostingService.AboutInformationGetResponse retVal = ((WCFDynamicInvocation.PostingService.IMIGQPosting)(this)).AboutInformationGet(inValue);
return retVal.Body.AboutInformationGetResult;
}
I believe this behavior is what one would expect to see in a Webservice Proxy. Hence I suspect that the WCF service is not properly configured.
Did someone here face this issue? What would be the change to be done at the service so that the proxy generated is similar to the WCF service.
Cheers.
There is a similar post here.
Right click your service reference -> Configure service reference... -> Check if "Always generate message contracts" check box is checked. Uncheck it and hit OK to regenerate the proxy to see if you get a normal proxy.
After struggling with this for some time, I've finally found that the cause for the message contracts in the proxy was the service interface had the following attribute:
[XmlSerializerFormat(Use = OperationFormatUse.Literal, Style = OperationFormatStyle.Document)]
As I understand, I could decorate the DataContracts with the following attribute to avoid wrapping
[MessageContract(IsWrapped = false)]
but the response still gets wrapped as the OperationContract hasn't been modified.
As there were no particular need to use XMLSerializer in place of WCF's default DataContractSerializer, we would remove the XmlSeralizerFormat decoration.
Sorry for the long question in the first place. I would rather prefer to come up with a shorter question but this is the most stripped version I could provide that I can clearly explain my point.
I have been trying to deliver a wrapper service to our client which should provide multiple services in it. Idea behind it is to reduce multiple calls to a one call and return a single object which has other associated objects in it. To illustrate my point, let me give following example:
Let's say we have following services:
MyCompany.Services.Donation
MyCompany.Services.Payment
MyCompany.Services.PartialPayment
Normally client should query Donation service (with a donationID) to get donation information, and then using the retrieved donation information, they should query Payment service to get payment related details, and if the payment is done in multiple small payments, using retrieved payment information, they should query PartialPayment service to get all donation information for a particular Donor.
Instead of client doing this, I am going to provide a wrapper service to accept donationID as a single parameter and return a class similar to this:
[DataContract(Namespace = "http://MyCompany.Services.DonationDetail")]
public class DonationDetail
{
[DataMember]
public MyCompany.Services.Donation.Record donationRecord;
[DataMember]
public PaymentDetail paymentDetail;
}
[DataContract(Namespace = "http://MyCompany.Services.DonationDetail")]
public class PaymentDetail
{
[DataMember]
public MyCompany.Services.Payment.Record paymentRecord;
[DataMember]
public List<MyCompany.Services.PartialPayment.Record> partialPayments;
}
So an instance of DonationDetail record should return all relevant information with that donation.
My problem arises when I use these individual services DLL's* in my wrapper service since any class I pass to client using wrapper service becomes part of the wrapper service and client can't use them right away with the corresponding types they retrieved using service references without writing a custom construction method to convert one type to another - although they are same objects. Instead of referring classes in original namespace, service uses following classes something like that now for the classes mentioned above:
DonationDetail.Record (Donation Record - I would expect MyCompany.Services.Donation.Record)
DonationDetail.Record1 (Payment Record - I would expect MyCompany.Services.Payment .Record)
DonationDetail.Record2 (PartialPayment Record - I would expect MyCompany.Services.PartialPayment.Record)
Is there a way to provide such an interface without a custom constructor? So, if they use "PartialPayment" namespace for the MyCompany.Services.PartialPayment WCF service, can they do something below after DonationDetail is retrieved via wrapper service?
PartialPayment.Record partialPayment = dDetailObj.paymentDetail.partialPayments[0];
*: Don't ask me why I don't use service references unless that is the cause of the problem, since that option gives me other problems to me at this point)
So I think what you are saying, effectively, is that if you have two different services that return the same object and when you add this as two different service references to the client, even though ultimately they are the same object as far as the services are concerned (since they reference the same DLL), the client sees them as two different types so you can't take the object returned from one and send it as the input to the other service.
Assuming I have understood your question (and I apologise if I have not)...
You could map one type to the other by constructing it and setting the properties but that is really kind of a pain and not very friendly to the consumer etc, hence I am going to suggest something kind of radical...
Ditch the service references on the client.
Yup, I said it, why would I suggest such a thing!?! Here's why...
First of all I would make sure my project was structured something like this:
Donation Detail Client Library
IDonationService (this is the service contract - notice no implementation in the client library)
DonationRecord
Payment Detail Client Library
IPaymentService (this is the service contract - notice no implementation in the client library)
PaymentRecord
Partial Payment Client Library
IPartialPaymentService (this is the service contract - notice no implementation in the client library)
PartialPaymentRecord
Wrapper Service Client Library (which references the three other client libraries)
IWrapperService (this is the service contract - notice no implementation in the client library)
Incidentally, I gave your records different class names but you could use namespaces if you like and call them all Record (I think calling them different names is less confusing, but that is probably just me).
On the service end you reference the client library that you need to implement the service and do whatever you have to do just as you always have.
On the client you reference the client libary (or libraries depending on what service you want to call) too, in the same way (so you effectively have a shared library between server and client - yeah old skool, but hey, you will see why).
The client then has the interface for the service contract and all the data contracts so it does not need the whole service reference, generated code thing. Instead what you can do on your client is something like this:
DonationRecord donation;
using (var cf = new ChannelFactory<IDonationService>("EndpointNameInConfigurationFile"))
{
IDonationService donationservice = cf.CreateChannel();
donation = donationservice.GetDonation("Donation1234");
}
using (var cf = new ChannelFactory<IWrapperService>("EndpointNameInConfigurationFile"))
{
IWrapperService wrapperService = cf.CreateChannel();
wrapperService.DoSomethingWithDonation(donation);
}
There, you see I took the data contract from one service and sent it to a completely unrelated service and it looks natural (I have an object that is returned from a method on class X and I took it and passed it as an agrument on class Y, job done, just like programming).
NOTE: Using this technique will not stop service references from working just as they always have so any existing client code would not have to change, just if you use your new wrapper service, you could use it like this to save having to map types.
My use-case:
I already have a working ASP.NET application
I would like to implement a new Web Service as part of that application
I am supposed to use a WCF service (*.svc), not an ASP.NET web service (*.asmx)
The service needs to have one operation, let’s call it GetInterface(), which returns instance of an interface. This instance must reside on the server, not be serialized to the client; methods called on that interface must execute on the server.
Here’s what I tried (please tell me where I went wrong):
For the purpose of testing this, I created a new ASP.NET Web Application project called ServiceSide.
Within that project, I added a WCF Service using “Add → New Item”. I called it MainService. This created both a MainService class as well as an IMainService interface.
Now I created a new Class library project called ServiceWorkLibrary to contain only the interface declaration that is to be shared between the client and server, nothing else:
[ServiceContract]
public interface IWorkInterface
{
[OperationContract]
int GetInt();
}
Back in ServiceSide, I replaced the default DoWork() method in the IMainService interface as well as its implementation in the MainService class, and I also added a simple implementation for the shared IWorkInterface. They now look like this:
[ServiceContract]
public interface IMainService
{
[OperationContract]
IWorkInterface GetInterface();
}
public class MainService : IMainService
{
public IWorkInterface GetInterface()
{
return new WorkInterfaceImpl();
}
}
public class WorkInterfaceImpl : MarshalByRefObject, IWorkInterface
{
public int GetInt() { return 47; }
}
Now running this application “works” in the sense that it gives me the default web-service page in the browser which says:
You have created a service.
To test this service, you will need to create a client and use it to
call the service. You can do this using the svcutil.exe tool from the
command line with the following syntax:
svcutil.exe http://localhost:59958/MainService.svc?wsdl
This will generate a configuration file and a code file that contains
the client class. Add the two files to your client application and use
the generated client class to call the Service. For example:
So on to the client then. In a separate Visual Studio, I created a new Console Application project called ClientSide with a new solution. I added the ServiceWorkLibrary project and added the reference to it from ClientSide.
Then I ran the above svcutil.exe call. This generated a MainService.cs and an output.config, which I added to the ClientSide project.
Finally, I added the following code to the Main method:
using (var client = new MainServiceClient())
{
var workInterface = client.GetInterface();
Console.WriteLine(workInterface.GetType().FullName);
}
This already fails with a cryptic exception in the constructor call. I managed to fix this by renaming output.config to App.config.
I notice that the return type of GetInterface() is object instead of IWorkInterface. Anyone know why? But let’s move on...
Now when I run this, I get a CommunicationException when calling GetInterface():
The underlying connection was closed: The connection was closed unexpectedly.
How do I fix this so that I get the IWorkInterface transparent proxy that I expect?
Things I’ve tried
I tried adding [KnownType(typeof(WorkInterfaceImpl))] to the declaration of WorkInterfaceImpl. If I do this, I get a different exception in the same place. It is now a NetDispatcherFaultException with the message:
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:GetInterfaceResult. The InnerException message was 'Error in line 1 position 491. Element 'http://tempuri.org/:GetInterfaceResult' contains data from a type that maps to the name 'http://schemas.datacontract.org/2004/07/ServiceSide:WorkInterfaceImpl'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to 'WorkInterfaceImpl' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.
The InnerException mentioned is a SerializationException with the message:
Error in line 1 position 491. Element 'http://tempuri.org/:GetInterfaceResult' contains data from a type that maps to the name 'http://schemas.datacontract.org/2004/07/ServiceSide:WorkInterfaceImpl'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to 'WorkInterfaceImpl' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.
Notice how this seems to indicate that the system is trying to serialize the type. It is not supposed to do that. It is supposed to generate a transparent proxy instead. How do I tell it to stop trying to serialize it?
I tried adding an attribute, [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)], to the WorkInterfaceImpl class. No effect.
I tried changing the attribute [ServiceContract] on the IWorkInterface interface (declared in the shared library ServiceWorkLibrary) to [ServiceContract(SessionMode = SessionMode.Required)]. Also no effect.
I also tried adding the following magic system.diagnostics element to the Web.config in ServerSide:
<system.diagnostics>
<!-- This logging is great when WCF does not work. -->
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
<listeners>
<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\traces.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
This does generate the c:\traces.svclog file as promised, but I’m not sure I can make any sense of its contents. I’ve posted the generated file to pastebin here. You can view this information in a more friendly UI by using svctraceviewer.exe. I did that, but frankly, all that stuff doesn’t tell me anything...
What am I doing wrong?
The use-case I am describing is not directly supported by WCF.
The accepted work-around is to return an instance of EndpointAddress10 which points to the service for the “other” interface. The client must then manually create a Channel to access the remote object. WCF doesn’t properly encapsulate this process.
An example that demonstrates this is linked to from the MSDN article “From .NET Remoting to the Windows Communication Foundation (WCF)” (find the text that says “Click here to download the code sample for this article”). This example code demonstrates both .NET Remoting as well as WCF. It defines an interface that looks like this:
[ServiceContract]
public interface IRemoteFactory
{
IMySessionBoundObject GetInstance();
[OperationContract]
EndpointAddress10 GetInstanceAddress();
}
Notice that the interface-returning method is not part of the contract, only the one that returns an EndpointAddress10 is marked with [OperationContract]. The example calls the first method via Remoting, where it correctly creates a remote proxy as one would expect — but when using WCF it resorts to the second method and then instantiates a separate ChannelFactory with the new endpoint address to access the new object.
What is MainServiceClient()? It is the class marshaling the client messages to the server.
You should take a look at a related SO post on returning interfaces as parameters in WCF. ServiceKnownTypeAttribute may be helpful.
Sessions may also be what you're looking for MarshalByRef as it relates to .NET Remoting behaviors.
Another approach (as mentioned on MSDN Forums) is to return the EndpointAddress of the service interface instead of the interface itself.
WCF does serialize everything - regardless of the binding. The best approach you should take if you need to communicate with the service on the same system is to use IPC transport binding (net.pipe).
What you are trying to do is a direct violation of the SOA Tenet: "Services share schema and contract, not class". What this means it that you don't actually pass implementation code from the service to its consumers, just the return values that are specified in the contract itself.
The main focus of WCF and SOA in general is interoperability, meaning services should be accessible to clients of any platform. How would a Java or C++ consumer be able to use this service you are designing? Short answer is that it couldn't, which is why you will find it difficult if not impossible to serialize this code over messaging standards like SOAP.
A more appropriate way to structure this code would be to host each implementation of IWorkerInterface as its own service (it has been defined as a service contract, after all), and expose each service on a different endpoint. Instead of MainService behaving as remote factory for proxies to an IWorkerInterface, it could act a as an endpoint factory to the different services you have set up. Endpoint metadata could easily be serialized and provided to the client by IMainService. The client could then take that metadata and construct a proxy to the remote implementation, either through some custom IServiceProxy implementation, or even through the objects already provided to you by WCF (such as the ChannelFactory).
I have a web service that will be consumed by some application (web site currently).
The calls are almost all specific to a certain client but still the same. So one call might be getAllFoo() but I would need some parameter to say from which client the Foo is.
It would become bothersome quickly if I just add a standard parameter to all calls so I was hoping to do it a little bit DRY and automatic. Something that would be included in all service calls.
Is IDispatchMessageInspector the right thing for me here? What kind of info could that include and can I access that info inside the methods?
Should I create some sort of attribute perhaps for the calls?
If anyone could point me towards a solution for this it would be great.
Edit
Another solution I'm thinking off.
Where the service call to a specific client happens on the consumer side, it will be known at instanceCreation so I could instance the ServiceClient with a known client.
Could I use this solution for the ClientBase<> extender somehow.
Let's say I'm serving Domain1 (let's call the client Domain to not confuse it with a serviceclient/consumer) I create a InformationProvider consumer side that has a ClientBase<IInformationService> field. I ensure that the DomainName (domain1) is set at construction so I could parhaps do the same thing when instancing the ClientBase<IInformationService> so It somehow let's the service know what domain I'm calling for.
I'm just still learning about WCF so I'm not sure how one would do this.
I can understand that you want to keep you solution simple and tidy, but ultimately - as you say yourself -
... I would need some parameter to say from which client...
The obvious and simplest solution is to include a client parameter on all your service calls where it is required. Surely there'll be service calls that don't require the client parameter, and in those cases you don't need to include the parameter.
You may be able to do something clever where a client identifier is passed discreetly under the covers, but beware of doing unnecessarily clever things. I would pass the client as a simple parameter because it is being used as a parameter. Two reasons come to mind:
if someone maintains your code they quickly understand what's going on.
if someone needs to use the service it is obvious how to use it.
A possible pattern:
Make sure you service instantiates per session. This means you'll have to use wsHttpBinding, netTcpBinding, or a custom binding as http does not support sessions.
Always call an initialization operation when each session is instantiated that sets the client id for that service.
Put this initialization operation inside a constructor for a proxy.
The steps involved would be something like this:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class MyService : IMyService
{
private int clientId;
public void StartUp(int clientId)
{
this.clientId = clientId;
and then client side, assuming you use the generated proxy, wrap the client inside another proxy.
public class ExtendedClient : MyServiceClient
{
public ExtendedClient(int clientid) : base()
{
this.StartUp(clientid);
}
Now you should instantiate the ExtendedClient, it will create the channel and prime the service by delivering the client id.
I would personally prefer to simply send the client id for each service call, but if you are able to use a session-able binding then this should work.
Just some information on WCF for you. If you have a stateless service, then you'll need to include the client as a parameter in every service call. This does not mean you need to include the client everywhere throughout your code - you could, for example, retrieve it inside the ClientBase constructor. But you will need to add it to every OperationContract and all the service implementations.
The alternative is to have a stateful service - the instance that you first use will remain for you to reuse (except for timeouts / exceptions). In this case you can potentially send the client just once, and then the service will know about the client for subsequent calls. This is the pattern described above. It means that you cannot use http binding. I believe that by doing this you're only increasing the potential for problems in your application (stateful services, having to ensure the initialization operation completes, more service calls being made).
Adding a service reference to a web service (this is all WCF) in Visual Studio produces some generated code including a client-side restatement of the interface being exposed.
I understand why this interface is generated: you might be consuming a 3rd party service and not have access to the actual interface.
But I do, and the two are not assignment compatible even though the transparent proxy does indeed exactly implement the interface to which I want to cast.
I can use reflection, but that's ugly. Is there some way to defeat this faux type safety and inject metadata to so I can use an interface with a class?
My specific problem departs from the norm in complicated ways that have to do with a single client that uses some derivatives of a base class directly and uses others remotely via service references. The base class for each server needs to keep references to subscribing clients in a collection for enumeration to notify events, and the problem was type varied due to the use of proxies.
None of these answers solves my specific problem, yet every single answer was instructive and helpful. I found my own solution (use a dual binding) but I would never have figured it out if you hadn't radically improved my understanding of the whole business.
Three excellent answers. How to choose just one? I choose the first, because it directly solves the problem I first thought I had.
If you already have the contract dll at the client, you don't even need a service reference (unless you are using it to write the setup code for you) - you can simply subclass ClientBase and expose the Channel, and use that directly - something like (no IDE handy...):
public class WcfClient<T> : ClientBase<T> where T : class
{
public new T Channel {get {return base.Channel;}}
}
Then you can just do things like:
using(var client = new WcfClient<IFoo>())
{
client.Channel.Bar(); // defined by IFoo
}
You still need the configuration settings in the config to determine the address, binding, etc - but less messy than proxy generation. Also, you might choose to re-implement IDipsoable to deal with the fact that WCF proxies can throw in Dispose() (which is bad):
public class WcfClient<T> : ClientBase<T>, IDisposable where T : class
{
public new T Channel {get {return base.Channel;}}
void IDisposable.Dispose() {
try {
switch(State) {
case CommunicationState.Open: Close(); break;
// etc
}
} catch {} // swallow it down (perhaps log it first)
}
}
When you add the service reference, go to "Advanced" and make sure "Reuse types in referenced assemblies" is selected and that the assembly containing your interface definition is selected. You can also do this with an existing service reference by right clicking on it and going to "Configure".
In order to return an interface from a service you need to use the KnownType attribute:
http://weblogs.asp.net/avnerk/archive/2006/07/31/WCF-Serialization-part-1_3A00_-Interfaces_2C00_-Base-classes-and-the-NetDataContractFormatSerializer.aspx
If you want to return a custom type from the service:
http://msdn.microsoft.com/en-us/library/bb628653.aspx
Does any of that help?