Related: No such host is known —> System.Net.Http.HttpRequestException:
So, I have an odd problem: whenever I perform any call to a RESTful API using HttpClient
, I get a the following error: System.Net.Http.HttpRequestException: No such host is known
I've seen several other Q&As that discuss this, but many of these (such as the one I link to) discuss it specifically in the context of an Azure VM. Many of them suggest that this is caused by a DNS issue.
My situation is a little different the other Q&As I've read, though: when I run my web site by debugging in Visual Studio 2019, it runs just fine. However, when I publish to IIS locally, I get this exception whenever I try to do a call to HttpClient
.
Also, unlike some of the other articles I've read about this, this does not happen intermittently for me - it happens every single time I try to do an API call.
If this is caused by a DNS issue like some of the other Q&As suggest, that suggests that there must be some difference between when I publish locally and when I debug in Visual Studio.
Here's how I configure my Publish (summary of the image below for those who prefer text):
Image summary:
- Web Deploy with WebPublishMethod MSDeploy
- TargetFramework netcoreapp3.1
- LastUsedBuildConfiguration Release
- LastUsedPlatform x86
- SelfContained false
- MSDeployPublishMethod InProc
- MSDeployServiceURL localhost
Additional details: - Destination URL http://localhost:80 - IIS Application Pool is set to "No managed code", as is usually suggested
Also, this occurs regardless of how I create the HttpClient
instance and the code works just fine when debugging, so I think that this is more likely to be a configuration issue than a code issue, but for what it's worth, I use the following code in my Startup
class to create it. (See also here for reference).
services.AddHttpClient("MyNamedClient", (sp, c) =>
{
c.BaseAddress = new Uri("https://api.smartrecruiters.com/");
c.Timeout = new TimeSpan(4, 0, 0);
c.DefaultRequestHeaders.Accept.Clear();
c.DefaultRequestHeaders.Add("Accept", "application/json");
var ctx = sp.GetService<DatabaseContext>();
Security security = ctx.Security.First();
c.DefaultRequestHeaders.Add("APIToken", security.Apikey);
});
I then use ASP.NET Core's Dependency Injection to get a HttpClient
instance whenever I need it.
I also tried creating HttpClient
as a singleton (which I know is not the recommended way of doing this in an ASP.NET Core application), but I had the same problem with that approach.
Here's the full error details from Event Viewer from when I try to do a GetAsync
call using HttpClient
:
Category: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware
EventId: 1
RequestId: 8000000c-0006-ff00-b63f-84710c7967bb
RequestPath: /UsersObject/GetUsersAPICall
SpanId: |f32bc4b9-41d453941179fa9f.
TraceId: f32bc4b9-41d453941179fa9f
ParentId:
An unhandled exception has occurred while executing the request.
Exception:
System.Net.Http.HttpRequestException: No such host is known.
---> System.Net.Sockets.SocketException (11001): No such host is known.
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at [Namespace].MyHttpClient.GetAsyncWithRetries(HttpClient client, String url) in C:\Users\[Removed]\source\repos\[Removed]\MyhHttpClient.cs:line 54
at SR_Interaction.Models.SRUser.Search(String emailAddress, HttpClient client) in C:\Users\[Removed]\Models\SRUser.cs:line 100
at Bosch_Live_Docs.Controllers.UsersObjectController.GetUsersAPICall(String query) in C:\Users\[Removed]\Controllers\UsersObjectController.cs:line 58
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
Anyone have any suggestions about how I might be able to fix this? I think it's probably either my IIS configuration or my publish settings - or am I on the wrong track entirely here?
Edit: As requested, here's the controller code:
[HttpGet]
[Authorize(Roles = "CreateUser,PatchUser")]
public async Task<IActionResult> GetUsersAPICall([Bind("query")] [RegularExpression(@"^\w+(\.\w+)*@\w+(\.\w+)+|(\w+(\s\w+)*)$", ErrorMessage = "This does not look like a valid query")] string query)
{
if (query == null)
{
return BadRequest();
}
else if (!ModelState.IsValid)
{
// TODO: What to do with this? How do we actually show the validation error?
return BadRequest("Does not look like a valid query");
}
List<SRUser> users = await SRUser.Search(query, clientFactory.CreateClient(Startup.srNamedClient));
users = users.OrderBy(ur => ur.firstName).ToList();
if (users.Any())
{
return PartialView("_UserList", users);
}
else
{
return NotFound();
}
}
And here's where I do the actual call:
public static async Task<List<SRUser>> Search(string emailAddress, HttpClient client)
{
string json;
using (HttpResponseMessage msg = await client.GetAsync("user-api/v201804/users?limit=100&q=" + emailAddress))
{
json = await msg.Content.ReadAsStringAsync();
}
return JsonSerializer.Deserialize<NextPageContainer<SRUser>>(json).content;
}
Further edit:
Here's the Application Pool:
Here are the modules I have installed:
I'm slightly confused about this particular one:
Is it necessary to include both? When I look at the Ordered view, the "old" one is actually higher:
However, I can't reorder it.
Are these problems?
Even further edit: For the version that was published locally, I found that this problem occurs when my App Pool runs under a built-in account (such as ApplicationPoolIdentity). However, it's fixed when I use a specific user account. However, this does not work on the server.