I am having problem to consume a WebService programmatically, using the WSDL under a squid proxy. My application is build in c# .net. I compile an Assembly from the XML, after import the service descripton using this:
// a namespace and compile unit are needed by importer
CodeNamespace codeNamespace = new CodeNamespace();
CodeCompileUnit codeUnit = new CodeCompileUnit();
codeUnit.Namespaces.Add(codeNamespace);
ServiceDescriptionImportWarnings importWarnings = descriptionImporter.Import(codeNamespace, codeUnit);
if (importWarnings == 0) // no warnings
{
// create a c# compiler
CodeDomProvider compiler = CodeDomProvider.CreateProvider("CSharp");
// include the assembly references needed to compile
string[] references = new string[2] { "System.Web.Services.dll", "System.Xml.dll" };
CompilerParameters parameters = new CompilerParameters(references);
// compile into assembly
CompilerResults results = compiler.CompileAssemblyFromDom(parameters, codeUnit);
foreach (CompilerError oops in results.Errors)
{
// trap these errors and make them available to exception object
throw new Exception("Compilation Error Creating Assembly");
}
// all done....
return results.CompiledAssembly;
}
else
{
// warnings issued from importers, something wrong with WSDL
throw new Exception("Invalid WSDL");
}
The problem is when i call the method Invoke(obj, args). Proxy cut the connection, if i call the WSDL using external address, like http://My_external_ip/my_webService.asmx. If i call using internal address, works fine.
When i add a webReference, manually, i use to do some thing like:
WebService WS = new WebService();
WS.Proxy = Proxy.credentials;
it work, but i couldn't find where to give the proxy credentials when using Assembly.
Thanks guys.
#Various,
You probebly want to write some code like this
WebService WS = new WebService();
WS.Proxy = wwwproxy("http://someproxy:8080";
WebProxy wwwproxy(string ptProxyURI)
{
var aProxy = New WebProxy;
aProxy.Credentials = CredentialCache.DefaultCredentials;
aProxy.BypassProxyOnLocal = True;
aProxy.Address = New Uri(ptProxyURI);
Return aProxy;
}
Hope it helps.
Cheers
Related
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;
}
}
}
Hey there im am running into a situation with the ServiceDescription importer.
In the code (which is pasted below) i am trying to import and compile a service reference from a WSDL file (stored locally) sadly due to customer implications i am not allowed to share this wsdl file.
However all the code runs trough well however the following line:
ServiceDescriptionImportWarnings warnings = importer.Import(nm, unit);
constantly keeps returning: ServiceDescriptionImportWarnings.NoCodeGenerated
could someone tell me if and where i am going wrong with this code ?
public string[] GenerateProxyAssembly(string pathOrURL)
{
Stream stream = File.OpenRead(pathOrURL);
ServiceDescription desc = ServiceDescription.Read(stream);
//find out the number of operations exposed by the web service
//store the name of the operations inside the string array
//iterating only through the first binding exposed as
//the rest of the bindings will have the same number
int i = 0;
Binding binding = desc.Bindings[0];
OperationBindingCollection opColl = binding.Operations;
string[] listOfOperations = new string[opColl.Count];
foreach (OperationBinding operation in opColl)
{
listOfOperations[i++] = operation.Name;
}
//initializing a ServiceDescriptionImporter object
ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
//set the protocol to SOAP 1.1
importer.ProtocolName = "Soap12";
//setting the Style to Client in order to generate client proxy code
importer.Style = ServiceDescriptionImportStyle.Client;
//adding the ServiceDescription to the Importer object
importer.AddServiceDescription(desc, null, null);
importer.CodeGenerationOptions = CodeGenerationOptions.GenerateNewAsync;
//Initialize the CODE DOM tree in which we will import the
//ServiceDescriptionImporter
CodeNamespace nm = new CodeNamespace("test");
CodeCompileUnit unit = new CodeCompileUnit();
unit.Namespaces.Add(nm);
//generating the client proxy code
ServiceDescriptionImportWarnings warnings = importer.Import(nm, unit);
if (warnings == 0)
{
//set the CodeDOMProvider to C# to generate the code in C#
System.IO.StringWriter sw = new System.IO.StringWriter();
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
provider.GenerateCodeFromCompileUnit(unit, sw, new CodeGeneratorOptions());
//creating TempFileCollection
//the path of the temp folder is hardcoded
TempFileCollection coll = new TempFileCollection(#"C:\wmpub\tempFiles");
coll.KeepFiles = false;
//setting the CompilerParameters for the temporary assembly
string[] refAssembly = { "System.dll", "System.Data.dll",
"System.Web.Services.dll", "System.Xml.dll" };
CompilerParameters param = new CompilerParameters(refAssembly);
param.GenerateInMemory = true;
param.TreatWarningsAsErrors = false;
param.OutputAssembly = "WebServiceReflector.dll";
param.TempFiles = coll;
//compile the generated code into an assembly
//CompilerResults results = provider.CompileAssemblyFromDom(param, unitArr);
CompilerResults results = provider.CompileAssemblyFromSource(param, sw.ToString());
this.assem = results.CompiledAssembly;
}
//return the list of operations exposed by the web service
return listOfOperations;
}
You don't share enough information, but i'll try to anwser.
Protocol could be the issue, i had similar problem, removing this line solved the problem
importer.ProtocolName = "Soap12";
So in my case, i was trying to connect to Soap 1.1 service with wrong protocol setting.
Soap 1.1 is default value.
Please check documentation:
https://learn.microsoft.com/en-us/dotnet/api/system.web.services.description.servicedescriptionimporter.protocolname?view=netframework-4.8
I can compile a DLL at runtime from a simple code string without any issues. Opening it in IL Spy shows exactly what it should. But if I put any extension methods in the code it outputs the following error:
error CS1644: Feature `extension methods' cannot be used because it is not part of the C# 2.0 language specification
The only help I could find says I should be able to set the "CompilerVersion" to "v3.5" by providing a dictionary of options to the code provider, but it doesn't help at all.
Here's my code:
var options = new System.Collections.Generic.Dictionary<string, string> { { "CompilerVersion", "v3.5" } };
var codeProvider = new Microsoft.CSharp.CSharpCodeProvider(options);
var provider = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("CSharp");
var parameters = new System.CodeDom.Compiler.CompilerParameters();
parameters.GenerateExecutable = false;
parameters.OutputAssembly = "AutoGen.dll";
var results = provider.CompileAssemblyFromSource(parameters, code);
Debug.Log(results.Errors.DeepToString());
I can't add the web reference from a wsdl file. I am getting an error.
But it is working normally with SoapUI.
"RPC Message getFaturaResponse in operation getKurumSTFatura has an invalid body name getFaturaResponse. It must be getKurumSTFaturaResponse"
abonePortTypeClient client = new abonePortTypeClient();
if (client.State != CommunicationState.Faulted)
{
string outresult = string.Empty;
var param35 = new AboneClient.SahaIsemri();
param35.tesisatno = 1;
param35.emirturu = 7;
param35.altemirturu = 5;
param35.elemankodu = 3208;
string resultstring = null;
var SahaIsemri = new AboneClient.SahaIsemri();
client.ClientCredentials.UserName.UserName = "XXX";
client.ClientCredentials.UserName.Password = "XXX";
var aaa = client.putSahaIsemri(param35, out resultstring, out SahaIsemri);
}
It refers that the references generated by wsdl does not match.
getFaturaResponse in operation getKurumSTFatura has an invalid body name getFaturaResponse. It must be getKurumSTFaturaResponse
You need to change the Operation in the service or you need to manually change in the reference.cs file.
Search for the particular method and rename the response as above!
#Sajeetharan's answer is fine, but I had some problems finding what I had to rename. Just in case it can help someone, you have to look for the WrapperName in the MessageContractAttribute. In the example above, it would be something like:
[System.ServiceModel.MessageContractAttribute(WrapperName="getKurumSTFatura", WrapperNamespace="xxxx", IsWrapped=true)]
public partial class getFaturaResponse {
given a url that references an asmx how would i go about displaying all of their method names?
if assembly="http://.../something/something.asmx" and i was trying to display the method names of that service what should i do now that i have gotten myself this far? i cant seem to find a solution among the hundreds of examples ive looked at
public TestReflection(string assembly)
{
Assembly testAssembly = Assembly.LoadFrom(assembly);
Type sType = testAssembly.GetType();
MethodInfo[] methodInfos = typeof(Object).GetMethods();
foreach (MethodInfo methodInfo in methodInfos)
{
Console.WriteLine(methodInfo.Name);
}
}
typeof(Object).GetMethods()
youre asking for all the methods of type object
you need to call GetMethods() on the type you want to get the methods of.
Try this:
public TestReflection(string assembly)
{
Assembly testAssembly = Assembly.LoadFrom(assembly);
Type sType = testAssembly.GetType("NamespaceOfYourClass.NameOfYourClassHere", true, true);
MethodInfo[] methodInfos = sType.GetMethods();
foreach (MethodInfo methodInfo in methodInfos)
{
Console.WriteLine(methodInfo.Name);
}
}
The idea is that in your original code, you're trying to get the methods by using typeof(Object), which will retrieve the methods of the Object type, which is not what you want.
You need to know what class the methods you're trying to grab are in. If you don't know that, replace testAssembly.GetType(... with testAssembly.GetTypes() and iterate through all the types, and getting the methods for each one.
You know, reflection aside, you can actually query the webservice's WSDL to get a list of methods. It may simplify your problem. If you're set on using reflection you'll have to find the type in the assembly and grab the methods using the other methods described in the other answers here.
You would need to look for method decorated with the [WebMethod] attribute on classes that inherit from System.Web.Services.WebService.
The code would look something like this (not tested):
public TestReflection(string assembly)
{
Assembly testAssembly = Assembly.LoadFrom(assembly); // or .LoadFile() here
foreach (Type type in testAssembly.GetTypes())
{
if (type.IsSubclassOf(typeof(System.Web.Services.WebService)))
{
foreach (MethodInfo methodInfo in type.GetMethods())
{
if (Attribute.GetCustomAttribute(methodInfo, typeof(System.Web.Services.WebMethodAttribute)) != null)
{
Console.WriteLine(methodInfo.Name);
}
}
}
}
}
so i figured out how to get what i wanted it goes something like this
[SecurityPermissionAttribute(SecurityAction.Demand, Unrestricted = true)]
internal static void LoadWebService(string webServiceAsmxUrl)
{
ParseUrl(webServiceAsmxUrl);
System.Net.WebClient client = new System.Net.WebClient();
// Connect To the web service
System.IO.Stream stream = client.OpenRead(webServiceAsmxUrl + "?wsdl");
// Now read the WSDL file describing a service.
ServiceDescription description = ServiceDescription.Read(stream);
///// LOAD THE DOM /////////
// Initialize a service description importer.
ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
importer.ProtocolName = "Soap12"; // Use SOAP 1.2.
importer.AddServiceDescription(description, null, null);
// Generate a proxy client.
importer.Style = ServiceDescriptionImportStyle.Client;
// Generate properties to represent primitive values.
importer.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;
// Initialize a Code-DOM tree into which we will import the service.
CodeNamespace nmspace = new CodeNamespace();
CodeCompileUnit unit1 = new CodeCompileUnit();
unit1.Namespaces.Add(nmspace);
// Import the service into the Code-DOM tree. This creates proxy code that uses the service.
ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit1);
if (warning == 0) // If zero then we are good to go
{
// Generate the proxy code
CodeDomProvider provider1 = CodeDomProvider.CreateProvider("CSharp");
// Compile the assembly proxy with the appropriate references
string[] assemblyReferences = new string[5] { "System.dll", "System.Web.Services.dll", "System.Web.dll", "System.Xml.dll", "System.Data.dll" };
CompilerParameters parms = new CompilerParameters(assemblyReferences);
CompilerResults results = provider1.CompileAssemblyFromDom(parms, unit1);
// Check For Errors
if (results.Errors.Count > 0)
{
foreach (CompilerError oops in results.Errors)
{
System.Diagnostics.Debug.WriteLine("========Compiler error============");
System.Diagnostics.Debug.WriteLine(oops.ErrorText);
}
Console.WriteLine("Compile Error Occured calling webservice. Check Debug ouput window.");
}
// Finally, add the web service method to our list of methods to test
//--------------------------------------------------------------------------------------------
object service = results.CompiledAssembly.CreateInstance(serviceName);
Type types = service.GetType();
List<MethodInfo> listMethods = types.GetMethods().ToList();
}
}
Paste http://.../something/something.asmx in your browser and it will give you a list of all the methods and its parameters?