Just starting off with Breeze and Azure. I downloaded the sample app and added my own controllers. On my local machine it works just fine. When I deploy to my Azure site, I keep getting the following error in the logging section of the page: Query failed: Metadata query failed for: api/CoreData/Metadata; An error has occurred.
I have a controller named Products that simply returns a view. The view contains the js calls to my CoreData ApiController. Follows the sample.
The only thing logged on the server is the following:
At first I was using EF to access data, but have changed to just creating an in-memory object and returning it so as to eliminate db issues.
The URL is http://acapella.azurewebsites.net/products. I've spent quite a bit of time trying to diagnose and research, but feel that I'm overlooking something simple.
Any help or suggestions would be appreciated.
An Azure web site is a free, relatively easy way to deploy a Breeze application where you can test it on a variety of mobile devices and experience your app's responsiveness (or lack thereof).
I have had good success pushing a Breeze app to an Azure web site but there were many stumbles including some that looked like yours.
Two thoughts. First, you'll want to turn "Custom errors off" in your Web.config.
<configuration>
<system.web>
<customErrors mode="Off"/>
</system.web>
</configuration>
My second recommendation: take a look at John Papa's post on deploying an MVC Web API app to an Azure web site. It is excellent. And I know it works.
I hope to have a video on the process very soon.
The first thing you can do is return the exception. In your Breeze controller do this:
[HttpGet]
public string Metadata()
{
try
{
return _contextProvider.Metadata();
}
catch (Exception e)
{
return e.Message + Environment.NewLine + Environment.NewLine + e.StackTrace;
}
}
That made it clear to me something was wrong with my connection string. The exception I got was:
Format of the initialization string does not conform to specification starting at index 0.
My connection string locally seemed ok, but the problem was on Azure. My web.release.config had a correct transform, but when publishing, Visual Studio would add another connection string. You can check this by connecting with FTP to your Azure site and looking at your web.config. I fixed it by selecting the correct connection string when publishing:
After that, there still seem to be two connection strings in my uploaded web.config, but at least it works.
Related
I created a simple Blazor WASM webapp using C# .NET5. It connects to some Functions which in turn get some data from a SQL Server database.
I followed the tutorial of BlazorTrain: https://www.youtube.com/watch?v=5QctDo9MWps
Locally using Azurite to emulate the Azure stuff it all works fine.
But after deployment using GitHub Action the webapp starts but then it needs to get some data using the Functions and that fails. Running the Function in Postman results in a 503: Function host is not running.
I'm not sure what I need to configure more. I can't find the logging from Functions. I use the injected ILog, but can find the log messages in Azure Portal.
In Azure portal I see my 3 GET functions, but no option to test or see the logging.
With the help of #Aravid I found my problem.
Because I locally needed to tell my client the URL of the API I added a configuration in Client\wwwroot\appsettings.Development.json.
Of course this file doesn't get deployed.
After changing my code in Program.cs to:
var apiAddress = builder.Configuration["ApiAddress"] ?? $"{builder.HostEnvironment.BaseAddress}/api/";
builder.Services.AddHttpClient("Api",(options) => {
options.BaseAddress = new Uri(apiAddress);
});
My client works again.
I also added my SqlServer connection string in the Application Settings of my Static Web App and the functions are working as well.
I hope somebody else will benefit from this. Took me several hours to figure it out ;)
As described in various other related questions here, I am also expecting long lasting (30 seconds) first call after (re)deploying a web role with pretty large EF6 Model and a plenty of referenced nuget-packages. After trying out different proposed solutions with preloadEnabled and serviceAutoStartProviders I am still consufed and decided to reopen this topic in hope, that somebody has come upon a better solution in the meantime.
The main goal for me is to make a web role answering the first request almost as fast as subsequent calls as soon as the role quits its busy state on a fresh deployment and gets accessible by load balancer and external clients. Unfortunately I experienced following problems with proposed solutions so far:
preloadEnabled:
I do add Application Initialization module via PKGMGR.EXE /iu:IIS-ApplicationInit in a startup task. So far so good.
When I then try to execute %windir%\system32\inetsrv\appcmd set site "MySiteName" -applicationDefaults.preloadEnabled:true it fails as at the time of execution of a startup script there are still no websites created in IIS on a fresh deployment.
If I try to set the preloadEnabled-setting via ServerManager-class in my Application_Start method instead, I cannot understand, how this code is intended to be executed before a first external call on the web role is made, as the preloadEnabled setting is defaulted to false after a fresh web role deploy and thus the Application_Start method in my understanding does not get a chance to be executed by the Application Initialization module?
serviceAutostartProviders:
here we need to put a name of our AutostartProvider implementing the IProcessHostPreloadClient interface in applicationhost.config i.e by using either appcmd script or the ServerManager class, BUT:
serviceAutostartProvider is like preloadEnabled a site related setting, so we have the same problem here as with %windir%\system32\inetsrv\appcmd set site "MySiteName" -applicationDefaults.preloadEnabled:true in 1.2 - at execution time of startup script after a fresh deployment the websites are not yet created in IIS and the script fails to execute properly
Another possibility would be to include applicationhost.config into the deployment package, but I did not find any solution to do this for a web role.
So how did you guys managed to ensure, that preloading assemblies and some initialization code (like filling memory caches) is run before the role gets it's first hit from outside?
We start to gain some traffic now and get approx. 1-2 requests per second on our WebApi, and thus a 30 second delay for preloading "visible" to clients after each update deployment is becoming a major issue now.
We are scheduling update deploys at low traffic times, but what if I need to make an urgent hotfix deploy?
Perhaps the best way to accomplish this is to use deployment slots. Deploy updates to your staging slot first. Before a switch from a staging slot to a production slot takes place, Kudu will hit the root of the staging slot with a request in order to warm up the application. After the request to the staging slot's root returns, the IP switch occurs and your slots are swapped.
However, sometimes you need to warm up other pages or services to get the app ready to handle traffic, and hitting the root with a warmup request is insufficient. You can update your web.config so that Kudu will hit additional pages and endpoints before the IP switch occurs and the slots are swapped.
These warmup request URLs should be in the tag. Here's an example:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<applicationInitialization>
<add initializationPage="/pagetowarmup1" />
<add initializationPage="/pagetowarmup2" />
<add initializationPage="/pagetowarmup3" />
</applicationInitialization>
</system.webServer>
</configuration>
You can read the Kudu docs on this issue here.
OK. Now I got it.
The point is to set preloadEnabled-property not inside of the Application_Start method in Global.asax (as it will not be hit before a first request to the Role anyway), but inside RoleEntryPoint.OnStart.
The difference is that RoleEntryPoint.OnStart is called directly after deployment package is extracted and everything is set up for starting the role. At this moment the azure instance is still in it's busy state and is not yet available from outside as long as some code inside RoleEntryPoint.OnStart is being executed.
So here is the code I came up so far for warming up the instance before it gets its first call from outside
public class WebRole : RoleEntryPoint
{
public override bool OnStart()
{
// set preloadEnabled of each Site in this deployment to true
using (var serverManager = new ServerManager())
{
foreach (var mainSite in serverManager.Sites)
{
var mainApplication = mainSite.Applications["/"];
mainApplication["preloadEnabled"] = true;
}
serverManager.CommitChanges();
}
// call my warmup-code which will preload caches and do some other time consuming preparation
var localuri = new Uri(string.Format("https://{0}/api/warmup", RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["Endpoint1"].IPEndpoint));
try
{
var request = (HttpWebRequest)WebRequest.Create(localuri);
request.Method = "GET";
var response = request.GetResponse();
}
catch { }
// send this thread to sleep in order to give the warmup-request a chance to complete BEFORE the Role will get started
// and becomes available to the outside world
System.Threading.Thread.Sleep(60000);
return base.OnStart();
}
}
After upgrading to ServiceStack to 4.0.24.0, I started receiving this below error when trying to login using Google OAuth.
The same works locally on my dev machine.
Has anything changed since the 4.0.21.0?
The site is hosted on Azure as you can see from the address bar.
I've the licensed version of SS
Google OAuth Callback url is correctly registered http://somesite.azurewebsites.net/auth/GoogleOAuth
Using ServiceStack.Authentication.OAuth2 4.0.24.0
This is a pretty strange problem, but recently did some digging and here is what I found. It seems that Azure Websites doesn't like the HttpResult returning from the method Authenticate on the OAuth2Provider.
Important to note: This problem is only present when hosted on Azure Websites. ServiceStack OAuth2Providers (4.0.24 to 4.0.40) work as expected when hosted else where.
Specifically, it doesn't like the Content-Length header being set when returning a HttpResult. I'm not sure exactly why this is the case as it works locally and when deployed to my own IIS host on AWS.
I've created a repository you can deploy yourself that highlights this issue.
Azure Websites seem to be interpreting this response differently than on a standard IIS setup (eg, installed via Web Installer on a clean VM) which seems to be causing the problem.
One (not very nice) work around would be to use a GlobalResponseFilter stripping out Content-Length header of the only the GoogleOAuth2Provider response.
I've tested this out and indeed worked as expected and I was able to login using Google OAuth. Here is an example of using a GlobalResponseFilter to work around this problem.
GlobalResponseFilters.Add((req, res, dto) =>
{
if (!req.PathInfo.EndsWith("/auth/GoogleOAuth", true, CultureInfo.InvariantCulture))
{
return;
}
HttpResult httpResult = dto as HttpResult;
if (httpResult != null && httpResult.Headers.ContainsKey("Content-Length"))
{
httpResult.Headers.Remove("Content-Length");
}
});
Would be great if someone can point out why Azure websites does this.
Hope this helps.
namespace StorageRoleMVC4.Controllers
{
public class SearchController : ApiController
{
public Dictionary<string, string> Get([FromUri] string searchString, [FromUri] string searchObject)
{
var searchHelper = new SearchStorageHelper();
var objectList = searchHelper.Retrieve(searchString, searchObject);
return objectList;
}
}
}
Is there anything about this controller that makes it unreachable once it's deployed (to an Azure web role)? I just get a 404 error when I try to reach it. It works great on the local emulator.
The last 2 times I've deployed my project, all the controllers in my web service have returned 404 errors for several hours, until the project seems to fix itself. I'm not sure why, but it might be related.
UPDATE
There is a WARNING in the event log on the web role VM after I publish:
The application '/' belonging to site '1273337584' has an invalid AppPoolId 'ea7a2e15-9390-49e1-a16b-67ff1cdb7dcb' set. Therefore, the application will be ignored.
This is the id of my site, but the AppPoolId is not correct. Changing the app pool turns the 404 into a 502.
Also, after publishing, the World Wide Web Publishing Service is turned off. When I turn it on and do an IIS reset, after the reset it's turned off again.
When I reboot the web role VM, most of the controllers work again, and the World Wide Web Publishing Service is turned on. But still, this SearchController doesn't work. Or any other new controllers I've created since this problem started happening.
Well, after a ridiculous amount of unsuccessful troubleshooting, I just rolled back to an earlier version of the code and found that it didn't read the web service when I deployed it. So I started over with that version and re-built the delta.
This involved removing a few web.config entries and removing some libraries, creating a few classes and referencing them in the global.asax (I think that's where it was) in order to override te Authorize attribute...
If anyone has a better answer, I will switch the answer to what you post.
After i have deployed my ASP.NET WebRole to Azure and looked into the Azure Intellitrace i noticed a lot of RoleEnvironment Exceptions and they are occuring at RoleEnvironment.IsEmulated.
I thought there is something missing in ServiceConfiguration because the next-to-last call in stacktrace is always RoleEnvironment.GetConfigurationSettingValue.
Now i searched after this problem but i found nothing but this link:
http://bretstateham.com/azure-serviceconfiguration-cscfg-changes%E2%80%A6/
But my service configuration is correct. I think the setting ?IsSimulationEnvironment? should be created by Azure, but not in my case because of the exceptions.
And i cannot put the "?IsSimulationEnvironment?" Setting manually in my configuration, because that is not compliant to the xml namespace of the serviceconfiguration.
Has anybody got an idea how to solve this annoying problem?
I think your RoleEnvironment is not available to you yet. ie you are checking RoleEnvironment.IsEmulated before its initialized...
Try this,
while (!RoleEnvironment.IsAvailable)
continue;//you can sleep sometime then continue
if (RoleEnvironment.IsEmulated)
{
//Your code here
}