I have a web role on azure and I would like to force a Application_Start without waiting for the first request.
I managed to set the "Start Automatically" property to true on my site
AutoStart a WCF on Azure WebRole
But the Application_Start is not called until the first request comes.
I don't know exactly if I am missing something important here. The server is a W2008 R2 and the IIS version is 7.5
Thanks!
SOLUTION
I put the solution code here. I hope will help someone. I just added a WebRole.cs and just put that code to perform a ping every 30 seconds. Please netice I'm browsing Service.svc because this is my endpoint, your endpoint could be another one. Notice I'm asking for "Endpoint1". If you have more than one endpoints, you should review that line.
public class WebRole : RoleEntryPoint
{
public override void Run()
{
var localuri = new Uri( string.Format( "http://{0}/Service.svc", RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["Endpoint1"].IPEndpoint ) );
while (true)
{
try
{
var request = (HttpWebRequest)WebRequest.Create(localuri);
request.Method = "GET";
var response = request.GetResponse();
}
catch { }
System.Threading.Thread.Sleep(30000);
}
}
public override bool OnStart()
{
return base.OnStart();
}
}
The IIS will only start when the first request arrives. The workaround is to send an HTTP request to the same VM from within OnStart or your RoleEntryPoint descendant - that's easy using WebRequest or equivalent class.
Jordi, I've recently experienced the same issue.
Based on my test Application_Start() is called ONLY when the 1st request ISS for the WebApp. (if you try to start VS in Debug without it open any page (see options in proj/debug), you will see that Application_Start() won't be called also if you don't run the WebApp in Azure)
I suppose that you need doing somethings when the WebRole start, well put your code in the WebRole.cs ;)
Here you can override OnStart() and OnStop() and put your code that wiil be execuded when the WebRole will start.
I've used this way to run a BakgroundWorker that do some scheduled tasks, independently from IIS.
I hope this help.
Davide.
Note:
1 - if you dont'have a WebRole.cs create it in the root of project and write inside:
public class WebRole : RoleEntryPoint
{
public override bool OnStart()
{
...your code...
return base.OnStart();
}
}
2 - If you need to debug the code mind that you need to run VS in debug with the Azure project that refer to WebApp as a "Run Project", otherwise the WebRole will not be called
You could try putting some code in your WebRole.cs to request some URLs from your website. I've tried that, and it seems to work somewhat. But it's a pain to debug, so I never got it really nailed down.
Another option would be to use IIS Application Initialization. You can't use it on IIS 7.5, but you can get IIS 8 if you upgrade your roles to Windows 2012 (set osFamily="3" in your .cscfg).
Related
Is the following code called after recycle when hosted in IIS:
[assembly: OwinStartup(typeof(xxx.Startup))]
public class Startup
{
public void Configuration(IAppBuilder app)
{
}
}
Yes, recycling works similary to "Reset", with the difference of first starting a new worker process and then shuting down the old in an attempt to keep the website availible for requests. It also tries to transfer the old requests to new process.
Good Article on this topic: https://fullsocrates.wordpress.com/2012/07/25/iisreset-vs-recycling-application-pools/
We finally got EventSource and ElasticSearch correctly configured in our service fabric cluster. Now that we have that we want to add EventSources to our web applications that interact with our service fabric applications so that we can view all events (application logs) in one location and filter / query via Kibana.
Our issue seems to be related to the differences between a service fabric app which is an exe and a .NET 4.6 (not .net CORE) web app which is stateless. In service Fabric we place the using statement that instantiates the pipeline in Program.cs and set an infinite sleep.
private static void Main()
{
try
{
using (var diagnosticsPipeline = ServiceFabricDiagnosticPipelineFactory.CreatePipeline("CacheApp-CacheAPI-DiagnosticsPipeline"))
{
ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(Endpoint).Name);
// Prevents this host process from terminating so services keeps running.
Thread.Sleep(Timeout.Infinite);
}
How do I do this in a web app? This is the pipeline code we are using for a non ServiceFabric implementation of the EventSource. This is what we are using:
using (var pipeline = DiagnosticPipelineFactory.CreatePipeline("eventFlowConfig.json"))
{
IEnumerable ie = System.Diagnostics.Tracing.EventSource.GetSources();
ServiceEventSource.Current.Message("initialize eventsource");
}
We are able to see the pipeline and send events to ElasticSearch from within the using statement but not outside of it. So the question is:
how/where do we place our pipeline using statement for a web app?
Do we need to instantiate and destroy the pipeline that every time we log or is there a way to reuse that pipeline across the stateless web events? It would seem like that would be very expensive and hurt performance. Maybe we can we cache a pipeline?
That’s the jist, let me know if you need clarification. I see lots of doco out there for client apps but not much for web apps.
Thanks,
Greg
UPDATE WITH SOLUTION CODE
DiagnosticPipeline pipeline;
protected void Application_Start(Object sender, EventArgs e)
{
try
{
pipeline = DiagnosticPipelineFactory.CreatePipeline("eventFlowConfig.json");
IEnumerable ie = System.Diagnostics.Tracing.EventSource.GetSources();
AppEventSource.Current.Message("initialize eventsource");
}
}
protected void Application_End(Object sender, EventArgs e)
{
pipeline.Dispose();
}
Assuming ASP.NET Core the simplest way to initialize EventFlow pipeline would be in the Program.cs Main() method, for example:
public static void Main(string[] args)
{
using (var pipeline = DiagnosticPipelineFactory.CreatePipeline("eventFlowConfig.json"))
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
host.Run();
}
}
This takes advantage of the fact that host.Run() will block until the server is shut down, and so the pipeline will exist during the time when requests are received and served.
Depending on the web framework you use things might vary. E.g. if the one you use offers "setup" and "cleanup" hooks, you could create a diagnostic pipeline during setup phase (and store a reference to it in some member variable), then dispose of it during cleanup phase. For example, in ASP.NET classic you'd put the code in global.asax.cs and leverage Application_OnStart and Application_OnEnd methods. See Application Instances, Application Events, and Application State in ASP.NET for details.
Creating a pipeline instance every time a request is served is quite inefficient, like you said. There is really no good reason to do that.
I need to add an IIS module for some processing. Here is my module:
namespace MyNamespace
{
public class MyModule : IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
}
public void Init(HttpApplication context)
{
//I hope to do some work here ONLY once for all requests
context.ReleaseRequestState += new EventHandler(myHandler);
}
#endregion
public void myHandler(Object source, EventArgs e)
{
//do some work...
}
}
}
I need to do some resources-consuming work in the Init() method. I HOPE that Init is called ONLY once in a website and is called again only when the website is restarted in IIS Manager.
Can an expert in this tell me whether Init() works as I hope for?
Thanks!
For ANY requests being carried out, it will always call this method so no, it is not for the first time the app pool spins up. What you may wish to do is have a static variable in there to see if it truly is the first time its been hit and if not, carry on with what you need otherwise ignore it. ensure you lock around the portion of code when you are setting the variable to true.
Remember, IIS has application pools which websites use (generally speaking). There will be multiple concurrent requests coming into IIS to process and what happens? The app pool executes to serve the request to the website therefore multiple "hits" will be executed for the Init() for the HttpModule but once per application, if that makes sense.
Every one of them initializes their own list of modules.
you DO have the option of using the Application_Start event in the global asax which will only ever execute once per application (when the app pool spins up and the request is being submitted) - perhaps you can use this for your needs, which would be a better option.
I'm having some troubles in my production environment, I found some clues that can lead to an IIS reset, but I'm not sure.
How and where can I find if there was an IIS reset in the past?
Edit:
Regarding the future resets the Kevin's solutions is ok and I have successfully used it.
You could create a Global.asax file on your ASP .Net application. Then you can hook into the application start and stop events with the following methods:
public void Application_Start(object sender, EventArgs e)
{
// log iis started
}
public void Application_End(object sender, EventArgs e)
{
// log iis stopped
}
All you have to do is declare these methods in your global.asax file, ASP .Net will automatically call them when your application is started/stopped. You can then do any logging code you need inside these methods.
I have an ASP.NET MVC 4 site running perfectly well in an Azure WebRole. The ASP.NET MVC project was started on its own, after which I added an Azure Cloud Service project to the solution and added the ASP.NET project/site as one of the 'roles' of the service (so it shows up in the 'Roles' folder).
My problem is that I would like to have working a WebRole.cs file within the ASP.NET MVC project, but no matter what I've tried to do, it appears that when deployed, it just never gets called. OnStart and the override of Run (which I know, must never leave the loop) -- these just apparently never get called.
But if you startup a new CloudService project and add, at that time from the start, an ASP.NET MVC project, it automatically has a WebRole.cs file in it, so my guess is that I need to configure something somewhere for the WebRole.cs (actually speaking, the WebRole class, which inherits RoleEntryPoint) to get called. What might that be?
using System;
using System.Web;
//using Microsoft.WindowsAzure.StorageClient;
using System.Diagnostics;
using System.Threading;
namespace Us.WebUI
{
public class WebRole : Microsoft.WindowsAzure.ServiceRuntime.RoleEntryPoint
{
public override bool OnStart()
{
return true; //return base.OnStart(); // CALL THIS???
}
public override void Run()
{
while (true) {
Thread.Sleep(TimeSpan.FromSeconds(30));
try {
EmailFuncs.SendEmailToUs("An email from our WebRole?????", "Email me this, email me that.");
}
catch { }
}
}
}
}
UPDATE: Thanks, the question has been answered. But I will add: On doing this, while it clearly was working (fully deployed and in emulator), that suddenly I was having problems doing a full publish of the site. After a azure publish took 3 hours:
Verifying storage account 'xyz'... > Uploading Package... > - Updating... [stayed here for 3 hours], it failed with this error: The server encountered an internal error. Please retry the request. So one thing I was wondering is, did I need to override OnStop in WebRole.cs?
UPDATE 2: Those previous problems were fixed, and had nothing to do with this issue. Actually, I've learned this: If you ever have any warnings generated in your build, Azure often will not work with them even when they don't cause problems locally or in other hosts. Since then, I've been much more studious to tackling build warnings (but critical to this is turning off with warning codes the many warning types you want to ignore!).
Adding a class to your Web Project which inherits from RoleEntryPoint is sufficient, it should just work. Did you try setting a breakpoint in the emulator?
What you might be experiencing is that EmailFuncs.SendEmailToUs requires info from the app/web.config and that this info is not available. You need to know that your WebRole class runs in a different process (not your web application), meaning it's not using your web.config. If you want the WebRole.cs to read info from the configuration file, you'll need to add these settings in WaIISHost.exe.config