WCF send and receive string? - wcf

im able to successfully use an MSDN example on sending a message to an MSMQ and reading it from a self hosted WCF service.
I am trying to use a simple string in a new project. I can send the string to the queue no problem but the WCF service hosted, faults.
After trying to figure out why, using the Microsoft Service Trace Viewer and enabling logging on the host, it says its a poison message!
but my contract defines MsmqMessage
This is what I am using to send:
System.Messaging.Message msg = new System.Messaging.Message(this.textBox1.Text);
And this is my contract (receiving):
[OperationContract(IsOneWay = true, Action = "*")] void
ProcessIncomingMessage(MsmqMessage<string> incomingMessage);
The content of the message when looking through MMC:
<?xml version="1.0"?>
<string>test</string>
any ideas?

Fixed: on the sender, define the formatter: msg.Formatter = new XmlMessageFormatter(new string[] { "System.String" }); on the contract, decorate it with a knowntype of string: [ServiceKnownType(typeof(String))]

Related

Can't get WCF service to send XML Document to BizTalk Receive Location

I'm new to BizTalk and WCF services and am trying to figure out how to use a WCF service to deliver XML data to Biztalk. I think I'm close but when I call the WCF service operation, the operation executes successfully but does not appear to generate any kind of a message in Biztalk. Am I wrong in assuming that simply calling an operation is enough to trigger a message to BizTalk?
Below is my code and some details about my BizTalk configuration:
WCF service:
public interface IService1
{
[OperationContract, XmlSerializerFormat]
XmlDocument GetXMLDocument(string sourceXML);
}
public class Service1 : IService1
{
public XmlDocument GetXMLDocument(string sourceXML)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(sourceXML);
return doc;
}
}
Calling application (button click calls the service):
protected void Button2_Click(object sender, EventArgs e)
{
XmlDocument doc = new XmlDocument();
doc.AppendChild(doc.CreateNode(XmlNodeType.Element, "Patients", "test"));
SendDoc(doc);
}
protected void SendDoc(XmlDocument doc)
{
//use a Service Client Object to call the service
objServiceClientobjService.GetXMLDocument(doc.OuterXml);
}
BizTalk configuration:
Receive Port:
Port type: One-Way
Receive Location:
Type: WCF-Custom with basicHTTP binding
Endpoint Address is the same as the IIS hosted WCF Service
Receive Pipeline Type: XMLReceive
Your implementation is not correct. There is no link between your WCF service and BizTalk. If you want to receive xml in BizTalk then you need to expose either an Orchestration or Xml Schema as WCF service using BizTalk WCF Web Service Publishing Wizard. This gets installed with BizTalk. Please see link for more details: msdn link
The solution I always use, is to expose an endpoint. Take a look at this example:

500 Internal Server Error on a self hosted WCF Service

I am attempting to develop a new WCF service that is hosted using the ServiceHost object. I am able to get the console application to start and I can see that it is binding to port 80 via netstat. Using WireShark I am also able to see that the client is able to connect to that port and send over the data. I had a problem early on with the amount of data that is being sent in the SOAP message from the client, but was able to resolve that issue by setting the max receive size on the binding. The HTTP 500 error that I am getting is:
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).
The following is my WCF code and my service code.
public class MyWCFService
{
private ServiceHost _selfHost;
public void Start()
{
Uri baseAddress = new Uri(#"http://192.168.1.10");
this._selfHost = new ServiceHost(typeof(MyServiceImpl), baseAddress);
try {
WebHttpBinding binding = new WebHttpBinding();
binding.MaxBufferSize = 524288;
binding.MaxReceivedMessageSize = 524288;
this._selfHost.AddServiceEndpoint(typeof(IMyServiceContract), binding, "MyService");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
this._selfHost.Description.Behaviors.Add(smb);
this._selfHost.Open();
}
catch ( CommunicationException ce ) {
this._selfHost.Abort();
}
}
public void Stop()
{
this._selfHost.Close();
}
}
The following is my service contract. It is fairly simple and only has a single Operation. It is expected that it will be called upon the receipt of a SOAP based message.
[ServiceContract(Namespace = "http://www.exampe.com")]
public interface IMyServiceContract
{
[OperationContract (Action="http://www.example.com/ReportData", ReplyAction="*")]
string ReportData( string strReport );
}
The following the my implementation of the service contract
class MyServiceImpl : IMyServiceContract
{
public string ReportData( string strReport )
{
return "ok";
}
}
Here is what I am getting from my client (the strReport was very long so I excluded it)
POST /MyService HTTP/1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://www.example.com/ReportData"
Host: 192.168.1.10
Content-Length: 233615
Expect: 100-continue
Connection: Keep-Alive
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<ReportData xmlns="http://www.example.com/">
<strReport>
........
</strReport>
</ReportData>
</soap:Body>
</soap:Envelope>
Any help resolving this issue would be greatly appreciated.
Regards,
Richard
Do you want your service to be a SOAP service or a REST service?
On the service side, it is configured to be a REST services (because you are using WebHttpBinding). However, the request from your client is a SOAP request. If your client is a WCF client, it is probably using wsHttpBinding or basicHttpBinding. Both of these are for SOAP.
You can either:
Change your service to use basicHttpBinding or wsHttpBindding to match your client (if you want to use SOAP), or
Change your client to use webHttpBinding (if you want to use REST). This will need more changes because your operation contract is not properly Attributed for REST. And anyway, WCF is not a good option for REST. The ASP.Net Web API is much simpler and better supported.
Also
the Action specified in your operation contract should be just ReportData rather than the namespace qualified version. You may not need it at all in fact.
you can remove the ReplyAction (or specify a proper value if your client needs it)
Generally, you do not need to specify these. I'm not an expert on the innards of SOAP but I believe that WCF will specify these values based on the method name if you don't specify them. Uniqueness of method names in .Net will ensure that the action/replyaction are unique in that case.
With these changes in place It Works On My Machine (TM)

WCF Discovery and DataService V3

I would like to expose discovery endpoints (both TCP and UDP) for my Data Services v3 and enable services to be discoverable from the client and discover them in another application. The main point in the discovery is to get the service endpoint address at the client.
I have tried to adapt the samples that Microsoft have provided for WCF Discovery, but so far I failed to achieve my goal.
I have created a custom Data Service Host Factory on server side:
public class CustomDataServiceHostFactory : System.Data.Services.DataServiceHostFactory
{
protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var serviceHost = base.CreateServiceHost(serviceType, baseAddresses);
EndpointDiscoveryBehavior endpointDiscoveryBehavior = new EndpointDiscoveryBehavior();
// Create XML metadata to add to the service endpoint
XElement endpointMetadata = new XElement(
"Root",
new XElement("Information", "This endpoint is Data Service v3!"),
new XElement("Time", System.DateTime.Now.ToString("MM/dd/yyyy HH:mm")));
// Add the XML metadata to the endpoint discovery behavior.
endpointDiscoveryBehavior.Extensions.Add(endpointMetadata);
//may be this is not the safest way to set the behaviour
foreach (var endpoint in serviceHost.Description.Endpoints)
{
endpoint.Behaviors.Add(endpointDiscoveryBehavior);
}
// Make the service discoverable over UDP multicast
serviceHost.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
serviceHost.AddServiceEndpoint(new UdpDiscoveryEndpoint());
return serviceHost;
}
}
On the client side I have tried the following code:
DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
// Find service endpoints
// ServiceReference.DataModel is the generated class for the Data Service client proxy
FindCriteria findCriteria = new FindCriteria(typeof(ServiceReference.DataModel));
findCriteria.Duration = TimeSpan.FromSeconds(30);
FindResponse findResponse = discoveryClient.Find(findCriteria);
// Check to see if endpoints were found & print the XML metadata in them.
if (findResponse.Endpoints.Count > 0)
{
foreach (XElement xElement in findResponse.Endpoints[0].Extensions)
{
Console.WriteLine("Printing Metadata from ServiceEndpoint:");
Console.WriteLine("Endpoint Information: " + xElement.Element("Information").Value);
Console.WriteLine("Endpoint Started at Time: " + xElement.Element("Time").Value);
Console.WriteLine();
}
}
Unfortunately this does not work. I get InvalidOperationException:
Attempted to get contract type for DataModel, but that type is
not a ServiceContract, nor does it inherit a ServiceContract.
If I am heading in the right direction I need a way to express the type for the service contract for the discovery. Too bad I am not sure that it will even work like the normal WCF Discovery...
Please share your ideas or even better - working solutions.
I think exception message is clear enough.
For service discovery You try to use type of your data model, while You must use type of your WCF service implementation - this is different things.
Basically DataServicesV3 service adapter uses your data model and exposes it as a WCF service with it's own service contract.
Look at DataServiceV3 type declaration see that it is implementing some interface, i just don't remember name, in this interface declaration you will find [ServiceContract] and [ServiceOperation] attributes. This is Your SERVICE CONTRACT for all ancestors of DataServiceV3. They use THE SAME contract. Here stands another problem I haven't managed to solve yet - how to make WS-Discovery work with DataServices if they share same contract. You'd better dig in this way.

WCF ServiceContract and SOAP response not called *Response

I'm writing a SOAP consumer using WCF.
In the following WCF service contract, WCF expects that the response has a Body and an element called HelloResponse:
[ServiceContract]
public interface HelloService
{
string Hello(string input);
}
On the service I'm calling, it is actually called HelloResult. How can I tell WCF this, without using MessageContracts? I tried combinations and variations of the following, but without success.
...
[OperationContract(ReplyAction = "HelloResult")]
[return: MessageParameter(Name = "HelloResult")]
...
If you know the service operation Hello(string) returns a string then why not just create a channel and call the operation directly rather than worrying about messages?

Call a WCF Service using just manual code (no config or autogen code)

I am loosely following the method in WCF The Right Way ... The Manual Way to setup my WCF Service.
I have a manually generated proxy class that looks like this:
// Setup a client so we can call our web services.
public class EmployeeClient :IEmployeeService
{
private readonly IEmployeeService EmployeeChannel;
public EmployeeClient(Binding binding, string address)
{
var endpointAddress = new EndpointAddress(address);
EmployeeChannel = new ChannelFactory<IEmployeeService>
(binding, endpointAddress).CreateChannel();
}
public EmployeeResponse SaveOrUpdateEmployee(EmployeeContract employee)
{
return EmployeeChannel.SaveOrUpdateEmployee(employee);
}
}
I then want to call some of these services. But I don't want to use any config files (I am setting up some integration tests and I don't want more dependencies than needed.)
I am currently trying to call them like this:
serviceHost = SelfServiceHost.StartupService();
employeeClient = new EmployeeClient(new BasicHttpBinding(),
SelfServiceHost.StartUpUrl);
EmployeeResponse employeeResponse = employeeClient.SaveOrUpdateEmployee(emp);
When I do that I am getting this exception:
System.ServiceModel.ProtocolException: Content Type text/xml; charset=utf-8 was not supported by service http://localhost:8090/EmployeeService. The client and service bindings may be mismatched. ---> System.Net.WebException: The remote server returned an error: (415) Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'..
What do I need to do to get a call to my service working with code only?
From what you dessribe the binding is not configured in a compatible way.
I suspect that the WCF host has wsHttpBinding and your client-side has BasicHttpBinding or similar...
see http://social.msdn.microsoft.com/forums/en-US/wcf/thread/f29cd9c8-3c89-43d2-92ae-d2a270ab86b9/