System.Net.WebException
A WebException is thrown by the older network APIs, WebRequest, HttpWebRequest and WebClient. It also comes from .NET Framework libraries that use them, such as old SOAP clients. Newer code that uses HttpClient gets an HttpRequestException instead.
The Status property tells what went wrong, and the Response property holds the response from the server, if there was one. Both are needed to understand the exception.
Minimum version: >= 1.1 >= Core 1.0
Statistics
Common causes
The Status property separates a request that never got a response from one that got an error. These are the usual causes.
The server cannot be reached
There is no response, so Response is null. On .NET Framework the status is ConnectFailure, NameResolutionFailure or Timeout. In current versions of .NET it is often UnknownError, and the details are in the inner exception. The server is down, the name is wrong, or a firewall is in the way.
var request = (HttpWebRequest)WebRequest.Create("http://localhost:1/prices");
using var response = request.GetResponse(); // WebException: connection refused
Check the address, and handle a missing response where the server can be down:
var request = (HttpWebRequest)WebRequest.Create("http://localhost:1/prices");
try
{
using var response = request.GetResponse();
}
catch (WebException e) when (e.Response is null)
{
logger.LogWarning(e, "The price service is not available");
}
The server answered with an error status
The status is ProtocolError, and Response holds the answer. These APIs throw for every status that is not a success, including 404 and 500, and the body of the error response is often the best clue.
Cast the response to HttpWebResponse to read the status code, and read its stream for the body that the server sent:
try
{
var request = (HttpWebRequest)WebRequest.Create("http://localhost:1/prices");
using var response = request.GetResponse();
}
catch (WebException e) when (e.Response is HttpWebResponse error)
{
using var reader = new StreamReader(error.GetResponseStream());
var body = reader.ReadToEnd();
logger.LogError(e, "Server answered {Status}: {Body}", (int)error.StatusCode, body);
}
catch (WebException)
{
}
TLS and certificate problems
The status is SecureChannelFailure or TrustFailure. The server uses a certificate that is not trusted or an old TLS version that the client does not accept.
Fix the certificate on the server. On .NET Framework, target 4.7 or later, so the operating system picks the TLS version, and do not turn the validation off.
How to fix it and prevent it
Move to HttpClient
WebRequest and WebClient are marked obsolete in .NET. HttpClient is the replacement. It is async, reuses connections and works with IHttpClientFactory.
using var client = new HttpClient();
var json = await client.GetStringAsync("http://localhost:1/prices");
Read Status and Response
Never log only the message. The status and the body of the response say whether the request failed on the way or was rejected by the server.
Dispose responses
On .NET Framework, a WebResponse that is not closed keeps the connection, and after a few requests the next ones wait and time out. Use using for responses and streams.
How to read the stack trace
The exception wraps the exceptions below it, so the innermost one is the real cause:
System.Net.WebException: No connection could be made because the target machine actively refused it. [::ffff:127.0.0.1]:5001 (localhost:5001)
---> System.Net.Http.HttpRequestException: No connection could be made because the target machine actively refused it. [::ffff:127.0.0.1]:5001 (localhost:5001)
---> System.Net.Sockets.SocketException (10061): No connection could be made because the target machine actively refused it. [::ffff:127.0.0.1]:5001
at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Connect(EndPoint remoteEP)
at System.Net.Sockets.Socket.Connect(IPAddress[] addresses, Int32 port)
--- End of stack trace from previous location ---
at System.Net.Sockets.Socket.Connect(IPAddress[] addresses, Int32 port)
at System.Net.HttpWebRequest.<>c__DisplayClass224_0.<<CreateHttpClient>b__1>d.MoveNext()
--- End of stack trace from previous location ---
at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.InjectNewHttp11ConnectionAsync(QueueItem queueItem)
at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellation(CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionWaiter`1.WaitForConnectionAsync(HttpRequestMessage request, HttpConnectionPool pool, Boolean async, CancellationToken requestCancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.HttpMessageHandlerStage.Send(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.Metrics.MetricsHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpMessageHandlerStage.Send(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpMessageHandlerStage.Send(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.SocketsHttpHandler.Send(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.Send(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
at System.Net.HttpWebRequest.SendRequest(Boolean async, HttpContent content)
at System.Net.HttpWebRequest.HandleResponse(Boolean async)
at System.Net.HttpWebRequest.GetResponse()
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.GetResponse()
at Shop.Services.LegacyFetcher.Fetch(String url) in C:\src\Shop\Services\LegacyFetcher.cs:line 16
at Program.<Main>$(String[] args) in C:\src\Shop\Program.cs:line 4
The innermost exception is a SocketException with the code 10061, so the connection was refused at localhost:5001. The call is GetResponse on line 16 of LegacyFetcher.cs. In this version of .NET, HttpWebRequest is implemented on top of HttpClient, so that is why HttpRequestException shows up in the middle.
Should you catch it?
Yes, around calls that use these APIs. Filter on Status and look at Response to handle the cases you know, such as 404 for a missing resource.
The Response can be null, for example for a connection failure, so check it before you use it.
Find WebException before your users do
elmah.io logs every unhandled exception in your .NET application with its stack trace and request details, groups identical errors and notifies you when a new one appears.
Start free trialRelated exceptions
- HttpRequestException is the exception of HttpClient, the replacement for these APIs.
- SocketException is the inner exception when the connection fails.
- TimeoutException is thrown for time limits set in code.
Frequently asked questions
How do I get the status code from a WebException?
Cast e.Response to HttpWebResponse and read StatusCode. The Status property of the exception is an enum for the type of failure, not the HTTP status.
How do I read the body of the error response?
Read e.Response.GetResponseStream(). Many APIs describe the error in the body, so log it.
Why does WebClient throw for 404?
These APIs treat every status outside the 200 range as an error. That is different from HttpClient, where you get a response and can check the status.
Should I still use WebClient?
Not for new code, where HttpClient is the replacement, because the old APIs are obsolete in current versions of .NET.
Let your AI agent track it down
Connect Claude Code, Cursor, VS Code or Visual Studio to the elmah.io MCP server and ask your agent to look into WebException for you. For example:
The agent reads the stack trace and request details from elmah.io, finds the code in your repository and proposes a fix. In Claude Code, add the server with one command:
claude mcp add --transport http --client-id claudecode elmahio https://mcp.elmah.io/mcp
The MCP server is included on every plan and is currently in beta. Set up the MCP server.
Further reading
YouTube videos
Answers from Stack Overflow
The ASP.NET Web API has replaced the WCF Web API previously mentioned.
I thought I'd post an updated answer since most of these responses are from early 2012, and this thread is one of the top results when doing a Google search for "call restful service C#".
Current guidance from Microsoft is to use the Microsoft ASP.NET Web API Client Libraries to consume a RESTful service. This is available as a NuGet package, Microsoft.AspNet.WebApi.Client. You will need to add this NuGet package to your solution.
Here's how your example would look when implemented using the ASP.NET Web API Client Library:
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
namespace ConsoleProgram
{
public class DataObject
{
public string Name { get; set; }
}
public class Class1
{
private const string URL = "https://sub.domain.com/objects.json";
private string urlParameters = "?api_key=123";
static void Main(string[] args)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(URL);
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
// List data response.
HttpResponseMessage response = client.GetAsync(urlParameters).Result; // Blocking call! Program will wait here until a response is received or a timeout occurs.
if (response.IsSuccessStatusCode)
{
// Parse the response body.
var dataObjects = response.Content.ReadAsAsync<IEnumerable<DataObject>>().Result; //Make sure to add a reference to System.Net.Http.Formatting.dll
foreach (var d in dataObjects)
{
Console.WriteLine("{0}", d.Name);
}
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
// Make any other calls using HttpClient here.
// Dispose once all HttpClient calls are complete. This is not necessary if the containing object will be disposed of; for example in this case the HttpClient instance will be disposed automatically when the application terminates so the following call is superfluous.
client.Dispose();
}
}
}
If you plan on making multiple requests, you should re-use your HttpClient instance. See this question and its answers for more details on why a using statement was not used on the HttpClient instance in this case: Do HttpClient and HttpClientHandler have to be disposed between requests?
For more details, including other examples, see Call a Web API From a .NET Client (C#)
This blog post may also be useful: Using HttpClient to Consume ASP.NET Web API REST Services
By Brian Swift. Read the original answer on Stack Overflow.
My suggestion would be to use RestSharp. You can make calls to REST services and have them cast into POCO objects with very little boilerplate code to actually have to parse through the response. This will not solve your particular error, but it answers your overall question of how to make calls to REST services. Having to change your code to use it should pay off in the ease of use and robustness moving forward. That is just my two cents though.
Example:
namespace RestSharpThingy
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using RestSharp;
public static class Program
{
public static void Main()
{
Uri baseUrl = new Uri("https://httpbin.org/");
IRestClient client = new RestClient(baseUrl);
IRestRequest request = new RestRequest("get", Method.GET) { Credentials = new NetworkCredential("testUser", "P455w0rd") };
request.AddHeader("Authorization", "Bearer qaPmk9Vw8o7r7UOiX-3b-8Z_6r3w0Iu2pecwJ3x7CngjPp2fN3c61Q_5VU3y0rc-vPpkTKuaOI2eRs3bMyA5ucKKzY1thMFoM0wjnReEYeMGyq3JfZ-OIko1if3NmIj79ZSpNotLL2734ts2jGBjw8-uUgKet7jQAaq-qf5aIDwzUo0bnGosEj_UkFxiJKXPPlF2L4iNJSlBqRYrhw08RK1SzB4tf18Airb80WVy1Kewx2NGq5zCC-SCzvJW-mlOtjIDBAQ5intqaRkwRaSyjJ_MagxJF_CLc4BNUYC3hC2ejQDoTE6HYMWMcg0mbyWghMFpOw3gqyfAGjr6LPJcIly__aJ5__iyt-BTkOnMpDAZLTjzx4qDHMPWeND-TlzKWXjVb5yMv5Q6Jg6UmETWbuxyTdvGTJFzanUg1HWzPr7gSs6GLEv9VDTMiC8a5sNcGyLcHBIJo8mErrZrIssHvbT8ZUPWtyJaujKvdgazqsrad9CO3iRsZWQJ3lpvdQwucCsyjoRVoj_mXYhz3JK3wfOjLff16Gy1NLbj4gmOhBBRb8rJnUXnP7rBHs00FAk59BIpKLIPIyMgYBApDCut8V55AgXtGs4MgFFiJKbuaKxq8cdMYEVBTzDJ-S1IR5d6eiTGusD5aFlUkAs9NV_nFw");
request.AddParameter("clientId", 123);
IRestResponse<RootObject> response = client.Execute<RootObject>(request);
if (response.IsSuccessful)
{
response.Data.Write();
}
else
{
Console.WriteLine(response.ErrorMessage);
}
Console.WriteLine();
string path = Assembly.GetExecutingAssembly().Location;
string name = Path.GetFileName(path);
request = new RestRequest("post", Method.POST);
request.AddFile(name, File.ReadAllBytes(path), name, "application/octet-stream");
response = client.Execute<RootObject>(request);
if (response.IsSuccessful)
{
response.Data.Write();
}
else
{
Console.WriteLine(response.ErrorMessage);
}
Console.ReadLine();
}
private static void Write(this RootObject rootObject)
{
Console.WriteLine("clientId: " + rootObject.args.clientId);
Console.WriteLine("Accept: " + rootObject.headers.Accept);
Console.WriteLine("AcceptEncoding: " + rootObject.headers.AcceptEncoding);
Console.WriteLine("AcceptLanguage: " + rootObject.headers.AcceptLanguage);
Console.WriteLine("Authorization: " + rootObject.headers.Authorization);
Console.WriteLine("Connection: " + rootObject.headers.Connection);
Console.WriteLine("Dnt: " + rootObject.headers.Dnt);
Console.WriteLine("Host: " + rootObject.headers.Host);
Console.WriteLine("Origin: " + rootObject.headers.Origin);
Console.WriteLine("Referer: " + rootObject.headers.Referer);
Console.WriteLine("UserAgent: " + rootObject.headers.UserAgent);
Console.WriteLine("origin: " + rootObject.origin);
Console.WriteLine("url: " + rootObject.url);
Console.WriteLine("data: " + rootObject.data);
Console.WriteLine("files: ");
foreach (KeyValuePair<string, string> kvp in rootObject.files ?? Enumerable.Empty<KeyValuePair<string, string>>())
{
Console.WriteLine("\t" + kvp.Key + ": " + kvp.Value);
}
}
}
public class Args
{
public string ClientId { get; set; }
}
public class Headers
{
public string Accept { get; set; }
public string AcceptEncoding { get; set; }
public string AcceptLanguage { get; set; }
public string Authorization { get; set; }
public string Connection { get; set; }
public string Dnt { get; set; }
public string Host { get; set; }
public string Origin { get; set; }
public string Referer { get; set; }
public string UserAgent { get; set; }
}
public class RootObject
{
public Args args { get; set; }
public Headers Headers { get; set; }
public string Origin { get; set; }
public string Url { get; set; }
public string Data { get; set; }
public Dictionary<string, string> Files { get; set; }
}
}
By Justin Pihony. Read the original answer on Stack Overflow.
Try setting maxReceivedMessageSize on the server too, e.g. to 4MB:
<binding name="MyService.MyServiceBinding" maxReceivedMessageSize="4194304">
The main reason the default (65535 I believe) is so low is to reduce the risk of Denial of Service (DoS) attacks. You need to set it bigger than the maximum request size on the server, and the maximum response size on the client. If you're in an Intranet environment, the risk of DoS attacks is probably low, so it's probably safe to use a value much higher than you expect to need.
By the way a couple of tips for troubleshooting problems connecting to WCF services:
Enable tracing on the server as described in this MSDN article.
Use an HTTP debugging tool such as Fiddler on the client to inspect the HTTP traffic.
Unrelated, I'm sure, but do wrap your IDisposable objects in using blocks to ensure proper disposal:
using System;
using System.Net;
using System.IO;
namespace ConsoleProgram
{
public class Class1
{
private const string URL = "https://sub.domain.com/objects.json?api_key=123";
private const string DATA = @"{""object"":{""name"":""Name""}}";
static void Main(string[] args)
{
Class1.CreateObject();
}
private static void CreateObject()
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = DATA.Length;
using (Stream webStream = request.GetRequestStream())
using (StreamWriter requestWriter = new StreamWriter(webStream, System.Text.Encoding.ASCII))
{
requestWriter.Write(DATA);
}
try
{
WebResponse webResponse = request.GetResponse();
using (Stream webStream = webResponse.GetResponseStream() ?? Stream.Null)
using (StreamReader responseReader = new StreamReader(webStream))
{
string response = responseReader.ReadToEnd();
Console.Out.WriteLine(response);
}
}
catch (Exception e)
{
Console.Out.WriteLine("-----------------");
Console.Out.WriteLine(e.Message);
}
}
}
}
By Jesse C. Slicer. Read the original answer on Stack Overflow.
Here are a few different ways of calling an external API in C# (updated 2019).
.NET's built-in ways:
- WebRequest& WebClient - verbose APIs & Microsoft's documentation is not very easy to follow
- HttpClient - .NET's newest kid on the block & much simpler to use than above.
Free, open-source NuGet Packages, which frankly have a much better developer experience than .NET's built in clients:
- ServiceStack.Text (1,000 GitHub stars, 7 million NuGet downloads) (*) - fast, light and resilient.
- RestSharp (6,000 GitHub stars, 23 million NuGet downloads) (*) - simple REST and HTTP API Client
- Flurl (1,700 GitHub stars, 3 million NuGet downloads) (*)- a fluent, portable, testable HTTP client library
All the above packages provide a great developer experience (i.e., concise, easy API) and are well maintained.
(*) as at August 2019
Example: Getting a Todo item from a Fake Rest API using ServiceStack.Text. The other libraries have very similar syntax.
class Program
{
static void Main(string[] args)
{
// Fake rest API
string url = "https://jsonplaceholder.typicode.com/todos/1";
// GET data from API & map to POCO
var todo = url.GetJsonFromUrl().FromJson<Todo>();
// Print the result to screen
todo.PrintDump();
}
public class Todo
{
public int UserId { get; set; }
public int Id { get; set; }
public string Title { get; set; }
public bool Completed { get; set; }
}
}
Running the above example in a .NET Core Console app, produces the following output.
Install these packages using NuGet
Install-Package ServiceStack.Text, or
Install-Package RestSharp, or
Install-Package Flurl.Http
Source: Stack Overflow
