Call All Operations In ASMX Programmatically - c#

Assume there exists a generic string collection that contains a variety of web service URLs:
List<string> webServiceCollection = new List<string>();
webServiceCollection.Add("http://<site>/_vti_bin/Lists.asmx");
webServiceCollection.Add("http://<site>/_vti_bin/Sites.asmx");
There a variety of methods, with a variety of input and return types in each web service. Is it possible to read the all the available operations and attempt the operation with default values? For this purpose, I am trying to write a security tool that will help test whether the web service allows the user to interact with them under a variety of accounts as an academic exercise.

You can do something like this:
PSEUDO CODE
System.Net.WebClient client = new System.Net.WebClient();
string strUrl = #"http://localhost:xxxxx/Service.asmx?wsdl";
System.IO.Stream stream = client.OpenRead(strUrl);
string serviceName = "Service";
// Get a WSDL file describing a service.
ServiceDescription description = ServiceDescription.Read(stream);
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)
{
// Generate and print the proxy code in C#.
CodeDomProvider provider1 = CodeDomProvider.CreateProvider("CSharp");
// Compile the assembly with the appropriate references
string[] assemblyReferences = new string[2] { "System.Web.Services.dll", "System.Xml.dll" };
CompilerParameters parms = new CompilerParameters(assemblyReferences);
CompilerResults results = provider1.CompileAssemblyFromDom(parms, unit1);
foreach (CompilerError oops in results.Errors)
{
Console.WriteLine("========Compiler error============");
Console.WriteLine(oops.ErrorText);
}
//Invoke the web service method
foreach (PortType portType in description.PortTypes)
{
foreach (Operation operation in portType.Operations)
{
try
{
object o = results.CompiledAssembly.CreateInstance(serviceName);
Type t = o.GetType();
Console.WriteLine(t.InvokeMember(operation.Name, System.Reflection.BindingFlags.InvokeMethod, null, o, null));
}catch(Exception ex){
Console.WriteLine(ex.Message);
}
}
}
}
else
{
// Print an error message.
Console.WriteLine("Warning: " + warning);
}

this will be your best attempt to try and achieve your goal:
string completeUrl ="http://localhost/testwebservice";
// Create a request for the URL.
WebRequest request = WebRequest.Create(completeUrl);
// If required by the server, set the credentials.
request.Credentials = CredentialCache.DefaultCredentials;
// If you have a proxy configured.
WebProxy proxyObject = new WebProxy("http://proxy.com/", true);
request.Proxy = proxyObject;
//Get the response.
using(HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
// Get the stream containing content returned by the server.
using(Stream dataStream = response.GetResponseStream())
{
// Open the stream using a StreamReader for easy access.
using(StreamReader reader = new StreamReader(dataStream))
{
// Read the content.
string responseFromServer = reader.ReadToEnd();
}
}
}
and in order to add your try you should do:
List<string> webServiceCollection = new List<string>();
webServiceCollection.Add("http://<site>/_vti_bin/Lists.asmx");
webServiceCollection.Add("http://<site>/_vti_bin/Sites.asmx");
foreach(var reqeust in webServiceCollection)
{
string completeUrl = $"{request}";;
// Create a request for the URL.
WebRequest request = WebRequest.Create(completeUrl);
// If required by the server, set the credentials.
request.Credentials = CredentialCache.DefaultCredentials;
// If you have a proxy configured.
WebProxy proxyObject = new WebProxy("http://proxy.com/", true);
request.Proxy = proxyObject;
//Get the response.
using(HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
// Get the stream containing content returned by the server.
using(Stream dataStream = response.GetResponseStream())
{
// Open the stream using a StreamReader for easy access.
using(StreamReader reader = new StreamReader(dataStream))
{
// Read the content.
string responseFromServer = reader.ReadToEnd();
}
}
}
}

Related

Use a stream directly to a parsing instead of saving a file

I mean, this is piece of my code:
// Create the web request (posts/1)
HttpWebRequest request = WebRequest.Create("https://jsonplaceholder.typicode.com/posts/1") as HttpWebRequest;
// Get response
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
{
string myString = reader.ReadToEnd();
System.IO.File.WriteAllText(#"C:\Users\admin\Documents\Visual Studio 2015\Projects\WriteText.json", myString);
}
// JSON deserialize from a file
String JSONstring = File.ReadAllText(#"C:\Users\admin\Documents\Visual Studio 2015\Projects\WriteText.json");
// List<PARSE> pList = JsonConvert.DeserializeObject<List<PARSE>>(JSONstring);
PARSE pList = JsonConvert.DeserializeObject<PARSE>(JSONstring);
How can I do this thing without saving the stream and again loading it to a string. I want use my stream directly to a String 'JSONstring' and then parse it.
Your code contains solution
// Create the web request (posts/1)
HttpWebRequest request = WebRequest.Create("https://jsonplaceholder.typicode.com/posts/1") as HttpWebRequest;
// Get response
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
{
//string myString = reader.ReadToEnd();
//System.IO.File.WriteAllText(#"C:\Users\admin\Documents\Visual Studio 2015\Projects\WriteText.json", myString);
}
// JSON deserialize from a file
// String JSONstring = File.ReadAllText(#"C:\Users\admin\Documents\Visual Studio 2015\Projects\WriteText.json");
// List<PARSE> pList = JsonConvert.DeserializeObject<List<PARSE>>(JSONstring);
PARSE pList = JsonConvert.DeserializeObject<PARSE>(reader.ReadToEnd());
reader.close();
Here's an example of how to parse an HTTP stream into a Json (with no error handling). Play with it and let us know if you run into anything specific. In this code. API_Json is the class with the deserialized classes, and I am deserializing API_Json.RootObject:
public async Task<API_Json.RootObject> walMart_Lookup(string url)
{
lookupIsWorking = true;
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
using (HttpClient http = new HttpClient(handler))
{
http.DefaultRequestHeaders.AcceptEncoding.Add(new System.Net.Http.Headers.StringWithQualityHeaderValue("gzip"));
http.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite);
url = String.Format(url);
using (var response = await http.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
{
Console.WriteLine(response);
var serializer = new JsonSerializer();
using (StreamReader sr = new StreamReader(await response.Content.ReadAsStreamAsync()))
{
using (var jsonTextReader = new JsonTextReader(sr))
{
var root = serializer.Deserialize<API_Json.RootObject>(jsonTextReader);
lookupIsWorking = false;
return root;
}
}
//var obj = (API_Json_Special_Feeds.RootObject)serializer.Deserialize(sr, typeof(API_Json_Special_Feeds.RootObject));
//return obj;
}
}
}

How can I call a SOAP Web Service without Adding Web Reference

I require developing a .NET 4.5 Client for a SOAP based web service. The problem is the company who are developing these SOAP based services do not provide WSDLs. However they do provide the request response schemas (XSD files). Since there are no WSDLs I'm unable to add a web reference and get the client proxy code autogenerated.
Are there any .NET 4.5 libraries out there that I can use to make these SOAP base service calls? It needs to support SOAP 1.1 and SOAP attachements too.
If for some reason you don't want to create the WSDL file, the example below could be used to manually construct a SOAP HTTP request:
var url = Settings.Default.URL; //'Web service URL'
var action = Settings.Default.SOAPAction; //the SOAP method/action name
var soapEnvelopeXml = CreateSoapEnvelope();
var soapRequest = CreateSoapRequest(url, action);
InsertSoapEnvelopeIntoSoapRequest(soapEnvelopeXml, soapRequest);
using (var stringWriter = new StringWriter())
{
using (var xmlWriter = XmlWriter.Create(stringWriter))
{
soapEnvelopeXml.WriteTo(xmlWriter);
xmlWriter.Flush();
}
}
// begin async call to web request.
var asyncResult = soapRequest.BeginGetResponse(null, null);
// suspend this thread until call is complete. You might want to
// do something usefull here like update your UI.
var success = asyncResult.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5));
if (!success) return null;
// get the response from the completed web request.
using (var webResponse = soapRequest.EndGetResponse(asyncResult))
{
string soapResult;
var responseStream = webResponse.GetResponseStream();
if (responseStream == null)
{
return null;
}
using (var reader = new StreamReader(responseStream))
{
soapResult = reader.ReadToEnd();
}
return soapResult;
}
private static HttpWebRequest CreateSoapRequest(string url, string action)
{
var webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("SOAPAction", action);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
return webRequest;
}
private static XmlDocument CreateSoapEnvelope()
{
var soapEnvelope = new XmlDocument();
soapEnvelope.LoadXml(Settings.Default.SOAPEnvelope); //the SOAP envelope to send
return soapEnvelope;
}
private static void InsertSoapEnvelopeIntoSoapRequest(XmlDocument soapEnvelopeXml, HttpWebRequest webRequest)
{
using (Stream stream = webRequest.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}
}

How can I simultaneously pass args and upload a file to a Web API Controller Method?

I decided that my question here isn't really what I want to do - the XML I need to send is a lot longer, potentially, than I really want to send in a URI.
It didn't "feel" right doing that, and this unsealed the deal.
I need to send both a couple of args AND a file to my Web API app from a client (handheld/CF) app.
I may have found the code for receiving that, from here [
http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2]
Specifically, Wasson's Controller code here looks like it very well might work:
public async Task<HttpResponseMessage> PostFile()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
try
{
StringBuilder sb = new StringBuilder(); // Holds the response body
// Read the form data and return an async task.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the form data.
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
sb.Append(string.Format("{0}: {1}\n", key, val));
}
}
// This illustrates how to get the file names for uploaded files.
foreach (var file in provider.FileData)
{
FileInfo fileInfo = new FileInfo(file.LocalFileName);
sb.Append(string.Format("Uploaded file: {0} ({1} bytes)\n", fileInfo.Name, fileInfo.Length));
}
return new HttpResponseMessage()
{
Content = new StringContent(sb.ToString())
};
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
...but now I need to know how to send it; other calls from the client are of the form:
http://<IPAddress>:<portNum>/api/<ControllerName>?arg1=Bla&arg2=Blee
but how does the file I need to send/attach get passed along? It is a XML file, but I don't want to append the whole thing to the URI, as it can be quite large, and doing so would be horrendously weird.
Does anybody know how to accomplish this?
UPDATE
Following the crumbs tvanfosson dropped below, I found code here which I think I can adapt to work on the client:
var message = new HttpRequestMessage();
var content = new MultipartFormDataContent();
foreach (var file in files)
{
var filestream = new FileStream(file, FileMode.Open);
var fileName = System.IO.Path.GetFileName(file);
content.Add(new StreamContent(filestream), "file", fileName);
}
message.Method = HttpMethod.Post;
message.Content = content;
message.RequestUri = new Uri("http://localhost:3128/api/uploading/");
var client = new HttpClient();
client.SendAsync(message).ContinueWith(task =>
{
if (task.Result.IsSuccessStatusCode)
{
//do something with response
}
});
...but that depends on whether the Compact Framework supports MultipartFormDataContent
UPDATE 2
Which it doesn't, according to How can i determine which .Net features the compact framework has?
UPDATE 3
Using the Bing Search Code for C# extension, I mashed "h", chose "How do I", entered "send file via http" and got this:
WebRequest request = WebRequest.Create("http://www.contoso.com/PostAccepter.aspx ");
request.Method = "POST";
string postData = "This is a test that posts this string to a Web server.";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
WebResponse response = request.GetResponse();
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
Console.WriteLine(responseFromServer);
reader.Close();
dataStream.Close();
response.Close();
As I need to add a couple of string args in addition to the file (which I assume I can add via the postData byte array), can I do that by adding more calls to dataStream.Write()? IOW, is this sensible (first and third lines differ):
WebRequest request = WebRequest.Create("http://MachineName:NNNN/api/Bla?str1=Blee&str2=Bloo");
request.Method = "POST";
string postData = //open the HTML file and assign its contents to this, or make it File postData instead of string postData?
// the rest is the same
?
UPDATE 4
Progress: This, such as it is, is working:
Server code:
public string PostArgsAndFile([FromBody] string value, string serialNum, string siteNum)
{
string s = string.Format("{0}-{1}-{2}", value, serialNum, siteNum);
return s;
}
Client code (from Darin Dimitrov in this post):
private void ProcessRESTPostFileData(string uri)
{
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
var data = "=Short test...";
var result = client.UploadString(uri, "POST", data);
//try this: var result = client.UploadFile(uri, "bla.txt");
//var result = client.UploadData()
MessageBox.Show(result);
}
}
Now I need to get it sending a file instead of a string in the [FromBody] arg.
You should look into using multipart/form-data with a custom media type formatter that will extract both the string properties and the uploaded XML file.
http://lonetechie.com/2012/09/23/web-api-generic-mediatypeformatter-for-file-upload/

C2DM server side C# web service Error=InvalidRegistration

I have searched everywhere and have not found an answer to my question. Let me get straight to the point. I have developed an android messaging app for the purpose of experimenting with C2DM. My app get's the registration ID and it gets displayed in my Log correctly. I then send that key through to my C# web service.
The C# Web service then applies for an auth token, which works fine. No problem so far. But, as soon as I POST my body items (registration_id, collapse_key, data.<key>, delay_while_idle) with my header(GoogleLogin auth=[AUTH_TOKEN]) I get the response: "Error=InvalidRegistration".
There is no reason for this not to work. And yes, I have tried every solution available here in stack overflow, but remained unsuccessful. Here is my main code for my server side:
WebRequest theRequest;
HttpWebResponse theResponse;
ArrayList theQueryData;
theRequest = WebRequest.Create("https://www.google.com/accounts/ClientLogin");
theRequest.Method = "POST";
theQueryData = new ArrayList();
String [] test = new String[5];
test[0] = "accountType=HOSTED_OR_GOOGLE";
test[1] = "Email=XXXXXXXXXXXXXXXXX";
test[2] = "Passwd=XXXXXXXXXXXXXXXX";
test[3] = "Source=Domokun";
test[4] = "service=ac2dm";
// Set the encoding type
theRequest.ContentType = "application/x-www-form-urlencoded";
// Build a string containing all the parameters
string Parameters = String.Join("&", (String[])test);
theRequest.ContentLength = Parameters.Length;
// We write the parameters into the request
StreamWriter sw = new StreamWriter(theRequest.GetRequestStream());
sw.Write(Parameters);
sw.Close();
// Execute the query
theResponse = (HttpWebResponse)theRequest.GetResponse();
StreamReader sr = new StreamReader(theResponse.GetResponseStream());
String value = sr.ReadToEnd();
String token = ParseForAuthTokenKey(value);
String value2 = "";
if (value != null)
{
WebRequest theRequest2;
HttpWebResponse theResponse2;
ArrayList theQueryData2;
theRequest2 = WebRequest.Create("http://android.clients.google.com/c2dm/send");
theRequest2.Method = "POST";
theQueryData2 = new ArrayList();
String[] test2 = new String[4];
test[0] = "registration_id=" + registerid;
test[1] = "collapse_key=0";
test[2] = "data.payload=Jannik was hier";
test[3] = "delay_while_idle=0";
// Set the encoding type
theRequest2.ContentType = "application/x-www-form-urlencoded";
// Build a string containing all the parameters
string Parameters2 = String.Join("&", (String[])test2);
theRequest2.ContentLength = Parameters2.Length;
theRequest2.Headers.Add(HttpRequestHeader.Authorization, "GoogleLogin auth=" + token);
// We write the parameters into the request
StreamWriter sw2 = new StreamWriter(theRequest2.GetRequestStream());
sw2.Write(Parameters2);
sw2.Close();
// Execute the query
theResponse2 = (HttpWebResponse)theRequest2.GetResponse();
StreamReader sr2= new StreamReader(theResponse2.GetResponseStream());
value2 = sr2.ReadToEnd();
public static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
return true;
}
private static string ParseForAuthTokenKey(string webResponse)
{
string tokenKey = String.Empty;
if (webResponse.Contains(AuthTokenHeader))
{
tokenKey = webResponse.Substring(webResponse.IndexOf(AuthTokenHeader) + AuthTokenHeader.Length);
if (tokenKey.Contains(Environment.NewLine))
{
tokenKey.Substring(0, tokenKey.IndexOf(Environment.NewLine));
}
}
return tokenKey.Trim();
}
All I can think is that my C2DM account isn't registered correctly. Could this be it? Or are there an error in my code that I'm missing?
OK. I've found the solution.
string requestBody = string.Format("registration_id={0}&collapse_key{1}&data.key=value",
HttpUtility.UrlEncode(registrationId), "collapse");
string responseBody = null;
WebHeaderCollection requestHeaders = new WebHeaderCollection();
WebHeaderCollection responseHeaders = null;
requestHeaders.Add(HttpRequestHeader.Authorization, string.Format("GoogleLogin auth={0}", authToken));
httpClient.DoPostWithHeaders(c2dmPushUrl,
requestBody,
"application/x-www-form-urlencoded",
out responseBody,
out responseHeaders,
requestHeaders);
public bool DoPostWithHeaders(string url,
string requestBody,
string contextType,
out string responseBody,
out WebHeaderCollection responseHeaders,
WebHeaderCollection requestHeaders = null)
{
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
// FIRST SET REQUEST HEADERS
httpWebRequest.Headers = requestHeaders;
httpWebRequest.Method = "POST";
// THEN SET CONTENT TYPE - THE ORDER IS IMPORTANT
httpWebRequest.ContentType = contextType;
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] data = encoding.GetBytes(requestBody);
httpWebRequest.ContentLength = data.Length;
stream = httpWebRequest.GetRequestStream();
stream.Write(data, 0, data.Length);
....
....
....
}

Can I create dynamic web service client reference without adding its reference to service references of the project?

I need to create dynamic references of multiple web services and sent some value with it.
To be truly dynamic, you have to do three things:
1) Get the service description (wsdl) from the web service
2) Generate the proxy code dynamically from the service description
3) Compile the code and expose it in your application - usually through reflection or some sort of dynamic scripting interface.
The code snippet below is from some experimenting I did a long time ago. It is not production code and won't compile, but should give you a head start if this is the direction you want to go.
It does not include step (3). The code generated can be compiled with classes provided in the System.CodeDom.Compiler namespace.
Uri uri = new Uri(_Url + "?wsdl");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AllowAutoRedirect = true;
request.PreAuthenticate = false;
if (_User.Length > 0)
{
request.UseDefaultCredentials = false;
request.Credentials = new NetworkCredential(_User, _Password, _Domain);
}
WebResponse response = null;
try
{
response = request.GetResponse();
}
catch (System.Net.WebException wex)
{
response = wex.Response;
}
catch (Exception ex)
{
}
Stream requestStream = response.GetResponseStream();
ServiceDescription sd = ServiceDescription.Read(requestStream);
_ReferenceName = _Namespace + "." + sd.Services[0].Name;
ServiceDescriptionImporter Importer = new ServiceDescriptionImporter();
Importer.AddServiceDescription(sd, string.Empty, string.Empty);
Importer.ProtocolName = "Soap12";
Importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties;
CodeNamespace nameSpace = new CodeNamespace(_Namespace);
CodeCompileUnit ccu = new CodeCompileUnit();
ccu.Namespaces.Add(nameSpace);
ServiceDescriptionImportWarnings warnings = Importer.Import(nameSpace, ccu);
if (warnings == 0)
{
StringWriter sw = new StringWriter(System.Globalization.CultureInfo.CurrentCulture);
Microsoft.CSharp.CSharpCodeProvider prov = new Microsoft.CSharp.CSharpCodeProvider();
CodeGeneratorOptions options = new CodeGeneratorOptions();
options.BlankLinesBetweenMembers = false;
options.BracingStyle = "C";
prov.GenerateCodeFromNamespace(nameSpace, sw, options);
_ProxySource = sw.ToString();
sw.Close();
}
I don't have the code right now but I know this can be done, in fact in a former company I have worked we did have a generic web service client developed in house.
have a lock here:
Generic Web Service Proxy

Categories

Resources