I am trying to access an old ASMX webservice using WCF by calling the ChannelFactory.CreateChannel() method.
If the web service is created by WCF, everything is straightforward. I can instantiate the proxy client generated by the svcutil tool, or manually call the ChannelFactory.CreateChannel() method. Afterwards, I can call the web service methods the same way for both scenarios.
But if the web service is of the old ASMX variety, I can still instantiate the proxy either way, but I am unable to call the same web service method.
For example, assume this basic WCF web service interface:
[ServiceContract]
public interface IWebService
{
[OperationContract]
string HelloWorld();
}
After using svcutil to generate the proxy, I can call HelloWorld() one of 2 ways:
WebServiceClient proxy = new ServiceReference.WebServiceClient();
textBox1.Text += proxy.HelloWorld();
or:
ChannelFactory<ServiceReference.IWebService2> cfactory =
new ChannelFactory<ServiceReference.IWebService>("BasicHttpBinding_IWebService");
ServiceReference.IWebService proxy = cfactory.CreateChannel();
((IClientChannel)proxy).Open();
textBox1.Text += proxy.HelloWorld();
Now assume this ASMX web service:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebService : System.Web.Services.WebService
{
public WebService() { }
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
Calling HelloWorld() using the SoapClient generated by svcutil tool is nearly the same as if it were a WCF web service:
WebServiceSoapClient proxy = new ServiceReference.WebServiceSoapClient();
textBox1.Text += proxy.HelloWorld();
But trying to call HelloWorld() if you create the channel yourself and you will get an error:
ChannelFactory<ServiceReference.WebServiceSoap> cfactory =
new ChannelFactory<ServiceReference.WebServiceSoap>("WebServiceSoap");
ServiceReference.WebServiceSoap proxy = cfactory.CreateChannel();
((IClientChannel)proxy).Open();
textBox1.Text += proxy.HelloWorld();
The error is "No overload for method HelloWorld takes 0 arguments".
It appears it is because the HelloWorld method in the autogenerated interface (ServiceReference.WebServiceSoap) takes an argument of type ServiceReference.HelloWorldRequest.
So in the end, I was only able to make it work by looking through the svcutil generated code and change my implementation to this:
ChannelFactory<ServiceReference.WebServiceSoap> cfactory =
new ChannelFactory<ServiceReference.WebServiceSoap>("WebServiceSoap");
ServiceReference.WebServiceSoap proxy = cfactory.CreateChannel();
((IClientChannel)proxy).Open();
ServiceReference.HelloWorldRequest inValue =
new WCFConsumeWebServices.ServiceReference.HelloWorldRequest();
inValue.Body = new WCFConsumeWebServices.ServiceReference.HelloWorldRequestBody();
ServiceReference.HelloWorldResponse retVal = proxy.HelloWorld(inValue);
textBox1.Text += retVal.Body.HelloWorldResult;
Is this how it is suppose to be?
For one type of basic http web service, we get to use virtually the same code to call a method, but for another we need to muck through the generated proxy code and have different implementation depending on how you open the channel ?
Related
The issue has already discussed here, but it did not addressed it quite the way I am looking for.
I have already created a service reference from a client console app in visual studio, but I want to do it programmatically with the following contraint:
From Microsoft Docs - wcf, it obvious that we have to have the service interface reference available to the client. In my case I do have the reference available, instead I have the address where the service is hosted and this address is a dynamic one.
So I want to define a customized client class that will have its object declared with the host address only. Lets take the following snippet as an example:
public partial class CalculatorServiceClient : System.ServiceModel.ClientBase<ICalculatorService>, ICalculatorService
{
}
As you can see that ICalculatorService is available while defining the class. What to do if the interface to the service is not available while defining the class.
You can connect to the WCF service pragmatically without having to use the generated class methods, but note that this can have issues if the service changes in future
The idea is simple .
Create a service contract that matches your service implementation
[DataContract]
public class SomeDataContarctClass
{
[DataMember]
public string SomeMember{get;set;}
etc....
}
Create the interface
public IServiceInterface
{
[OperationContract]
List<SomeDataContarctClass> GetSomeData();
...etc
}
Now this is where you start to Glue things together,
Then create the service
public IServiceInterface CreateIService()
{
EndpointAddress myEndpoint = new EndpointAddress("SERVICE URL");
BasicHttpBinding binding= new BasicHttpBinding();
defaultBinding.MaxReceivedMessageSize = 2147483647;
defaultBinding.MaxBufferPoolSize = 2147483647;
defaultBinding.MaxBufferSize = 2147483647;
defaultBinding.ReaderQuotas.MaxArrayLength = 2147483647;
defaultBinding.ReaderQuotas.MaxStringContentLength = 2147483647;
ChannelFactory<IUpdaterService> myChannelFactory = new ChannelFactory<IServiceInterface>(binding, myEndpoint);
myChannelFactory.Endpoint.EndpointBehaviors.Add(new ServiceInterceptionBehavior());
// Create a channel.
return myChannelFactory.CreateChannel();
}
Then you can call the service using
var myserviceImp = CreateIService();
var data = myserviceImp.GetSomeData();
I have a WCF RIA Service with methods that return IQueryable<>. I want to access this methods using ClannelFactory from a
console application. I have an interface on the client that matches the the methods in my RIA Service. When I run the server and
the client applications I can see that the server method is called and an IQuery<> object is returned. The problem is that on the
client I can't get the data sent by the server. I can see that data actually comes by using Fiddler, but I think that the data can't be
deserialized to IQueryable.
For me the type of the data received doesn't matter. I'll be happy with just an array. But because the method in the
service returns IQueryable my OperationContract method on the client has the same type.
So the question is how to get the data from the server, without changing the return type (IQueryable) on the server side?
Server side:
public IQueryable<Customers> GetCustomers()
{
List<Customers> customersList = new List<Customers>();
customersList.Add(new Customer())
...
return customersList.AsQueryable();
}
Client side:
[ServiceContract]
public interface CustoemrsService
{
[OperationContract]
IQueryable<Customers> GetCustomers();
}
And the ChannelFactory code:
var endpointAddress = new EndpointAddress(_endpointAddress);
var channelFactory = new ChannelFactory<VfxSystemDomainServiceSoap>(new BasicHttpBinding());
var channel = channelFactory.CreateChannel(endpointAddress);
IQueryable<Customers> customersCollection = channel.GetVfxfopenQuery();
Sorry to bother you guys again.
I am going to consume a WCF service on a server. The service was created by outside. If I look at it in the browser, it is fine. Please see the image below.
To consume it, I add service reference. with the url http://wsvc01/BOERPI/BOERPI.svc
Then I instantiate the proxy by the code.
BOERPI.PostPhoneCallResponse client = null;
client = new BOERPI.PostPhoneCallResponse();
double x = client.ActualCallCharge; // suppose to get a proper value but not
Some of the code of the service is:
[ServiceContract]
public interface iBOERPI
{
[OperationContract]
PostPhoneCallResponse PostPhoneCall(PostPhoneCallRequest objCDRRequest);
[DataContract]
public class PostPhoneCallResponse
{
[DataMember]
public double ActualCallCharge = -1.0;
I assume the service code is 100% right, is any thing wrong when I consume the service?
When I righted click the definition of PostPhoneCallResponse, it is:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="PostPhoneCallResponse", Namespace="http://schemas.datacontract.org/2004/07/nsBOERPI")]
[System.SerializableAttribute()]
public partial class PostPhoneCallResponse : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private double ActualCallChargeField;
Thanks.
client = new BOERPI.PostPhoneCallResponse(); You are trying to use your DataContract here instead of Service client.
Check under Service References for your service name you used in your client application and
use it:
eg.
using(var client = new BingMapsGeocodeService()) // This should be your service client name
{
}
Update:
Sending and Received messages using request and response objects:
You need to create a request object as per your operation shows:
var request = new PostPhoneCallRequest(){ // populate all your properties you need to send to the service};
var client = new BOERPI.MyClient(); // Instantiate your client with the name you have given for your service client.
PostPhoneCallResponse response = client.PostPhoneCall(request); // You are sending your request and getting a response as PostPhoneCallResponse object
Is there a way to create an async client for a synchronous WCF service without adding a service reference? This is for a .NET 4 client.
A service reference in Visual Studio is nothing else than a code generator that creates a proxy class with corresponding data elements necessary to call your web service. Of course you can hand build a proxy if you really want to go over tedious and boring work.
Maybe start by decompiling System.ServiceModel.ClientBase using .net reflector?
Do some research on ChannelFactory: http://msdn.microsoft.com/en-us/library/system.servicemodel.channelfactory.aspx
Even when implementing my own client by wrapping a ChannelFactory, I am still using the Add Service reference in another project to create the class definitions and move them into the real project. That's a good compromise.
Here's a simple async service interface:
[ServiceContract(Name = "IService")]
public interface IServiceAsync
{
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetStuff(string someData, AsyncCallback callback, object state);
IEnumerable<Stuff> EndGetStuff(IAsyncResult result);
}
The .NET contract might look like this:
[ServiceContract]
public interface IService
{
[OperationContract]
IEnumerable<Stuff> GetStuff(string someData);
}
Then in code, assuming you use HTTP, No security and binary message encoding, something like this (Sorry I haven't compiled any of this, just typed it using some of the code I have written for projects):
//Create a binding for the proxy to use
HttpTransportBindingElement httpTransportBindingElement;
httpTransportBindingElement = new HttpTransportBindingElement();
absoluteServiceUri = new Uri(absoluteServiceUri.OriginalString + BinaryEndpointUri, UriKind.Absolute);
}
//Create the message encoding binding element - we'll specify binary encoding
var binaryMessageEncoding = new BinaryMessageEncodingBindingElement();
//Add the binding elements into a Custom Binding
var customBinding = new CustomBinding(binaryMessageEncoding, httpTransportBindingElement);
// Set send timeout
customBinding.SendTimeout = this.SendTimeout;
var factory = new ChannelFactory<IServiceAsync>(customBinding, new EndpointAddress(absoluteServiceUri, new AddressHeader[0]));
var channel = factory.CreateChannel();
channel.BeginGetStuff(Bla, results => { // Do something }, null);
I've created a WCF service project. Using the standard generated example service the project generates I create a wrapper class using wsdl.exe.
However the service times out when I use the following code:
Service1 svc = new Service1();
svc.UseDefaultCredentials = true;
svc.Url = "http://localhost:16218/Service1.svc?wsdl";
string x = svc.GetData(1, true);
When I invoke the same webmethod via a normal Service Reference it works fine. What am i missing?
Thanks in advance!
Well, if you want to call the service, you shouldn't be connecting to the WSDL endpoint!
svc.Url = "http://localhost:16218/Service1.svc?wsdl";
Use this code instead:
Service1 svc = new Service1();
svc.UseDefaultCredentials = true;
svc.Url = "http://localhost:16218/Service1.svc";
string x = svc.GetData(1, true);
But why would you use wsdl.exe to create a client side bits for WCF?? Use svcutil.exe instead! That's the right tool for the WCF job.