Problem in consuming WCF service (basicHttpBinding) in Delphi Win32 Client - wcf

I am trying to make a Delphi client (Delphi 2006) to communicate with a service written using WCF. Service is damn simple with just one function. Technically like below:
[ServiceContract (Namespace = "http://www.company.com/sample/")]
public interface IService
{
[OperationContract]
string GetNumber (string name);
}
I have hosted this service on IIS and exposed it using basicHttpBinding with mex end point. I am able to use it in .NET clients.
I tried to run WSDLImp.exe and it generated a source code unit (btw, it generates wierd classes to encapsulate string type. Why cant it be same as Delphi string type?). When I try to call this service, I get the exception:
The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
I don't see any way to configure the Delphi Win32 client to changing the binding or security parameters. How can I fix this problem?

I've had the exact same problem. Delphi just has hard time importing the WSDL exposed by WCF. One solution is to add an ASMX wrapper to your service and use that with Delphi clients.
Here's an example:
[ServiceContract (Namespace = "http://www.company.com/sample/")]
public interface IService
{
[OperationContract]
string GetNumber (string name);
}
public class Service : IService
{
public string GetNumber (string name)
{
return Repository.GetNumber(name);
}
}
[WebService(
Namespace = "http://www.company.com/sample/",
Name = "wstest",
Description = "description")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class AsmxService : WebService
{
[WebMethod]
public string GetNumber(string name)
{
return Repository.GetNumber(name);
}
}

You need to look at the network traffic between the client and service to see what's going on. Alternatively, turn on WCF tracing on the service, possibly including message tracing. You should be able to see what's going on, in great detail.

Related

Configure WCF to deserialize arrays as collections without svcutil

I have a net.tcp WCF service and its client, each in one assembly and sharing another assembly containing the service interface and DTOs.
The client is implemented as a proxy to the service using a Channel instantiated through ChannelFactory:
public ServiceClient : IService
{
IService _channel;
public ServiceClient()
{
_channel = new ChannelFactory<IService>("NetTcp_IService")
.CreateChannel();
}
public DTO ServiceMethod()
{
return _channel.ServiceMethod();
}
}
public class DTO
{
public IList<int> SomeList;
}
As expected, the SomeListfield of the DTO returned by the client is an array but I would like it to be converted by WCF to a List. As you may suspect from the described set-up, I don't use svcutil (or the Add Service Reference dialog for that matter), so I can't use configureType.
I don't want to modify the client proxy to instantiate the List and modify the received DTO in my client proxy because the actual implementation uses a command processor using interfaces resolved through dependency injection at run-time to avoid coupling - and this solution would do the opposite, by requiring the client to perform know service commands.
Therefore, I'm currently using the work-around which modifies the DTO to internally create the List instance:
public class DTO
{
private IList<int> _someList;
public IList<int> SomeList
{
get { return _someList; }
set {
if (value != null)
_someList = new List<int>(value);
else
_someList = new List<int>();
}
}
}
However, I'd rather avoid this. So the question is:
How can I configure the WCF deserialization so that the array is converted to the expected List?
Is there any way to configure the deserialization through the binding either in the App.config or from code upon Channel creation? Maybe through ImportOptions.ReferencedCollectionTypes or CollectionDataContract?
There are 4 ways:
Convert data to List in your save methods on Client side
Change property type:
public IList<int> SomeList;
to
public List<int> SomeList;
Approach you have shown above (changing type on assigment).
Implement IDataContractSurrogate. But you will have to apply a behaviour on client side.

Calling a Web Service using WCF channel Factory.Is it possible?

In the project I am working on I need to call webservices (asmx).I would like to call them using wcf and using the channelfactory(No adding service Reference).
Some might have an interface(contract)many dont.
Is there an end to end example how to do it?
var service=ChannelFactory<?>... How do I get the webserviceContract.
Surely this must be a common scenario to be able to call a webservice (asmx)
Thanks for your time
To expand upon my comment, you should be able to create an interface that has methods that match the web service methods in the asmx service. For example:
Web Service Methods
string GetMessage()
void SendMessage(string message)
int AddNumbers(int x, int y)
Service Contract
[ServiceContract]
public interface IServiceName
{
[OperationContract]
string GetMessage();
[OperationContract]
void SendMessage(string message);
[OperationContract]
int AddNumbers(int x, int y)
}
ChannelFactory
ChannelFactory<IServiceName> serviceFactory =
new ChannelFactory<IServiceName>(new BasicHttpBinding(),
"http://www.services.com/Service.asmx");
Not 100% sure this will work, but it would be easy to try out. Also, you'd probably want to set the namespace on the service contract ([ServiceContract(Namespace = "somenamespace")]) to match the legacy asmx service, otherwise the messages might not get processed.

WCF Msmq problem reading messages using netMsmqBinding

I have a WCF service using netMsmqBinding that I am using to add messages of Msmq<string> to a queue. The messages are added fine and I can see them in the queue via the computer management console.
I have another WCF service that is trying to retrieve the messages from the queue, this is where I'm having a problem. My method in my service is getting called whenever a message is added to the queue (that bit is working fine) but the Msmq<string> message seems to have all null values.
I'm not sure how I can get the message from that Msmq<string>? Here is my service details... any help appreciated..
[ServiceContract]
[ServiceKnownType(typeof(Msmq<string>))]
public interface IMessageListener
{
[OperationContract(IsOneWay = true, Action = "*")]
void ListenForMessage(Msmq<string> msg);
}
public class MessageListener : IMessageListener
{
[OperationBehavior(TransactionScopeRequired = false, TransactionAutoComplete = true)]
public void ListenForMessage(MsmqMessage<string> msg)
{
//this gets called and seems to remove the message from the queue, but message attributes are all null
}
}
I think you're not quite "getting" the idea of WCF over MSMQ.
When using WCF with the netMsmqBinding, the whole idea is that you don't need to deal with the details of MSMQ - let the WCF runtime handle that!
So basically, your approach should be as with any WCF service:
define your service contract and its methods (operation contract)
define your data structures as a [DataContract] and use those in your service methods
implement the service
So your service should be something like:
[DataContract]
public class Customer
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Name { get; set; }
...
}
[ServiceContract]
public interface ICustomerService
{
[OperationContract(IsOneWay=true)]
void SaveCustomer(Customer myCustomer)
[OperationContract(IsOneWay=true)]
void CreateCustomer(int ID, string name);
}
You should have a data contract to describe your data - just your data, no MSMQ details needed here! Then you should have one set of service methods that will deal with the Customer object - you can put it into the queue for storing, create a new one etc.
You would then implement the client and the server side for this service contract, and the WCF runtime will handle all the details of MSMQ transport, putting the payload (the Customer object) into a MSMQ message and getting it back out again and so on... you don't have to deal with that, really.

Send information in Soap Header to WCF service in C#

i want a web application to create a service reference to my WCF service, insert information to the header of the soap call and call my WCF method.
i read about MessageContract attribute and declared one in the interface file:
[MessageContract]
public class BasicServiceHeader
{
[MessageHeader]
public string myString;
}
my WCf interface is:
[ServiceContract]
public interface IBasicService
{
[OperationContract]
[WebGet(UriTemplate = "GetData?value={value}")] // Add support for HTTP GET Requests
string GetData(int value);}
i don't want the BasicServiceHeader to be passed as a parameter of GetData function , i want to keep the function as it is and to extract the BasicServiceHeader inside the function, can i do that ?
Client side, you can pass a header prior invoking the operation:
MessageHeader messageHeader = MessageHeader.CreateHeader(_headerName, _headersNameSpace, _headerValue);
OperationContext.Current.OutgoingMessageHeaders.Add(messageHeader);
and extract it using FindHeader service side

Object hierarchy returned by WCF Service is different than expected

My understanding may be wrong, but I thought once you applied the correct attributes the DataContractSerializer would render fully-qualified instances back to the caller.
The code runs and the objects return. But oddly enough, once I look at the returned objects I noticed the namespacing disappeared and the object-hierarchy being exposed through the (web applications) service reference seems to become "flat" (somehow). Now, I expect this from a web-service…but not through WCF. Of course, my understanding of what WCF can do may be wrong.
...please keep in mind I'm still experimenting with all this.
So my questions are…
Q: Can I do something within the WCF Service to force the namespacing to render through the (service reference) data client proxy?
Q: Or perhaps, am I (merely) consuming the service incorrectly?
Q: Is this even possible?
The service code looks like…
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class DataService : IFishData
{
public C1FE GetC1FE(Int32 key)
{
//… more stuff here …
}
public Project GetProject(Int32 key)
{
//… more stuff here …
}
}
[ServiceContract]
[ServiceKnownType(typeof(wcfFISH.StateManagement.C1FE.New))]
[ServiceKnownType(typeof(wcfFISH.StateManagement.Project.New))]
public interface IFishData
{
[OperationContract]
C1FE GetC1FE(Int32 key);
[OperationContract]
Project GetProject(Int32 key);
}
[DataContract]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class Project
{
[DataMember]
public wcfFISH.StateManagement.ObjectState ObjectState { get; set; }
//… more stuff here …
}
[DataContract]
KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class C1FE
{
[DataMember]
public wcfFISH.StateManagement.ObjectState ObjectState { get; set; }
//… more stuff here …
}
[DataContract(Namespace = "wcfFISH.StateManagement")]
[KnownType(typeof(wcfFISH.StateManagement.C1FE.New))]
[KnownType(typeof(wcfFISH.StateManagement.Project.New))]
public abstract class ObjectState
{
//… more stuff here …
}
[DataContract(Namespace = "wcfFISH.StateManagement.C1FE", Name="New")]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class New : ObjectState
{
//… more stuff here …
}
[DataContract(Namespace = "wcfFISH.StateManagement.Project", Name = "New")]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class New : ObjectState
{
//… more stuff here …
}
The web application code looks like…
public partial class Fish_Invite : BaseForm
{
protected void btnTest_Click(object sender, EventArgs e)
{
Project project = new Project();
project.Get(base.ProjectKey, base.AsOf);
mappers.Project mapProject = new mappers.Project();
srFish.Project fishProject = new srFish.Project();
srFish.FishDataClient fishService = new srFish.FishDataClient();
mapProject.MapTo(project, fishProject);
fishProject = fishService.AddProject(fishProject, IUser.UserName);
project = null;
}
}
In case I’m not being clear…
The issue arises in that the namespacing I expect to see (returned) is different from what is actually returned.
fishProject.ObjectState SHOULD look like...
srFish.StateManagement.Project.New
fishC1FE.ObjectState SHOULD look like...
srFish.StateManagement.C1FE.New
fishProject.ObjectState ACTUALLY looks like...
srFish.New1
fishC1FE.ObjectState ACTUALLY looks like...
srFish.New
OK - default behavior for a WCF Service is this:
you define your service contracts, operations, and data contract on the server (e.g. in namespace "Server.MyService")
once the service is up and running, on your client, you create a service reference
when doing so, what Visual Studio or svcutil.exe do, is interrogate that service for its metadata (description of service methods and data)
based on that metadata, the client side proxy is generated (namespace "Client.MyService") and it contains replicas of the service contract (the methods) and the data contract
Important: it contains replicas of those things! They look the same, and they serialize into the same XML format on the wire - but they are different - in different namespaces, most notably.
This is the very nature of WCF - all you do is exchange serialized messages between client and server - all that goes back and forth are textual messages. Nothing more - no object references, no remote object - nothing like that. Toss that out of your mind! :-)
If you control both ends of the wire, this can be a pain - if you need to change anything, you have to change it on the server side, update the client references and so forth.
So if you control both ends of the wire - both the server and the client - and they're both .NET based, you can do the following:
put your service contracts and your data contracts (only the contracts - no implementations!) into a separate assembly
from your service implementation, reference that contracts assembly
copy the contracts assembly to your client, and also reference it in your client project
Now, if you add the service reference, by default, the Add Service Reference function in Visual Studio will reuse existing types in referenced assemblies - so if you have referenced your common "Contracts" assembly, those types (in their full glory, including their namespace) will be reused - no additional copies will be created.
That way, you can create a single, shared contracts assembly used by both the server side code, as well as your client, and you don't have to mess with any duplication of data structures. But again: that only works if you are in control of both ends of the wire, and both are .NET