Unknown 405 error on C# code + Fine tuning - c#

I started learning C# recently, and found a practical application that isn't too difficult to accomplish, but I need some help figuring out my link I'm pretty sure. Let me show you.
using System;
using System.Net;
using System.Text;
... Namespace class etc etc
Console.WriteLine("Trying...");
WebClient client = new WebClient();
var nameValue = new System.Collections.Specialized.NameValueCollection();
nameValue.Add("FIRST NAME", "myname");
nameValue.Add("LAST NAME", "mylname");
nameValue.Add("GRADE", "mygrade");
Uri uri = new Uri("https://docs.google.com/forms/d/e/1FAIpQLScB206NtDOPl4_lQfCk9SZwqKfVRARVm0dSLujSj4qkWulp3Q/viewform");
byte[] response = client.UploadValues(uri, "POST", nameValue);
string result = Encoding.UTF8.GetString(response);
The linked form is one I created to model my schools. It's an attendance form (HS senior!) and I'm just trying to get it from my email and auto fill it every morning (lol), but I'm focused on this section first. My code generates a 405:
Unhandled exception. System.Net.WebException: The remote server returned an error: (405) Method Not Allowed.
at System.Net.HttpWebRequest.GetResponse()
at System.Net.WebClient.GetWebResponse(WebRequest request)
at System.Net.WebClient.DownloadBits(WebRequest request, Stream writeStream)
at System.Net.WebClient.UploadBits(WebRequest request, Stream readStream, Byte[] buffer, Int32 chunkSize, Byte[] header, Byte[] footer)
at System.Net.WebClient.UploadValues(Uri address, String method, NameValueCollection data)
at AttendanceAutomaticac.Program.Main(String[] args) in C:\Users\Lee\source\repos\AttendanceAutomaticac\Program.cs:line 18
Edit: Can I use any apis for this that someone knows of?
Bad link probably, but it works? I found this code via a link to google on a forum, and modified it slightly to fit my form. I'm also not quite sure whether or not the 3rd value will work for a single choice answer... So, I just need any other solution / explanation, I'm not too great at debugging and problem solving errors beyond StackOverflow in C# yet as I have minimal experience with it.

Related

Error 400: Bad Request while posting through LinkedIn Share API

I have checked a bunch of questions on StackOverflow which may be termed as related but most of them are either too old or too specific, and doesn't help me much.
While working on an application that helps schedule posts on LinkedIn, I follow below process:
Allow user to Sign-up using their LinkedIn account.
After they submit for Sign-up, I store Access Token, Refresh Token and relevant TTL along with the user details.
When they schedule a post at a specific time, I have an Azure function (serverless) that checks for any post to submit every minute, and supposed to post on user's behalf.
Using the Access Tokenthat I saved earlier, I hit https://api.linkedin.com/v2/me to get the person:id of the user. Everything works as expected until here and gets the person:id using GetPersonID()
See my code below for posting using API:
string pid = GetPersonID();
sstring PostCode = #"{""content"":{""contentEntities"":[{""entityLocation"":""" + URL + #""",""thumbnails"":[{""imageSpecificContent"":{},""resolvedUrl"":""" + OriginalURL + #"""}]}],""description"":"" + URL + "",""title"":""" + Title + #"""},""distribution"":{""linkedInDistributionTarget"":{}},""owner"":""urn:li:person:" + pid + #""",""subject"":""" + Title + #""",""text"":{""text"":""" + Description + #"""}}";
string outJ = JsonConvert.SerializeObject(PostCode);
WebClient clientx = new WebClient();
clientx.Headers.Add("Authorization", "Bearer " + access_token);
clientx.Headers.Add("X-Restli-Protocol-Version", "2.0.0");
clientx.Headers.Add("x-li-format", "json");
clientx.Headers["Content-Type"] = "application/json";
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
string LinkedInAccessTokenURL = "https://api.linkedin.com/v2/shares";
string result = clientx.UploadString(LinkedInAccessTokenURL, "POST", data: outJ);
A Sample Json Post
{"content":{"contentEntities":[{"entityLocation":"http://www.test.com","thumbnails":[{"imageSpecificContent":{},"resolvedUrl":"https://picsum.photos/200/300"}]}],"description":" + URL + ","title":"This is a test post"},"distribution":{"linkedInDistributionTarget":{}},"owner":"urn:li:person:<person:id>","subject":"This is a test post for LinkedIn API","text":{"text":"ashdjahs dadjh asdjahs da\nahs djashdjkashdas\nahsd jasdhkjasdh "}}
Everything works until the last line of the above code. Upon POST the LinkedIn API throws an error System.Net.WebException: 'The remote server returned an error: (400) Bad Request.' (LinkedIn documentation reference). I've even tried posting the value in PostCode using Postman and it works perfectly fine, which tells me that the JSON generated it correct.
But despite multiple tries and fixes, nothing seems to work for actual Post.
Exception thrown:
Data: {System.Collections.ListDictionaryInternal}
HResult: -2146233079
HelpLink: null
InnerException: null
Message: "The remote server returned an error: (400) Bad Request."
Response: {System.Net.HttpWebResponse}
Source: "System.Net.Requests"
StackTrace: " at System.Net.HttpWebRequest.GetResponse()\r\n at System.Net.WebClient.GetWebResponse(WebRequest request)\r\n at System.Net.WebClient.DownloadBits(WebRequest request, Stream writeStream)\r\n at System.Net.WebClient.UploadBits(WebRequest request, Stream readStream, Byte[] buffer, Int32 chunkSize, Byte[] header, Byte[] footer)\r\n at System.Net.WebClient.UploadDataInternal(Uri address, String method, Byte[] data, WebRequest& request)\r\n at System.Net.WebClient.UploadString(Uri address, String method, String data)\r\n at System.Net.WebClient.UploadString(String address, String method, String data)"
Status: ProtocolError
TargetSite: {System.Net.WebResponse GetResponse()}
Marking as resolved.
The issue was apparently with the Json being generated. Probably it was encoding, but I'm still confused on how Postman was able to post it without any issues.
I created relevant class, and then using its object, I serialized it into Json using Newtonsoft. Which after passing to the WebClient object rendered the correct results.
Lessons learnt!
I know manually creating a JSON is never a good idea (what I actually did earlier, to save time), but at times being lazy can make you work harder than you would have in the first place. So if we're planning to do an API call with JSON as payload, its never a waste of time to create a relevant class and then serialize to Json.

Is there a way to retrieve the String the way it is actually uploaded to the server (as a whole)?

I am currently working on a OAuth2 implementation. However I am stuck on an Error 401. It seems like there is something wrong with my post request that is supposed to retrieve the access token from the Company the User logged in to. This is my code:
internal void RequestAccessToken(string code)
{
string requestBody = "grant_type="+ WebUtility.UrlEncode(GRANTTYPE)+ "&code=" + WebUtility.UrlEncode(code)+"&redirect_uri="+ WebUtility.UrlEncode(REDIRECT_URI);
WebClient client = new WebClient();
client.Headers.Add("Authorization",HeaderBase64Encode(CLIENT_ID, SECRETKEY));
var response = client.UploadString("https://thewebsiteiamcallingto.com/some/api", requestBody);
var responseString = client.OpenRead("https://thewebsiteiamcallingto.com/some/api");
}
My Questions are:
Is there anything wrong with the way I try to make the POST request ?
Is there a way to retrieve the whole string that is posted to the URI using UploadString?
P.S. I have seen this post regarding the POST creation. However I find the async part to be too complicated for my case.
Since we dont know the api documentation, I would suggest you to make a postman request and view the actual request sent and response received, and secondly make a request using your method and capture using a utility like wireshark and compare the difference.

SendGrid throws "Error while copying content to a stream"

I'm creating a Core 2.1 solution in Visual Studio 2017 where I send emails via Sendgrid. When trying to send an email via SendGrid, I get the following error:
An unhandled exception occurred while processing the request.
IOException: The server returned an invalid or unrecognized response.
System.Net.Http.HttpConnection.FillAsync() HttpRequestException: Error
while copying content to a stream.
System.Net.Http.HttpContent.LoadIntoBufferAsyncCore(Task
serializeToStreamTask, MemoryStream tempBuffer)
Here is what my code looks like. I'm entering the following in parameters:
recipients: list containing "****#gmail.com"
Subject: "Hello"
Body: Html generated via Heml. It compiles in an online editor without problem.
private async Task<bool> SendAsync(List<string> recipients, string subject, string body)
{
var client = new SendGridClient(this.configuration["Sendgrid:ApiKey"]);
var from = new EmailAddress(
this.configuration["Administration:MainEmailAddress"],
this.configuration["Administration:MainEmailName"]);
var tos = await GetRecipientsForEnvironment(recipients);
var message = MailHelper.CreateSingleEmailToMultipleRecipients(
from,
tos,
subject,
"",
body,
false);
var response = await client.SendEmailAsync(message);
return response.StatusCode == HttpStatusCode.Accepted;
}
What is the cause of this error?
It turns out that there is a known bug in Sendgrid. If the html content entered is very big, the correct error message will not be sent. Instead, this error will show up. In my case, my apiKey was not found and I should therefore have gotten an Unauthorized error message. When I changed my html into one much smaller, this gave me the correct error.
Read more about the issue here.
I'm having the same problem, but in my case it's because the email quota has expired (I'm using the free version for testing):
Lib version 9.21.0
On the mentioned thread https://github.com/sendgrid/sendgrid-csharp/issues/648 some people were passing the wrong apiKey, and others exceeding the HTML size.
As said in the thread above, apparently it's a bug in the sendgrid library when interpreting the error.
Therefore, in addition to the problems mentioned (passing the wrong apiKey, exceeding the HTML size) the return “Error while copying content to a stream” is hiding other problems as well (like in my case: quota expired).

How to create an otrs ticket using a soap request

The lack of documentation on this subject coupled with the fact that I'm struggling with a learning curve on all fronts and making me really confused about where to start. I need to get this done using C# if possible. I apologize for the vagueness of this question, but I'm really lost. I would love links to comprehensive guides/references.
In my efforts to get this done, I've run into the following problems/questions:
I've created a web service using the otrs gui, with the operation CreateTicket, but requests via C# to my chosen namespace are returning 404 (not found). When I try to add a service reference or web reference with that namespace, I get the same error. However, when I plug that namespace into my browser as the url, it displays "customer.pl".
Can I send a soap request without adding the web service as a service reference in visual studio? Given the previous problem I'm having I can't do it that way. Would I just build the soap request string and write it to the web request's data stream with http://domain/rpc.pl as the uri?
If the answer to the previous question is yes... When trying the below code segment I get an internal server error (500) on the last line. However the header looks like a SOAP header which confuses me because I wouldn't have thought it got that far.
var document = new StringBuilder();
document.Append("<UserLogin>some user login</UserLogin>");
document.Append("<Password>some password</Password> ");
document.Append("<Ticket>");
document.Append("<Title>some title</Title> ");
document.Append("<CustomerUser>some customer user login</CustomerUser>");
document.Append("<Queue>some queue</Queue>");
document.Append("<State>some state</State>");
document.Append("<Priority>some priority</Priority>");
document.Append("</Ticket>");
document.Append("<Article>");
document.Append("<Subject>some subject</Subject>");
document.Append("<Body>some body</Body>");
document.Append("<ContentType>text/plain; charset=utf8</ContentType>");
document.Append("</Article>");
//var uri = new Uri("http://domain/injest");
var uri = new Uri("http://domain/rpc.pl");
var httpWebReq = (HttpWebRequest)WebRequest.Create(uri);
var bytePostData = Encoding.UTF8.GetBytes(document.ToString());
httpWebReq.Timeout = 5 * 1000;
httpWebReq.Method = "POST";
httpWebReq.ContentLength = bytePostData.Length;
httpWebReq.ContentType = "text/xml;charset=utf-8";
//httpWebReq.TransferEncoding=
//httpWebReq.ContentType = "application/xml";
//httpWebReq.Accept = "application/xml";
var dataStream = httpWebReq.GetRequestStream();
dataStream.Write(bytePostData, 0, bytePostData.Length);
dataStream.Close();
var httpWebResponse = (HttpWebResponse)httpWebReq.GetResponse();
Even if all you can offer is where to start, it would help me to know how to proceed, as I'm stumped.
You're using the rpc.pl endpoint which is part of the 'old' RPC-style interface.
You mention you added the web service via the GUI which means you're using the 'new' Generic Interface, which is indeed much easier from .Net.
The address of the endpoint is /otrs/nph-genericinterface.pl/Webservice/GenericTicketConnector or whatever you have called the web service in the admin section.

Posting using POST from C# over https

After wasting two days with this question (and trying to make it work), I've decided to take a step back and ask a more basic question, because apparently there's something I don't know or I'm doing wrong.
The requirements are simple, I need to make an HTTP post (passing a few values) over https from C#.
The website (if given the appropriate values) will return some simple html and a response code. (i'll show these later).
It's really that simple. The "webservice" works. I have a php sample that works and successfully connects to it. I also have a Dephi "demo" application (with source code) that also works. And finally I have the demo application (binary) from the company that has the "service", that also works of course.
But I need to do it through C#. That that sounds so simple, it is not working.
For testing purposes I've created a simple console app and a simple connect method. I've tried like 7 different ways to create an HTTP request, all more or less the same thing, different implementation (Using WebClient, using HttpWebRequest, etc).
Every method works, except when the URI begins with 'https'.
I get a webexception saying that the remote server returned 404. I've installed Fiddler (as suggested by a SO user), and investigated a little bit the traffic. The 404 is because I am passing something wrong, because as I mentioned later, the 'service' works. I'll talk about the fiddler results later.
The URL where I have to POST the data is: https://servicios.mensario.com/enviomasivo/apip/
And this is the POST data: (the values are fakes)
usuario=SomeUser&clave=SomePassword&nserie=01234567890123456789&version=01010000&operacion=220
The server might return a two/three lines response (sorry about the spanish, but the company is from Spain). Here's a sample of a possible response:
HTTP/1.1 200 OK
Content-Type: text/plain
01010000 100 BIEN
998
And here's another
HTTP/1.1 200 OK
Content-Type: text/plain
01010000 20 AUTENTIFICACION NEGATIVA
Ha habido un problema en la identificación ante el servidor. Corrija sus datos de autentificacion.
The 1st one means OK, and the 2nd one is Auth Failure.
As you can see the task is quite easy, only it doesn't work. If I use fiddler, I see that there's some sort of SSL stuff going on in the connection and then everything works fine. However, as far as I've read, .NET handles all that stuff for us (yes, i've added the callback to always validate invalid certs). I don't understand what I'm doing wrong. I can post/email the code, but what I'd like to know is very simple:
How can you make a POST over SSL using C# and a "simple" HttpWebRequest and later have the response in a string/array/Whatever for processing?
Trust me when I say I've been googling and Stackoverflowing for two days. I don't have any sort of proxy. The connection passes through my router. Standard ports. Nothing fancy. My Machine is inside a VMWare virtual machine and is Windows Vista, but given that the sample applications (php, delphi, binary) all work without an issue, I cannot see that as a problem).
The different samples (sans the binary) are available here if anyone wants to take a look at them.
I'd appreciate any help. If anyone wants to try with a "real" username, I have a demo user and I could pass you the user/pass for testing purposes. I only have one demo user (the one they gave me) and that's why I'm not pasting it here. I don't want to flood the user with tests ;)
I've tried (within the samples) using UTF8 and ASCII, but that didn't change anything.
I am 100% positive that there's something I have to do with SSL and I am not doing it because I don't know about it.
Thanks in advance.
Martín.
I was battling with the exact same problem a bit earlier (although in compact framework). Here's my question and my own answer to it:
Asynchronous WebRequest with POST-parameters in .NET Compact Framework
My version is asynchronous, so it's a bit more complex than what you're looking for, but the idea remains.
private string sendRequest(string url, string method, string postdata) {
WebRequest rqst = HttpWebRequest.Create(url);
// only needed, if you use HTTP AUTH
//CredentialCache creds = new CredentialCache();
//creds.Add(new Uri(url), "Basic", new NetworkCredential(this.Uname, this.Pwd));
//rqst.Credentials = creds;
rqst.Method = method;
if (!String.IsNullOrEmpty(postdata)) {
//rqst.ContentType = "application/xml";
rqst.ContentType = "application/x-www-form-urlencoded";
byte[] byteData = UTF8Encoding.UTF8.GetBytes(postdata);
rqst.ContentLength = byteData.Length;
using (Stream postStream = rqst.GetRequestStream()) {
postStream.Write(byteData, 0, byteData.Length);
postStream.Close();
}
}
((HttpWebRequest)rqst).KeepAlive = false;
StreamReader rsps = new StreamReader(rqst.GetResponse().GetResponseStream());
string strRsps = rsps.ReadToEnd();
return strRsps;
}
see my answer to your other question. I believe your problem may not be your C# code. The web service URL accually returns a 404 with several other tools I used, but it returns the response you indicated if you leave off the trailing slash from the web service URL, so I suggest trying that.
Oddly, it doesn't seem to matter if the trailing URL is there when not doing SSL. Something strange with that web server, I guess.
dont know if u already resolved this issue, it´s a post from one year ago. I am Spanish and I am using mensario too.
to send and http request: (this is in ASP but the process is the same one)
Function enviarMsg2
Dim oHTTP,inicio
Dim strParametros
Dim devolver
Set oHTTP= server.CreateObject("Msxml2.ServerXMLHTTP")
strParametros = "usuario="&usuario&"&clave="&clave&"&nserie="&nserie&"& version=01010000&operacion=300&sms=1%0934635035526%0920041231233000%09Clinica+Paz%09Clinica+Paz+le+desea+Feliz+Navidad%2E&sms=2%0934612345678%0920041231233001%09Clinica+Paz%09Clinica+Paz+le+desea+Feliz+Navidad%2E"
'response.Write strParametros
'response.End
'Abrimos la conexión con el método POST, ya que estamos enviando una petición.
oHTTP.open "POST", "https://servicios.mensario.com/enviomasivo/apip", False
'Agregamos encabezados HTTP requeridos...
oHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
'Enviamos la petición
oHTTP.send strParametros
devolver = oHTTP.responsetext
'Comprobamos si fue correcto
inicio = Instr(devolver, "100 BIEN")
'response.Write "--->"&inicio
'response.End
if inicio <=0 then
enviarSMS2 = "Ha ocurrido un error en el envío del SMS."
else
enviarSMS2 = Mid(devolver,inicio+9,len(devolver))
end if
Set oHTTP = Nothing
The only thing i dont have is a user /password for a try :)
Basicaly, when the response is "100 bien" the function returns that, otherwise it returns error.Hope it helps :)

Categories