Dynamically Invoke Web Service At Runtime - c#

I am using the sample code to dynamically invoke a web service from this site:
http://www.crowsprogramming.com/archives/66
The issue that I am facing is when I use the Class to call a web service from a web application I get the following error: "The remote host cannot be found" and the error happens at the following line of code:
if (!ServiceDescription.CanRead(xmlreader))
But if I use the same code from a windows application to connect to the web service:
http://www.w3schools.com/webservices/tempconvert.asmx?WSDL
it works fine. I am not sure how to resolve this issue. Has anyone else faced the same issue and was able to resolve it then would appreciate some pointers in the right direction.

The code above needs a little more:
ServiceDescription serviceDescription;
using (WebClient client = new WebClient {Proxy = new WebProxy(host, port)})
{
using (Stream stream = client.OpenRead(webserviceUri))
{
using (XmlReader xmlreader = XmlReader.Create(stream))
{
serviceDescription = ServiceDescription.Read(xmlreader);
}
}
}
WebClient, Stream, and XmlReader all implement IDisposable, so should be created in a using block when their usage is only locally scoped. Also, new XmlTextReader() has been deprecated since .NET 2.0, and should be replaced with XmlReader.Create.
(answer made CW because it's really just a formatted comment)

The issue for me was the Proxy to be used to connect to the internet. The code needs to change at the following two places for the successful operation:
1] The method BuildServiceDescriptionImporter(XmlTextReader xmlreader) was changed to
private ServiceDescriptionImporter BuildServiceDescriptionImporter( string webserviceUri )
{
ServiceDescriptionImporter descriptionImporter = null;
**WebClient client = new WebClient { Proxy = new WebProxy( string host, int port ) };**
Stream stream = client.OpenRead( webserviceUri );
XmlTextReader xmlreader = new XmlTextReader( stream );
// parse wsdl
ServiceDescription serviceDescription = ServiceDescription.Read( xmlreader );
// build an importer, that assumes the SOAP protocol, client binding, and generates properties
descriptionImporter = new ServiceDescriptionImporter();
descriptionImporter.ProtocolName = "Soap12";
descriptionImporter.AddServiceDescription( serviceDescription, null, null );
descriptionImporter.Style = ServiceDescriptionImportStyle.Client;
descriptionImporter.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties;
return descriptionImporter;
}
2] The second piece of code that was to be changed was within the public T InvokeMethod<T>( string serviceName, string methodName, params object[] args ) method
add the following code snippet before Invoking the method:
PropertyInfo Proxy = type.GetProperty( "Proxy" );
WebProxy webProxy = new WebProxy( string host, int port);
Proxy.SetValue( serviceInstance, webProxy, null );
After doing those changes I was able to use the code to connect to a remote web service dynamically.
Hope this helps others facing the same issue as I did.

Related

USCG PSIX Web Service returning auth error

The United States Coast Guard runs a SOAP Web Service called PSIX:
https://cgmix.uscg.mil/xml/default.aspx
https://cgmix.uscg.mil/xml/PSIXData.asmx
https://cgmix.uscg.mil/xml/PSIXData.asmx?WSDL
Recently some software that has been accessing this web service for a ling time started erroring out, the error returned from PSIX is:
The HTTP request was forbidden with client authentication scheme 'Anonymous'.
There is a problem with the certificate on the site, but that's been like that for as long as we've been accessing the service (a little over a year and a half).
There is no mention on the USCG sites that I can find saying you need any kind of authentication to access the service - so I'm not sure what to do. There are also no contact details provided for the service I can find to ask if they've changed something on their side - there is comment form to which I've submitted a question about this issue.
The service was added into a .NET Core project using the Microsoft WCF Web Service Reference Provider. We create an instance if it with this static helper method.
Any ideas on how to get around the error?
private static PSIXDataSoap ServiceProxy
{
get {
try
{
if (_serviceProxy == null)
{
BasicHttpBinding binding = null;
binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport); //Force use SSL, otherwise you get "expected http"
binding.MaxReceivedMessageSize = 20000000;
binding.MaxBufferSize = 20000000;
binding.MaxBufferPoolSize = 20000000;
binding.AllowCookies = true;
var factory = new ChannelFactory<PSIXDataSoap>(binding, new EndpointAddress("https://psix.uscg.mil/xml/PSIXData.asmx"));
//Tell it: Yes, I know the Coast Guard's Certificate is invalid...
factory.Credentials.ServiceCertificate.SslCertificateAuthentication =
new X509ServiceCertificateAuthentication()
{
CertificateValidationMode = X509CertificateValidationMode.None,
RevocationMode = X509RevocationMode.NoCheck
};
_serviceProxy = factory.CreateChannel();
}
return _serviceProxy;
}
catch (Exception)
{
return null;
}
}
}
And then access the proxy like:
var psixResponse = await ServiceProxy.getVesselSummaryAsync(vesselId_str, vesselName_str, callsign_str, vin_str, hin_str, flag_str, service_str, buildYear_str);
The following code work great. If it fails on your machine then it is probably a TLS issue. :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string URL = "https://cgmix.uscg.mil/xml/PSIXData.asmx?WSDL";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(URL);
}
}
}
Somewhere along the lines I guess the USCG changed the URL of their web service. So I:
Deleted and re-added the WCF Connected Service reference
Changed my service proxy helper method to use the new URL (I think this was the root cause of my problem).
As to why I needed to have the special helper method instead of creating the service reference from the built-in initializer, I think mainly because:
I needed to bypass the certificate error
I needed to increase the default message/buffer sizes because some of these calls can return a lot of information.
Anyway, new helper method that fixed my problem:
private static PSIXDataSoap ServiceProxy
{
get {
try
{
if (_serviceProxy == null)
{
BasicHttpBinding binding = null;
binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport); //Force use SSL, otherwise you get "expected http"
binding.MaxReceivedMessageSize = 20000000;
binding.MaxBufferSize = 20000000;
binding.MaxBufferPoolSize = 20000000;
binding.AllowCookies = true;
//var factory = new ChannelFactory<PSIXDataSoap>(binding, new EndpointAddress("https://psix.uscg.mil/xml/PSIXData.asmx"));
var factory = new ChannelFactory<PSIXDataSoap>(binding, new EndpointAddress("https://cgmix.uscg.mil/xml/PSIXData.asmx")); //<--- NEW URL
//Tell it: Yes, I know the Coast Guard's Certificate is invalid...
factory.Credentials.ServiceCertificate.SslCertificateAuthentication =
new X509ServiceCertificateAuthentication()
{
CertificateValidationMode = X509CertificateValidationMode.None,
RevocationMode = X509RevocationMode.NoCheck
};
_serviceProxy = factory.CreateChannel();
}
return _serviceProxy;
}
catch (Exception)
{
return null;
}
}
}

Need help to write web api wrapper for Silverlight project

Please bear with me as I am new to Silverlight. I need to write a web api wrapper (I've named it WebClientWrapper) which is supposed to consume rest services. The project uses Silverlight 5. I am facing many problems while writing such a wrapper. There are a lot of examples demonstrating rest service consumption in C#. But unfortunately none of them worked for me. It's been a challenge for me to get done with what I need. Below are my requirements:
1) UI should not freeze while I make any GET request,
2) Calling methods from WebClientWrapper should be as easier as possible.
3) .NET framework version of project should not be changed.
I tried following things so far:
1) Use of HttpClient. I referred this link: http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client. The problem with this approach is I cannot call ReadAsAsync method. Calling this method requires change in framework (i.e. replacing dlls or changing framework version) which is not feasible.
2) Use of WebClient. http://www.kastory.net/index.php?option=com_content&view=article&id=25:rest-web-service-in-c-with-silverlight-and-asp-net-web-api&catid=32:web-services&Itemid=130.
The problem with this is I will probably (not sure!) have to make changes in the way I call methods from WebClientWrapper. I am trying to accomplish calling method from WebClientWrapper something like this:
var appointments = WebClientWrapper.Get<Appointments>(new Dictionary<string, string>()
{
{"hospitalId", "19465654546"}
}, "appointment");
Below is the code snippet I tried in WebClientWrapper.
private const string BaseUrl = "http://localhost:63455/api";
private static WebClient GetClient()
{
int leadingInt = new Random().Next(10000, 99999);
int trailingInt = new Random().Next(1000, 9999);
string date = DateTime.Now.ToString("ddHHmmMMssMMyyyyyss");
string ticketString = string.Format("{0}{1}{2}", leadingInt, date, trailingInt);
var client = new WebClient();
client.Headers["Accept"] = ticketString;
client.Headers["UserAgent"] = "ReceptionistApp";
return client;
}
private static void DownloadCompletionHandler<T>(object sender, DownloadStringCompletedEventArgs e)
{
Encoding messageEncoding = Encoding.UTF8;
var serializer = new DataContractJsonSerializer(typeof (T));
var memoryStream = new MemoryStream(messageEncoding.GetBytes(e.Result));
var objectToReturn = (T) serializer.ReadObject(memoryStream);
}
public static T Get<T>(Dictionary<string, string> paramDictionary, string controller)
{
string absoluteUrl = BaseUrl + controller + "?";
absoluteUrl = paramDictionary.Aggregate(absoluteUrl,
(current, keyValuePair) => current + (keyValuePair.Key + "=" + keyValuePair.Value + "&"));
absoluteUrl = absoluteUrl.TrimEnd('&');
WebClient client = GetClient();
client.DownloadStringCompleted += DownloadCompletionHandler<T>;
client.DownloadStringAsync(new Uri(absoluteUrl));
}
Below are the things I want to mention regarding the code above:
1) As obvious, compiler throws error for the method Get<T> since I've not returned object of type T. How shall I get that object from DownloadStringAsync? I know I can use DownloadStringTaskAsync. But it is not available with the current framework. What changes do I have to make in my code so that I get appointments as shown in the Get<Appointments> method call?
2) DownloadCompletionHandler<T> is bound to return void but actually I want to return objectToReturn as shown in code.
Help will be greatly appreciated. Any new code snippets that will fulfill my requirements are welcome.
RestSharp helped me instead of WebClient.

C# equivalent to Java SSL-socket-connection

Hey guys I'm trying to write an AXL-client (SOAP) for the Cisco Unified Communications Manager. For that purpose I need to establish an ssl-connection to the AXL-service. Unfortunatly I dont know much about all that ssl-stuff.
However I was able to find a working Java-example, that does, what I want. The problem is, i need that in C#.NET. So I'm hoping, that someone could "translate" the following Java-code in a C#-version. But it has to do exactly the same, espacially the authentication and certificate-stuff.
Here is the code:
String sAXLSOAPRequest = "...";
byte[] bArray = null; // buffer for reading response from
Socket socket = null; // socket to AXL server
OutputStream out = null; // output stream to server
InputStream in = null; // input stream from server
X509TrustManager xtm = new MyTrustManager();
TrustManager[] mytm = { xtm };
SSLContext ctx = SSLContext.getInstance("SSL");
ctx.init(null, mytm, null);
SSLSocketFactory sslFact = (SSLSocketFactory) ctx.getSocketFactory();
socket = (SSLSocket) sslFact.createSocket("192.168.1.100", Integer.parseInt("8443"));
in = socket.getInputStream();
// send the request to the server
// read the response from the server
StringBuffer sb = new StringBuffer(2048);
bArray = new byte[2048];
int ch = 0;
int sum = 0;
out = socket.getOutputStream();
out.write(sAXLSOAPRequest.getBytes());
while ((ch = in.read(bArray)) != -1) {
sum += ch;
sb.append(new String(bArray, 0, ch));
}
socket.close();
// output the response to the standard output
System.out.println(sb.toString());
and this is the MyTrustManager-Class:
public class MyTrustManager implements X509TrustManager {
MyTrustManager() {
// create/load keystore
}
public void checkClientTrusted(X509Certificate chain[], String authType)
throws CertificateException {
}
public void checkServerTrusted(X509Certificate chain[], String authType)
throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
Any help would be appreciated.
Thanks
edit: sorry i should have mentioned: youre right i can generate a proxy-class, but sadly its not working properly. cisco did a really bad job with that (not to mention the really bad documentation). the proxy class throws some xml-errors when parsing some responses. so i have to do it manually for that cases...
i'll worry about the certificate security later
Have you tried consuming the web service the "proper" way? Add a SOAP web service reference to your C# project in Visual Studio, gets the stubs etc? That's the easiest way of doing it from C#. You can just specify a https protocol in the URL when you add the reference.

Amazon API, Product Advertising API , ItemSearch, C#

I'm trying to get use the new product amazon API to search for products on Amazon. I've been looking at their sample code and other people's examples of this but I'm not getting back any results and wondering if anyone else has used the API recently and could provide some assistance?
using System;
using System.ServiceModel;
using Simple.Amazon.ECS;
namespace Simple {
class Program {
// your Amazon ID's
private const string accessKeyId = "*******************";
private const string secretKey = "************************************";
// the program starts here
static void Main(string[] args) {
// create a WCF Amazon ECS client
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
binding.MaxReceivedMessageSize = int.MaxValue;
AWSECommerceServicePortTypeClient client = new AWSECommerceServicePortTypeClient(
binding,
new EndpointAddress("https://webservices.amazon.com/onca/soap?Service=AWSECommerceService"));
// add authentication to the ECS client
client.ChannelFactory.Endpoint.Behaviors.Add(new AmazonSigningEndpointBehavior(accessKeyId, secretKey));
// prepare an ItemSearch request
ItemSearchRequest request = new ItemSearchRequest();
request.SearchIndex = "Books";
request.Title = "WCF";
request.ResponseGroup = new string[] { "Small" };
ItemSearch itemSearch = new ItemSearch();
itemSearch.Request = new ItemSearchRequest[] { request };
itemSearch.AWSAccessKeyId = accessKeyId;
// issue the ItemSearch request
ItemSearchResponse response = client.ItemSearch(itemSearch);
// write out the results
foreach (var item in response.Items[0].Item) {
Console.WriteLine(item.ItemAttributes.Title);
}
}
}
}
All the samples/examples are similar to this in structure but when it comes to the foreach loop there are no items returned(Null) so I get a null exception error.
if the solution above still won't work.
try this one..
download the sample code on http://www.falconwebtech.com/post/2010/06/14/Using-WCF-and-SOAP-to-Send-Amazon-Product-Advertising-API-Signed-Requests.aspx
we need to update service references, make little change at app.config, program.cs, and reference.cs.
app.config:
(1.) appSettings tag;
assign accessKeyId and secretKey value,
add .
(2.) behaviours tag -> endpointBehaviors tag -> behaviour tag -> signingBehavior tag;
assign accessKeyId and secretKey value.
(3.) bindings tag -> basicHttpBinding tag; (optional)
delete binding tag except AWSECommerceServiceBindingNoTransport
and AWSECommerceServiceBindingTransport.
(4.) client tag;
delete endpoint tag except AWSECommerceServiceBindingTransport.
program.cs:
add itemSearch.AssociateTag = ConfigurationManager.AppSettings["associateTag"]; before ItemSearchResponse response = amazonClient.ItemSearch(itemSearch);
reference.cs: (open file in service references folder using visual studio)
change private ImageSet[][] imageSetsField; to private ImageSet[] imageSetsField;
change public ImageSet[][] ImageSets {...} to public ImageSet[] ImageSets {...}
finally we can run our program and it will work. good luck..
nb: i use microsoft visual studio 2010.
there will be 1 warning (invalid child element signing behaviour), i think we can ignore it, or if you have any solution please share.. ^^v..
This is a wsdl error, I use link below to fix it:
https://forums.aws.amazon.com/thread.jspa?threadID=86989

How to send an XDocument via MSMQ (using WCF)?

I have an order as an XDocument and I simply want to stick it in the body of a message and send it to an MSMQ queue. I've effectively serialized the order object already and now I just want to send it. Is this possible?
I'm using WCF here but I'd happy with a plain old msmq solution. I'm getting an error here indicating that an XDocument can't be serialized ... obviously can't do that, but how do I get my XDocument into the message body? Do I need to roll my own Serializer?
public void SendOrder(XDocument order)
{
var address = new EndpointAddress(#"msmq.formatname:DIRECT=OS:myServer\private$\myQueue");
var binding = new MsmqIntegrationBinding();
binding.Security.Mode = MsmqIntegrationSecurityMode.None;
binding.ExactlyOnce = false;
binding.Durable = false;
var channelFactory = new ChannelFactory<IOrderSubmitter>(binding, address);
var channel = channelFactory.CreateChannel();
var message = new MsmqMessage<XDocument>(order);
message.Label = "Really Big Order with lots of profit";
message.BodyType = (int)System.Runtime.InteropServices.VarEnum.VT_ARRAY;
using (var scope = new TransactionScope(TransactionScopeOption.Required))
{
channel.SubmitOrder(message);
scope.Complete();
}
}
[ServiceContractAttribute(Namespace = "http://my.namespace.com", Name = "Hello")]
public interface IOrderSubmitter
{
[OperationContract(IsOneWay = true)]
void SubmitOrder(MsmqMessage<XDocument> message);
}
An XDocument is a convenient wrapper over XML data. There is no need to serialize the XDocument, just send the XML data as a string, using XDocument.ToString()
I'm having the same problem developing on a Windows 7 box. It's putting my XML string inside another xml. Everything works just fine in server 2003.
I was finally able to fix this. There seem to be two ways to do this. Both involve setting the Formatter to XmlMessageFormatter. You can either set the Formatter on the MessageQueue or you can set it on the message before you send and after you peek/receive.
messageQueue.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(System.String) });

Categories