HttpClient calls slow from Kestrel + IIS - iis

I have a simple asp.net core 2.0 WebApi app running in Kestrel behind an IIS reverse proxy. The single route is pretty simple, it just makes a http request:
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("http://www.google.ca");
HttpResponseMessage response = await client.GetAsync("/search?q=test&oq=test");
return Ok();
}
However, this request consistently takes 2-3 seconds to complete. Yet, if I run Kestrel directly without IIS, the same code takes ~100ms.
I followed all the Microsoft docs for configuring kestrel with IIS.

TL;DR Needed to configure HttpClient to not use the default proxy settings
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.UseProxy = false;
using (HttpClient client = new HttpClient(clientHandler))
{ ... }
The long explanation is that asp.net attempts to use the machine's default proxy configuration settings for each request. My IIS is configured to run under the Network Service account which has limited access, and as such, will eventually fail (presumably because it doesn't have access to the registry) to find the proxy settings and just connect directly. This process apparently takes about 2.5 seconds.
For my kestrel tests, I was running dotnet .\api.dll from the command line, which uses my logged in credentials, and could successfully access the proxy settings. However, when using IIS, it spawns the dotnet process under the same Network Service account that IIS is running as.

Related

How to get correct WSDL URL when hosting a WCF service behind an Azure Application Gateway?

We are in the process of migrating services from on-premise to Azure, and we are now hosting a legacy WCF service an Azure App Service. To make it backwards compatible with existing clients, it needs to be available through {domainNameHere}.com/services.
There are also other services that should be accessible through the same domain, for example {domainNameHere}.com/api. We have set up an Azure Application Gateway to route requests to different App Services based on the request paths, and have set {domainNameHere}.com to point to the Application Gateway IP.
This works well for all the services except for the WCF service. It is accessible in the browser at https://{domainNameHere}.com/services/exports.svc, but the WSDL URIs at that page shows the azurewebsites.net URIs instead of our custom domain. When clients attempt to access the service, they get the following error:
System.ServiceModel.EndpointNotFoundException:
'There was no endpoint listening at https://{domainNameHere}.com/services/export.svc
that could accept the message. This is often caused by an incorrect address or SOAP
action. See InnerException, if present, for more details.'
Inner Exception
WebException: The remote server returned an error: (404) Not Found.
We have tried to use useRequestHeadersForMetadataAddress in the WCF config to no avail.
Here is the WCF configuration, all in code. The endpoint URI is https://{domainNameHere}.com/services/exports.svc.
public static void Configure<T>(ServiceConfiguration config, Uri endpoint) where T : class
{
// Configure service behavior
config.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true, HttpsGetEnabled = true });
config.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
var serviceCredential = config.Description.Behaviors.Find<ServiceCredentials>();
if (serviceCredential == null)
{
serviceCredential = new ServiceCredentials();
config.Description.Behaviors.Add(serviceCredential);
}
serviceCredential.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
serviceCredential.UserNameAuthentication.CustomUserNamePasswordValidator = new CredentialsValidator();
config.AddServiceEndpoint(typeof(T), GetBinding(), endpoint);
}
I finally figured it out. The Application Gateway made requests to the WCF service using HTTP, but the WCF service only replied on HTTPS. As soon as I updated the Application Gateway to make requests using HTTPS it was working as expected.

Selfhosted Asp.Net Core WebAPi with http.sys webserver deploy

I'm trying to deploy selfhosted Asp.Net Core WebApi. I replaced the default Kestrel web server with Http.sys. I'm deploying on a virtual machine with Windows Server 2016.
When I request the api locally (from the virtual machine) I can access it without any problems on http://localhost:61152.
The problem is that I can't access it from the host machine.
I opened the port 61152 in the Windows Firewall.
In the program.cs I have:
.UseStartup<Startup>().UseHttpSys(options =>
{
options.Authentication.Schemes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM;
options.Authentication.AllowAnonymous = false;
options.MaxConnections = null;
options.MaxRequestBodySize = 30000000;
options.UrlPrefixes.Add("http://localhost:61152/");
}).Build();
I use asp.net core 2.0. I browse with the IP of the server which like this:
http://192.168.0.112:61152/
Also I have IIS running on the guest machine and I can see the default IIS page.
Can you please tell what I'm doing wrong or direct me to an article how to fix this.
Thanks
I found a solution. I just changed the http://localhost:61152/ to http://*:61152/

How to host servicestack on node.js?

We have a Icneium Hybrid Mobile app accessing servicestack REST services. Is it OK to host the servicestack on Node.js instead of IIS? Any examples are highly appreciated.
You won't be able to host ServiceStack in node.js directly, but there are many proxy modules for node that can transparently proxy requests to a ServiceStack Self Hosted application, thus removing the need for IIS.
You now have two options:
If your intent is just to ditch IIS and you don't specifically need node.js then a self hosted application is great, because there are no other dependency layers. Requests can go straight to ServiceStack.
But if you are looking to have some integration with node.js, then as I said a transparent proxy can forward the requests to the ServiceStack service, but you will still need the Self Hosted ServiceStack service running behind the node proxy.
Set up a Self Hosted ServiceStack Service
To get this to work. You would need to configure ServiceStack to use Self Hosting. The way this is done is to create a AppHostHttpListenerBase AppHost in a console application, as shown in the link (above).
Once you have a Self Hosted application, you will have configured the hostname and port that ServiceStack will listen on. If you navigate to that URL you should see your ServiceStack service.
If you chose not to use node (option 1), then the ServiceStack application is ready to be accessed directly. If you do wish to use with node because you have some other part of your application already use node (option 2) then follow the next steps to setup a proxy.
Node.JS Proxy
There are many proxy modules for node available. I have chosen to go with the popular node-http-proxy, by nodejitsu.
Setup looks simple. Requests on port 80 standard http port will be forwarded to ServiceStack application on localhost:9000. Assuming that's were its running.
var http = require('http'),
httpProxy = require('http-proxy');
httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(80);
If you need more control. Check out all the options in the documentation.

How to publish MVC app with proxy if Azure does not use same web.config as my local environment

In my MVC web app, one controller function (Validate) calls a service. See below code and note that MessageHandlerClient is a service proxy generated in Visual Studio. The service proxy call client.ValidateMessage(formdataasbson["HLmessage"].ToString()) works fine in my local dev environment. When I publish the project to Azure, calls to Validate controller function no longer work. Suspecting a problem with the proxy, I changed Validate() to give back hard-coded results, re-publish to Azure, and all works fine - confirming a problem with the web service proxy behavior in Azure.
[HttpPost]
public ActionResult Validate(String serializedformdata)
{
try
{
BsonDocument formdataasbson = this.serializer.JSONFormtoBSON(serializedformdata);
MessageHandlerClient client = new MessageHandlerClient();
this.jsonresponse.ReturnValue = "true";
StandaloneValidator.My_ServiceReference.Error[] results = client.ValidateMessage(formdataasbson["HLmessage"].ToString());
this.jsonresponse.ReturnMessage = results.ToJson();
return Json(this.jsonresponse);
}
catch (Exception ex)
{
this.jsonresponse.ReturnValue = "false";
this.jsonresponse.ReturnMessage = ex.Message;
return Json(this.jsonresponse);
}
}
What's more, I see details of the web service proxy in my local web.config file as below (IP intentionally obscured):
I have read various posts about web.config in Azure and the fact that it is not writable, so I'm suspecting my local ..... proxy info is never published in Azure. If indeed web.config does not publish from local to Azure, then I understand why my proxy doesn't work. The question is.....what should I do to fix??!
EDIT: I see various posts discussing migration of some settings from web.config to csfg files for Azure - perhaps a viable solution? Given that I am not coding manual read of these settings (I simply created service proxy from URL to service) I worry about auto-generated code or any "under-the-hood" behavior of the service not knowing how to read migrated settings from csfg.
Based on what you have written above, it seems you are confused with Web Role and Web Sites. First you would need to understand the difference between these two so you can make better decision on what to choose for your application. Here are some useful links:
SO discussion on difference between Azure Web Sites and Web Role
MSDN Article on when and why to choose Azure Web Sites and Web Role and Azure VM
Windows Azure Web site, you do not have full control over IIS web server and because of that some of the settings web site specific settings are configurable and others are not. In Windows Azure websites, most of machine and system specific settings added into web.config are overwritten so these settings does not work. Also you can not RDP to your Azure Websites instance as well.
If you have to use ASP.NET MVC application which MUST need proxy configuration, you must deploy it to Windows Azure Cloud Service.

Time Job Cannot Pass Proxy Server

I am just wondering how SharePoint Timer Job works with external services.
We have a web part and timer job that both call external service. Web part didn't pass our proxy as well, but after we changed proxy setting in web.config of that web application it works now.
How can we set our Timer Job to pass the proxy? It seems that is not related directly to our web application where we have installed our web part.
Read the same web.config with this code:
SPWebApplication webApp = this.Parent as SPWebApplication;
Configuration config = WebConfigurationManager.OpenWebConfiguration("/", webApp.Name);
String appValue = config.AppSettings.Settings["appSettingKey"].Value;

Resources