In our MVC 5 site we have a VerifyEmail method that contacts a service to check that an email exists. We do the basic preliminary checks, to make sure it looks like a valid email, etc, then we pass it to the service.
We're using a WebClient.DownloadString() function. When we navigate to the appropriate View and trigger the method, we get these errors:
When debugging:
<h2>Bad Request - Invalid Hostname</h2>
<hr><p>HTTP Error 400. The request hostname is invalid.</p>
When we're not debugging, we get this:
System.Net.WebException: Unable to connect to the remote server --->
System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it 127.0.0.1:63595
at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception)
--- End of inner exception stack trace ---
If I call the method (VerifyEmailOrgEmailVerificationClient.VerifyEmail) from LinqPad it works!!!
I get this:
MX record about emailserver.com exists.<br/>
Connection succeeded to emailserver-com.mail.protection.outlook.com SMTP.<br/>
220 SN1NAM01FT022.mail.protection.outlook.com Microsoft ESMTP MAIL Service ready at Mon, 29 Feb 2016 21:08:50 +0000<br/>
> HELO verify-email.org<br/>
250 SN1NAM01FT022.mail.protection.outlook.com Hello [verify-email.org]<br/>
> MAIL FROM: <check#verify-email.org><br/>
=250 2.1.0 Sender OK<br/>
> RCPT TO: <redacted#emailserver.com><br/>
=250 2.1.5 Recipient OK<br/>
That's what we should get. So, the code works from LinqPad, but not when we call it as a website. We put a test method together and get the same results. With our test, we're just trying to get a response from WebClient.DownloadString(). Even like that we get an error.
Here's our test method:
using System;
using System.IO;
using System.Net;
using System.Web.Mvc;
using PublicationSystem.ViewModels;
namespace TestWebClient.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
var newModel = new TestViewModel();
using (var webClient = new WebClient())
{
webClient.Encoding = System.Text.Encoding.UTF8;
webClient.Headers["Content-Type"] = "application/json;charset=UTF-8";
var requestUrl = string.Empty;// GetRequestUrl(email);
try
{
requestUrl =
"http://api.verify-email.org/api.php?usr=igiglobal&pwd=emailsareweak&check=mkenyon#mkptechnologies.com";
newModel.ResponseString = webClient.DownloadString(requestUrl);
}
catch (WebException exception)
{
string responseText;
if (exception.Response != null)
{
using (var reader = new StreamReader(exception.Response.GetResponseStream()))
{
responseText = reader.ReadToEnd();
}
newModel.ResponseString = responseText;
}
else
{
newModel.ResponseString = exception.ToString();
}
}
catch (Exception exception)
{
newModel.ResponseString = exception.ToString();
}
}
return View(newModel);
}
Our AppPool is set for .Net 4.0. The app compiles for .Net 4.5. We're using MVC 5.
Any idea why our method, specifically the WebClient.DownloadString() fails while we're running the site, but works if we call the code from LinqPad?
UPDATE: I created a new MVC project with Visual Studio 2013, just like this project. In the new test project, I pasted the same code, and have tried to get the references to match as exactly as possible. My code works in the test project. So something with the way my project is set up is blocking WebClient.DownloadString(). Using Fiddler, it looks like it doesn't even send the request out.
Is there a setting that could block WebClient.DownloadString() while testing an MVC site?
UPDATE 2: In the web.config I found this. Could this be it?
<system.net>
<defaultProxy>
<proxy proxyaddress="http://localhost:63595/" />
</defaultProxy>
</system.net>
In the web.config I found this. Commenting it out let WebClient.DownloadString() work again. Hope this helps somebody. I'll have to do more research on this.
<system.net>
<defaultProxy>
<proxy proxyaddress="http://localhost:63595/" />
</defaultProxy>
</system.net>
Related
I'm migrating my existing console app to a web app. I'm making an api call in the controller. The below code works perfectly in console app. But in web app,i get exception at
var result = webClient.DownloadString(sourceUrl);
with the message "unable to connect to remote server" and the inner exception says {"A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond}System.Exception {System.Net.Sockets.SocketException}
I have tried to pass the url as uri object, edited web.config file to include default credentials, servicepointmanager etc. I have also tried to make it asynchronous using async and await. I really do not know what is going on. I'm behind a corporate proxy but the api call works perfectly in console app and Postman.
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web.Http;
namespace webApp.Controllers
{
public class DataController : ApiController
{
private string sourceUrl="http://api.openweathermap.org/data/2.5/weather?zip=94040,us&appid=YOURID";
[Route("")]
public void GetAlldata()
{
var dataCall = DownloadData(sourceUrl);
}
private string DownloadData(string url)
{
try
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var webClient = new WebClient();
IWebProxy wp = WebRequest.DefaultWebProxy;
wp.Credentials = CredentialCache.DefaultCredentials;
webClient.Proxy = wp;
var result = webClient.DownloadString(sourceUrl);
return result;
}
catch (Exception ex)
{
return ex.Message;
}
}
}
}
Just to mention that after trying the above code in my home network and it worked, I pinpointed the problem to be a proxy issue. Removing the below from my code
IWebProxy wp = WebRequest.DefaultWebProxy;
wp.Credentials = CredentialCache.DefaultCredentials;
webClient.Proxy = wp;
and explicitly adding the below to web.config fixed it. I don't know why web app doesn't pickup the default proxy from code but console app does. Any explanation for this behavior will be appreciated.
<system.net>
<defaultProxy>
<proxy usesystemdefault="False" proxyaddress="http://proxy.MYCOMPANY.com:8080" bypassonlocal="True" />
</defaultProxy>
</system.net>
Íf above solution(cmoe's answer) don't work for your case. May be The console app pass proxy but other app drop by firewall. Check firewall settings.
I'm working on an integration with Alternative Payments using their hosted page integration. Their C# SDK does not have this integration available at the moment, but as you can see it's pretty simple and I made a small class to send the post request and get the JSON response.
I tested the json object I'm sending on PostMan and cURL and both work, also the authentication header, so I think they are not the problem. Here is the constructor of my class:
public AlternativePaymentsCli(string apiSecretKey)
{
this._apiSecretKey = apiSecretKey;
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var authInfo = _apiSecretKey;
authInfo = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:", _apiSecretKey)));
// The two line below because I saw in an answer on stackoverflow.
_httpClient.DefaultRequestHeaders.Add("Connection", "Keep-Alive");
_httpClient.DefaultRequestHeaders.Add("Keep-Alive", "3600");
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Anything.com custom client v1.0");
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authInfo);
}
And the method where I'm posting the data:
public string CreateHostedPageTransaction(HostedPageRequest req)
{
var settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
// I send this same json content on PostMan and it works. The json is not the problem
var content = new StringContent(JsonConvert.SerializeObject(req, settings), Encoding.UTF8, "application/json");
var response = _httpClient.PostAsync(this._baseUrl + "/transactions/hosted", content).Result;
var responseText = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
if (response.IsSuccessStatusCode)
return responseText;
return "";
}
Then I get this error: An existing connection was forcibly closed by the remote host, at the PostAsync line. This is the error details:
[SocketException (0x2746): An existing connection was forcibly closed by the remote host]
System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult) +8192811
System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult) +47
[IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.]
System.Net.TlsStream.EndWrite(IAsyncResult asyncResult) +294
System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar) +149
[WebException: The underlying connection was closed: An unexpected error occurred on a send.]
System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context) +324
System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar) +137
[HttpRequestException: An error occurred while sending the request.]
I'm using C# 4.5, Asp.Net MVC. I've been reading answers for the same error and none of them solved my issue so far. What am I missing in this code?
Thanks for any help
I don't see in your code sample where you are setting the value of _baseUrl, but I'm assuming that is being done somewhere. I'm also assuming that since this related to payments, the URL is HTTPS. If the remote host has disabled TLS 1.0 and your connection is coming in as TLS 1.0, it could cause that behavior. I know C# 4.6 has TLS 1.0/1.1/1.2 support enabled by default, but I think C# 4.6 still defaults to only SSL3/TLS 1.0 even though TLS 1.1 and 1.2 are supported. If this is the cause of the issue, you can manually add TLS 1.1 and 1.2 to the enabled values using the following code.
System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
If you are using .Net 4.0 then SecurityProtocolType.Tls11 and SecurityProtocolType.Tls2 are not defined so instead you can use the hard coded value below.
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
It is possible to solve the issue without any changes in the code, as described in this excellent answer to a similar question:
Retarget the web project to .Net 4.6+, then update web.config as the following:
<system.web>
<compilation targetFramework="4.6" />
<httpRuntime targetFramework="4.6" />
</system.web>
This worked for me, the first line ensures the protocols ssl3 and TLS1.2, and the second line ignores any potential certificate errors (ignore and continue - like expired certs.):
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
For me this error was caused by forgetting to configure the proxy server.
Using the following code to construct the HttpClient solved it for my .NET 4.7.2 application:
var httpClientHandler = new HttpClientHandler { Proxy = WebRequest.GetSystemWebProxy() };
var httpClient = new HttpClient(httpClientHandler);
Hope this helps someone.
How to send notification using Webpush library. I was trying but its throws error msg like {"Received unexpected response code"}
****Now i have created web API to send notification & calling you through fiddler,but did n't get exception it's stuck somewhere
here is my code sample****
public void Sendnotification()
{
try
{
WebPush.VapidDetails vapidKeys = apidHelper.GenerateVapidKeys();
string subject =#"mailto:xyz.com";
string publicKey = Convert.ToString(vapidKeys.PublicKey);
string privateKey = Convert.ToString(vapidKeys.PrivateKey);
var subscription = new PushSubscription(pushEndpoint, p256dh, auth);
var vapidDetails = new VapidDetails(subject, publicKey, privateKey);
client.SendNotification(subscription, "payload", vapidDetails);
}
catch (WebPushException e)
{
}
}
I have configured Https enabled to call api using fidder. Please have look. also its throws error, it stuck somewhere
now it got the error please have look it's showing error HTTP/1.1 410 NotRegistered
See the full screen of Fiddler response error details
If you are getting the error 410 (to check the error use fiddler to intercept the https call), probably what you have is an error in the subscription data of the user probably the keys stored in your database doesn't match the subscription in the browser an easy fix could be to re-subscribe and re-save the subscription data and try again.
to setup fiddler, you have to use it as a proxy visual studio to intercept the https calls and also you have to enable https decryption.
EDIT
you can set up fiddler just by adding this configuration in your web.config or app.config:
<system.net>
<defaultProxy
enabled = "true"
useDefaultCredentials = "true">
<proxy autoDetect="false" bypassonlocal="false" proxyaddress="http://127.0.0.1:8888" usesystemdefault="false" />
</defaultProxy>
</system.net>
if in any case, you get unauthorized registration check this questions:
Web Push API Chrome, returning "Unauthorized Registration"
WebPushError and UnauthorizedRegistration when try to send push notification to Chrome and Opera, FF is OK
This is related/sort of a followup to this question but contains more and more specific information.
I have a REST app running on my PC. I need to call some of the methods on the server from a handheld WindowsCE device that uses the compact framework.
I can contact the server's methods from Postman, so it's not a problem that way. In Postman, I use:
http://localhost:21609/api/inventory/sendXML/duckbill/platypus/bloo
...and with this I reach the breakpoint in this REST method on my server app:
[HttpPost]
[Route("api/inventory/sendxml/{userId}/{pwd}/{filename}")]
public async Task SendInventoryXML(String userId, String pwd, String fileName)
However, although using "PPP_PEER" is the way to contact the PC from the handheld device (127.0.0.1 doesn't fly, because the handheld sees that as being itself, and commits egregious acts of cannibalism when trying to contact that address) - as can be seen by this TCP code that does work from the handheld device:
string pingString = "PING|";
TcpClient client = new TcpClient("PPP_PEER", 7727);
try
{
try
{
Stream s = client.GetStream();
StreamReader sr = new StreamReader(s);
StreamWriter sw = new StreamWriter(s) { AutoFlush = true };
String response = String.Empty;
if (firstRecord)
{
sw.WriteLine(pingString);
. . .
...trying to use PPP_PEER to call the REST method fails.
Here is the code I use to try to do that:
//HHSConsts
public static string BASE_REST_URL = "http://PPP_PEER:21609/api/";
. . .
//frmMain
private void SendInventories()
{
try
{
foreach (String tblname in listBoxWork.Items)
{
String xmlData = hhsdbutils.GetINVDataAsXMLFromTable(tblname, fileName);
String uri = String.Format("{0}inventory/sendXML/duckbill/platypus/{1}",
HHSConsts.BASE_REST_URL, fileName);
fileXferImp = HHSConsts.GetFileTransferMethodology();
fileXferImp.SendDataContentsAsXML(uri, xmlData, tblname);
. . .
// FileXferREST.cs
public void SendDataContentsAsXML(String destinationPath, String data, String fileName,
String siteNumber, bool firstRecord, bool lastRecord)
{
SendHTTPRequestNoCredentials(destinationPath, HttpMethods.POST, data, "application/xml");
}
public static HttpWebRequest SendHTTPRequestNoCredentials(string uri, HttpMethods method,
string data, string contentType)
{
WebRequest request = WebRequest.Create(uri);
try
{
request.Method = Enum.ToObject(typeof(HttpMethods), method).ToString();
request.ContentType = contentType;
((HttpWebRequest)request).Accept = contentType;
((HttpWebRequest)request).KeepAlive = false;
((HttpWebRequest)request).ProtocolVersion = HttpVersion.Version10;
if (method != HttpMethods.GET && method != HttpMethods.DELETE)
{
byte[] arrData = Encoding.UTF8.GetBytes(data);
request.ContentLength = arrData.Length;
using (Stream oS = request.GetRequestStream())
{
oS.Write(arrData, 0, arrData.Length);
}
}
else
{
request.ContentLength = 0;
}
}
catch (WebException webex)
{
HttpWebResponse hwr = (HttpWebResponse)webex.Response;
HttpStatusCode hsc = hwr.StatusCode;
String webExMsgAndStatusCode = String.Format("{0} Status code == {1}", webex.Message,
hsc.ToString());
ExceptionLoggingService.Instance.WriteLog(String.Format("From
FileXferREST.SendHTTPRequestNoCredentials: {0}", webExMsgAndStatusCode));
}
return request as HttpWebRequest;
}
No exception is thrown; it simply doens't work.
When attempting this call, I run rawcap to capture the packages being sent over the network with these command line args:
rawcap 127.0.0.1 [fileName].pcap
I then open the .pcap file in Wireshark, search for "21609" and get this TCP stream:
...I added the screen shot above to show the red/blue coloration for the request/response, but here is the entire rawcap/Wireshark conversation involving port 21609:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
POST /api//inventory/sendXML/duckbill/platypus/INV_3_20090307181658000.xml HTTP/1.0
Content-Type: application/xml
Accept: application/xml
Connection: Close
Content-Length: 388
Host: ppp_peer:21609
112209003343742SOME DESC2.2testVendorID]6161.51.995.58HTTP/1.1 404 Not Found
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/8.0
X-SourceFiles: =?UTF-8?B?QzpccHJvamVjdFxnaXRcQ1N0b3JlXEhIUy5BUElcYXBpXGludmVudG9yeVxzZW5kWE1MXGR1Y2tiaWxsXHBsYXR5cHVzXElOVl8zXzIwMDkwMzA3MTgxNjU4MDAwLnhtbA==?=
X-Powered-By: ASP.NET
Date: Thu, 18 Dec 2014 17:23:01 GMT
Connection: close
Content-Length: 5016
IIS 8.0 Detailed Error - 404.0 - Not Found
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
Most likely causes:
.The directory or file specified does not exist on the Web server. .The URL contains a typographical error. .A custom filter or module, such as URLScan, restricts access to the file.
Things you can try:
.Create the content on the Web server. .Review the browser URL. .Check the failed request tracing log and see which module is calling SetStatus. For more information, click here.
Detailed Error Information:
Module IIS Web Core
Notification MapRequestHandler
Handler StaticFile
Error Code 0x80070002
Requested URL http://ppp_peer:21609/api/inventory/sendXML/duckbill/platypus/INV_3_20090307181658000.xml
Physical Path C:\project\git\CStore\HHS.API\api\inventory\sendXML\duckbill\platypus\INV_3_20090307181658000.xml
Logon Method Anonymous
Logon User Anonymous
Request Tracing Directory C:\Users\clay\Documents\IISExpress\TraceLogFiles\HHS.API
More Information:
This error means that the file or directory does not exist on the server. Create the file or directory and try the request again.
View more information »
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So to recap, "PPP_PEER" does work as a way for the handheld device to describe/contact the PC (it works with the TCP code), and the REST method is reachable from another process (such as Postman), but trying to call the method using PPP_PEER from the handheld device fail with the "404.0 - Not Found" error.
Why?
UPDATE
When I replace "PPP_PEER" with the machine name of the PC, the error changes from "404 - Not Found" to "503 - Service Unavailable":
But that is a bit of a rompecabeza, because the service is obviously available, as it is running and its breakpoint is hit when I call it from Postman.
UPDATE 2
Now this is odd: If I use the full machine name instead of just the "truncated" name, the error goes back to being 404 instead of 503:
So if I use PPP_PEER as the host name, I get a 404; if I use shannon2, I get a 503; if I use shannon2.sscs.ad, I again get 404. Should I blame this on Tim Berners-Lee, Al Gore, Andy Warhol, or someone else?
SO...those are my results on trying to follow Eric Law's first suggestion; there are two others, but: what would I edit the Host header to that might make a difference? Or overwrite it to what?
It seems as if the basic problem is trying to access a "server" app running locally on my PC (even though the handheld != the PC, it is "sort of" the same thing, after a fashion).
Now that the server app is running on a different machine on the network altogether, I'm able to hit it; albeit not yet totally unexceptionally, as can be seen here.
Is it possible to detect/reuse those settings ?
How ?
The exception i'm getting is
This is the exception while connecting to http://www.google.com
System.Net.WebException: Unable to connect to the remote server --->
System.Net.Sockets.SocketException: A connection attempt failed because the
connected party did not properly respond after a period of time, or established
connection failed because connected host has failed to respond 66.102.1.99:80
at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot,
SocketAddress socketAddress)
at System.Net.Sockets.Socket.InternalConnect(EndPoint remoteEP)
at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure,
Socket s4, Socket s6, Socket& socket, IPAddress& address,
ConnectSocketState state, IAsyncResult asyncResult, Int32 timeout,
Exception& exception)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.GetResponse()
at mvcTest.MvcApplication.Application_Start() in
C:\\home\\test\\Application1\\Application1\\Program.cs:line 33"
HttpWebRequest will actually use the IE proxy settings by default.
If you don't want to use them, you have to specifically override the .Proxy proprty to either null (no proxy), or the proxy settings of you choice.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://news.bbc.co.uk");
//request.Proxy = null; // uncomment this to bypass the default (IE) proxy settings
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Console.WriteLine("Done - press return");
Console.ReadLine();
I was getting a very similar situation where the HttpWebRequest wasn't picking up the correct proxy details by default and setting the UseDefaultCredentials didn't work either. Forcing the settings in code however worked a treat:
IWebProxy proxy = myWebRequest.Proxy;
if (proxy != null) {
string proxyuri = proxy.GetProxy(myWebRequest.RequestUri).ToString();
myWebRequest.UseDefaultCredentials = true;
myWebRequest.Proxy = new WebProxy(proxyuri, false);
myWebRequest.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
}
and because this uses the default credentials it should not ask the user for their details.
Note that this is a duplicate of my answer posted here for a very similar problem: Proxy Basic Authentication in C#: HTTP 407 error
For people having problems with getting this to play nice with ISA server, you might try to set up proxy in the following manner:
IWebProxy webProxy = WebRequest.DefaultWebProxy;
webProxy.Credentials = CredentialCache.DefaultNetworkCredentials;
myRequest.Proxy = webProxy;
This happens by default, if WebRequest.Proxy is not set explicitly (by default it's set to WebRequest.DefaultWebProxy).