We recently deployed a .NET Framework 4.8 Web API 2 application to an Azure App Service. We’re using the Azure S1 application service plan.
Unfortunately, we’re seeing very inconsistent response times when making API requests to this service – sometimes as long as 10 seconds. The same application running on a VM takes less than a second.
Initially we assumed it was slow database query performance, but after doing some profiling it appears the queries actually run quickly and most of the time appears to be in “external code”.
Specifically, it appears that most of the time is spent in the OWIN request handler code:
Here is our Startup.cs:
app.UseCors(CorsOptions.AllowAll);
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions() {
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(AccessTokenExpirationInMinutes),
Provider = new CustomOAuthAuthorizationProvider()
});
app.UseCustomSessionAuthentication(new CustomSessionAuthenticationOptions());
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
var config = GlobalConfiguration.Configuration;
WebApiConfig.Register(config);
ServiceConfig.Register(config);
app.UseWebApi(config);
Has anyone experienced issues using OWIN in an Azure App Service? Is there special configuration or code changes needed?
Versions:
.NET Framework 4.8
MVC 5.2.3
Microsoft.Owin.* 3.0.1
Related
My ASP.NET web app takes an image file and uploads it to Azure storage as a BLOB. It works fine when ran locally in both debug & release mode. The problem occurs when the app is deployed through its Azure web app. Unfortunately, because I cannot get the stack trace I can't quite figure out what's causing the issue but the only thing I can think of is the Azure storage is blocking it for security reasons, but it's set to allow calls from Azure services so I thought it would allow it.
Here's the function that the site calls to upload the image. This is the only function that's called from the action so it has to be throwing an exception here.
public async Task<bool> UploadFile(IFormFile file, string fileName, Vendor vendor)
{
string storageConnectionString = _config.GetConnectionString("Storage");
CloudStorageAccount storage = CloudStorageAccount.Parse(storageConnectionString);
CloudBlobClient blobClient = storage.CreateCloudBlobClient();
string nameFormatted = vendor.Name.Replace(" ", "").ToLower();
var container = blobClient.GetContainerReference(nameFormatted);
await container.CreateIfNotExistsAsync();
using (var stream = file.OpenReadStream())
{
var blobRef = container.GetBlockBlobReference(fileName);
await blobRef.UploadFromStreamAsync(stream);
}
return true;
}
And here's the error that is thrown when deployed.
Although I could not see any obvious issue in your code, actually you can remote debug your application on Azure WebApp by Visual Studio.
There are three offical blogs introduce how to remote debugging on Azure WebApp.
Introduction to Remote Debugging on Azure Web Sites
Remote debug your Azure App Service Web App
Troubleshoot an app in Azure App Service using Visual Studio
You just need to follow the figure below to enable the Debugging feature of your App Service on Azure portal, then you can follow the blogs above to do it.
Hope it helps.
I have a very weird issue with a Web Application I have deployed.
Relevant Data:
Application Server: IIS 7.5
Server: Windows Server 2008 R2 Standard SP1
Framework: ASP.NET
.NET Framework: 4 (4.0.30319)
Application Pool: Integrated
I the web application I make use of a service that's authenticated with Client Certificate Authentication. I don't have problems relating to the authentication itself (it is working on my development environment). But I am seeing problems whenever I want to use the service from the server (production) environment.
Here's the relevant portion of the CODE:
private void SetupClienteCertificate(HttpWebRequest req)
{
var binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
var crt = new X509Certificate2(
txtClientCertificateFile.Text,
txtCertificatePassword.Text,
X509KeyStorageFlags.MachineKeySet
);
req.ClientCertificates.Add(crt);
}
The error I am getting is pretty common and self explanatory:
The request was aborted: Could not create SSL/TLS secure channel.
The very weird part of it is that if I run the exact same code from a C# .Net Windows Forms Desktop Application (with the same .NET 4 framework) I can get the code to communicate with the server.
So my question is: Why is it working from the Desktop Application and not working from the ASP.NET Web Application?
Some stuff that I've already made sure of:
SSLv3, TLS, TLSv1, TLSv2 are enabled in the registry
I am ignoring SSL CERTIFICATE ERRORS (not necessary, but JUST IN CASE)
Restarted the Application Pool every time I change something configuration wise.
Any ideas?
I think I get your problem. Can you ensure the account under which application pool is running have sufficient privilege to read certificate from certificate
store.
I have a .Net 4.5.2 WebApp that is calling my API. When I point my web app to the LocalHost version of my API, it gets the data, and comes back just fine. I published that API, and confirm that the API is working correctly with PostMan.
Then I run the exact same WebApp code, changing only the URI from localhost to live api, and I get a multiple exception error consisting of the following:
An existing connection was forcibly closed by the remote host
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
The underlying connection was closed: An unexpected error occurred on a send.
An error occurred while sending the request.
Here's my calling code
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("user", serializedUser);
response = null;
try
{
//Uri uri = new Uri("https://jsonplaceholder.typicode.com/posts/1");//https works
Uri uri = new Uri("https://api.acme.com/values/test");
//Uri uri = new Uri("http://localhost/5000/values/test"); //http localhost works
response = client.GetAsync(uri).Result;
}
catch (Exception e)
{
string er = e.Message;
}
}
EDIT 1: I created a .NET Core app from scratch, and my original code works perfectly calling my live API. My original code also work in .NET 4.5.2 calling a different "https" API.
EDIT 2:
So this is where I'm at now, I have created two generic apps from VS 2015, one is a .NET Core Web App, the other a .NET Framework Web App. I have used the above code exactly the same in both apps to call the API. In both apps, I can call a generic "https" api I found online (jsonplaceholder). I can also call the localhost version of my app at "http" from both. In the .NET Core version of the app, I can call my "https" live API and get the results I'm looking for. In the .NET Framework app I still get the same errors.
I can't figure out what the difference is between my Core and Framework requests that is getting one shut down when the other isn't.
It seems you are hosting the application on secured http environment (https). Are you using SSL certificate on the server where you are hosting your Web API? If not, It might be throwing the certificate related exceptions.
Just add the following line before the call to GetAsync and This will ignore the SSL errors.
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
This is only recommended in an intranet environment or other closed network where server identities can't be forged.
C# Ignore certificate errors?
Adding the following line before my API call fixed the issue, but I'd love to hear an explanation of what this line does, and any security risks this might impose using it in my web app.
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Props to this answer!
I have a Windows 8.1 Store application that I side-load on a Windows 10 Enterprise DELL tablet. The app uses data from a repository via an ASP.NET Web API installed on a remote server. The Web API is configured to use Windows Authentication. If I use Fiddler to make Web API calls I can see the several steps in the NTLM negotiation, the 401.2 HTTP Error messages returned twice before the HTTP 200 Ok.
However, my application gets the 401.1 and then it does not do anything else. In my application's package manifest, I have checked Enterprise Authentication check box in the list of required capabilities. Also, when I tested it with the Visual Studio Simulator, on my development machine, the negotiation was done and the Web API responded properly to my calls.
In order to have the NTLM Negotiation done automatically in the background, I though all that needs to be done is to have an HttpClientHandler object constructed like this:
var webApiAuthClientHandler = new HttpClientHandler()
{
Credentials = CredentialCache.DefaultNetworkCredentials,
ClientCertificateOptions = ClientCertificateOption.Automatic
};
Then, this HttpClientHandler object would be passed in the constructor of the HttpClient object used to make the Web API calls:
var webApiHttpClient = new HttpClient(webApiAuthClientHandler)
{
BaseAddress = new Uri(_myWebApiUri, UriKind.Absolute),
Timeout = new TimeSpan(0, 0, 150)
};
What am I missing? How do I get my app to automatically negotiate the authentication in the background and have my GetAsync call return the needed HTTP Code 200?
Any suggestion would be highly appreciated.
TIA,
Eddie
I see your issue has been resolved in MSDN forum: https://social.msdn.microsoft.com/Forums/windowsapps/en-US/58620579-240d-49da-8538-cee5aff91a68/w81-sideloaded-windows-81-application-generates-an-exception-when-calling-methods-of-an-restful?forum=wpdevelop
So I post it here to help more visitors find the solution easily.
Thank you.
I have two different web projects on Microsoft Azure. One project is a .NET MVC web application and the other project is a .NET Web API.
Both projects are configured to use Azure AD. The MVC web application is able to get a token and use it to make requests against the Web API. Here's sample code from the MVC web app.
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID));
ClientCredential credential = new ClientCredential(clientId, appKey);
result = authContext.AcquireTokenSilent(todoListResourceId, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
// Make a call against the Web Api
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, webApiBaseAddress + "/api/list");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
HttpResponseMessage response = await client.SendAsync(request);
So this code works just fine. However, what I need to do now is call the Web API directly from an AngularJS application. When I try to do that, I get a 401 unauthorized error.
The way I am doing this is by adding a header to the HTTP GET request sent by AngularJS. I'm setting "Bearer" to the result.AccessToken value that I am passing to the page from my MVC application (code above).
Obviously this doesn't work. I suppose now my question is what are my options? Is there an official or better way to do this? Let's say I wanted to make calls to the Web API from standard JavaScript (lets forget the complexities of AngularJS). Is there a way to authenticate with Azure AD?
the canonical way of obtaining a token for an in-browser JS application would be to use the OAuth2 implicit flow. Azure AD does not currently expose that flow, but stay tuned: we are working on enabling the scenario. No dates to share yet.
HTH!
V.
The work I mentioned in the older answer finally hit the preview stage. Please take a look at http://www.cloudidentity.com/blog/2014/10/28/adal-javascript-and-angularjs-deep-dive/ - that should solve precisely the scenario you described. If you have feedback on the library please do let us know!
Thanks
V.