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

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/

Related

WCF Service unable to call from .NET Core

I am doing something wrong and I can't figure it out ... I made .NET Framework 4 console application to communicate with SOAP Service, with use of Topshelf I deployed service on a server and with simple URL access to a method or use of Boomerang tool, I can see service is returning value
URL: http://35.231.17.237:8066/ERPCommunicationService/OriginalService/IsServiceHealthy
But now, when I try to access same service, from .NET Core project, I keep getting error:
System.ServiceModel.ProtocolException:
The remote server returned an unexpected response: (405) Method Not Allowed.
at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(
SendAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndCall(
String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.<>c__DisplayClass1_0.
<CreateGenericTask>b__0(IAsyncResult asyncResult)
--- End of stack trace from previous location where exception was thrown ---
Code is simple, I successfully used service endpoint to connect it to .NET Core project, where I can see Reference.cs autogenerated file and all methods from service are there ...
Here is service call from client side (.net core):
public async Task<bool> IsServiceHealthy()
{
try
{
string servicesUrl = $"{_iConfiguration["servicesUrl"]}/IsServiceHealthy";
//My binding setup, since ASP.NET Core apps don't use a web.config file
var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
binding.MaxReceivedMessageSize = 10485760;
binding.SendTimeout = new TimeSpan(0, 0, 0, 180);
binding.ReceiveTimeout = new TimeSpan(0, 0, 0, 180);
var rsExec = new OriginalService.OriginalServiceClient(binding,
new EndpointAddress(servicesUrl));
var clientFactory = rsExec.ChannelFactory.CreateChannel();
var response = await clientFactory.IsServiceHealthyAsync();
return response;
}
catch (Exception ex)
{
logging.LogError(ex.ToString());
throw ex;
}
}
And code from server side (.NET Framework 4):
Interface:
[OperationContract]
[WebInvoke(Method = "GET",
RequestFormat = WebMessageFormat.Json,
UriTemplate = "/IsServiceHealthy")]
bool IsServiceHealthy();
Implementation:
public bool IsServiceHealthy()
{
bool serviceResult = false;
byte[] test = new byte[200];
var client = new ChannelFactory<BisWebWS.BisWebWSSOAPPortType>("BisWebWSSOAPPort")
.CreateChannel();
BisWebWS.tauthStrct auth = ServisBasic.GetAuth();
try
{
var result = client.wsTest(new BisWebWS.wsTestRequest(test));
serviceResult = result.wsTestResult;
}
catch (Exception ex)
{
logger.LogError(ex.InnerException.ToString());
}
return serviceResult;
}
When ever I google shown error, everywhere it says its server side setup, but I am kinda stuck as I installed everything there is ... I am using MS Windows Server 2012 R2 Datacenter,
Thank you for shared idea how to fix this problem
The way that we call the service by using the proxy class is an Http Post request, while there is a GET decoration on the method. It requires an Http Get request instead of Post request. This might directly cause the issue.
[OperationContract]
[WebInvoke(Method = "GET",
RequestFormat = WebMessageFormat.Json,
UriTemplate = "/IsServiceHealthy")]
bool IsServiceHealthy();
If the server host the service by using Webhttpbinding, we could directly get the result by typing the service address in the browser address bar since the default request is an Http Get request (your link is not available).
This kind of service is called Restful-style service.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/wcf-web-http-programming-model
https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design
The typical call is to construct an HTTP request with a request body by using HttpClient library.
We could also call the service by using the client proxy class, like what you do. However, we should keep the binding configuration consistent between the server and the client.
WCF: There was no endpoint listening at, that could accept the message
It is too complex to call the service by using client proxy class, it is better to send Http request with HttpClient when we call Restful style service.
Besides, we could also host the service by using BasicHttpBinding, this may simplify the call. There is no need to add webhttpendpoint behavior and no need to add additional [Webget] decorations.
Simply speaking, we should maintain the binding consistent between the server and the client when using client proxy.
Feel free to let me know if the problem still exists.

Xamarin.Forms Add Connected Service on WCF only generated async method

I just begun to do Xamarin.Forms with .Net Standard 2.0 (PCL) project. I'm trying to consume my WCF web service but never got it successfully done.
I have created a simple WCF as below
[ServiceContract]
public interface IWcfConnection
{
[OperationContract]
string GetHelloWorld();
}
the implementation as below
public class WcfConnection : IWcfConnection
{
public string GetHelloWorld()
{
return "Hello World";
}
}
It's a very simple WCF, when I go to my Xamarin.Forms and right click on the "Connected Service", there is no "Add Web Service", but only "Add Connected Service", so I selected that as below
Then select "Microsoft WCF Web Service Service Provider"
Select the option as below (I untick everything because if I add more than 1 service, it will crash)
When I look into the reference.cs created, there is only async method created.
public System.Threading.Tasks.Task<string> GetHelloWorldAsync()
{
return base.Channel.GetHelloWorldAsync();
}
1) May I know why only async is created? Is it for .net standard and core, only async services will be created? As I read somewhere.
2) If so, how do I consume the web service?
In my xaml.cs file, I did the following,
WcfConnectionService.WcfConnectionClient client = new WcfConnectionService.WcfConnectionClient(new WcfConnectionService.WcfConnectionClient.EndpointConfiguration());
string abc = client.GetHelloWorldAsync().GetAwaiter().GetResult();
But I'm getting error and unable to work accordingly. Anybody got any idea?
Unhandled Exception:
System.ServiceModel.FaultException`1[[System.ServiceModel.ExceptionDetail, System.ServiceModel, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: Error in deserializing body of request message for operation 'GetHelloWorld'. OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'GetHelloWorld' and namespace 'http://tempuri.org/'. Found node type 'Element' with name 'GetHelloWorldAsync' and namespace 'http://tempuri.org/'
At the moment Xamarin apps aren't compatible with the Task-based asynchronous WCF proxy methods that the WCF Web Service Reference connected service provider generates for .NET Standard projects (bugzilla.xamarin.com Bug 51959).
Generate an older compatible style of WCF proxy methods via checked "Generate Synchronous Operations" checkbox on Configure WCF Web Service Reference screen:
Consume the web service:
KimlikServiceReference.KPSPublicSoapClient soapClient = new KimlikServiceReference.KPSPublicSoapClient(KimlikServiceReference.KPSPublicSoapClient.EndpointConfiguration.KPSPublicSoap);
//KimlikServiceReference.TCKimlikNoDogrulaResponse response = soapClient.TCKimlikNoDogrulaAsync(TCKimlikNo, Ad, Soyad, DogumYili).Result;
bool result = soapClient.TCKimlikNoDogrula(TCKimlikNo, Ad, Soyad, DogumYili);

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.