How to detect if ASP.NET site is running locally,

2019-04-30 17:58发布

Note: This is different from the question of detecting running locally versus in an Azure role, which I understand has been answered already.

I've got an APS.NET MVC app which I deploy to Azure. I'm running V2.5 of the Azure tooling. I'd like to be able to detect which of the following three scenarios the code is running in:

Locally (debugging on IIS), Azure website or Azure web role

I've seen in other posts the suggestion to use the following:

RoleEnvironment.IsAvailable

However, this seems to be an incomplete solution for my needs. It seems to detect if the code is running locally or as a web role with no problem. However, it doesn't seem to cover the scenario of checking for running as an azure web site. Not only does it not cover this, but trying to check that property when running in an Azure website makes it blow up with:

A first chance exception of type 'System.IO.FileLoadException' occurred in mscorlib.dll

Additional information: Could not load file or assembly
'Microsoft.WindowsAzure.ServiceRuntime, Version=2.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies.
The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

So, can anyone tell me how to detect between these three scenarios?

2条回答
男人必须洒脱
2楼-- · 2019-04-30 18:26

Let me offer you another approach will let you know if you are in Azure, Azure Emulator, IIS or locally running integration tests. This is important because it is useful and faster to debug in IIS express the pure web projects that you will eventually run in Azure or run integration tests which may run even outside of IIS. Which means that you can debug your project faster and not waste all the time loading/running the azure compute emulator every time.

There are several ways to check this and that but here is another method that can help you move around in all the cases for a good ALM and development.

You have four available mechanisms to use :

  1. HostingEnvironment object in IIS
  2. RoleEnvironment object in Azure or Azure Emulator
  3. System.Environment object that you have everywhere.
  4. Configuration - In my case web.config, web.debug.config, web.release.config, web.debug.staging.config, web.release.production.config, app.config, ServiceConfiguration.Local.cscfg, ServiceConfiguration.CloudStaging.cscfg and ServiceConfiguration.CloudProduction.cscfg

The problem consists in that : If you try to access RoleEnvironment.IsAvailable or RoleEnvironment.IsEmulated in IIS without running in Emulator or in Azure - you will get an exception. In Azure Emulator with IIS will get an exception too if the environment is not yet ready - Emulator and IIS are running together and IIS is not waiting for the emulator even though you get through RoleEntryPoint before you get to Global.asax.cs. This 'thing' eliminates the possibility to wait like that

  while(!RoleEnvironment.IsAvailable)

and resolve the issue quick and clean. This issue also eliminates the use of RoleEnvironment.IsEmulated because it will throw exception in local IIS or local integration test and it is not possible to check for RoleEnvironment.IsAvailable before it because if you wait for it to be ready outside of Azure or Azure Emulator you will wait for something that is going to be there.

Side note : Sometimes in the emulator environment can load later then your MVC project and accessing RoleEnvironment properties throws exception. This can be mitigated easily by waiting for it by calling

 while(!RoleEnvironment.IsAvailable)

End of side note.

Side note 2 Setting Environment variable in RoleEntryPoint like that :

public class WebRole : RoleEntryPoint
{
    public override bool OnStart()
    {
        Environment.SetEnvironmentVariable("CodeRunsInAzure","true");
    }
}

will not work because they run in different places and you are not able to retrieve it like that :

Environment.GetEnvironmentVariable("CodeRunsInAzure")

in Global.asax.cs or elsewhere in your Web/Worker project. Otherwise the problem will be easily resolved.

End of side note 2.

The solution is in two parts. The first is in your configuration files. Just set the variable in your all your configs in which it is needed - *.cscfgs :

<Setting name="RunsInAzureCloudEnv" value="true/false"/>

in ServiceConfiguration.Local.cscfg - false and everywhere else in cscfg - true. Then in web.*.config / app.config accordingly

<add key="RunsInAzureCloudEnv" value="true/false"/>

This way the variable will be set to true only while you publish or you run it in the emulator otherwise it will be false.

One case of using this is when you want to run code only in azure - like updating the Edition of your old databases from the retired WEB edition to BASIC inside your custom implementation of IDatabaseInitializer. In this case you need to run your code only in Azure and only if it is not in the emulator but in your staging or production environment. The example usage is as follows :

// check the variable that is set only in azure environment
var runsInAzureEnvStr = CloudConfigurationManager.GetSetting("RunsInAzureCloudEnv");
bool runsInAzureEnv = false;
Boolean.TryParse(runsInAzureEnvStr, out runsInAzureEnv);

if(!runsInAzureEnv)
{
    return;
}   

If only the Emulator was ready before the MVC was launched only : if(RoleEnvironment.IsAvailable && !RoleEnvironment.IsEmulated) would be enough. If somebody knows how to make the two happen in exact sequence and share it - it will be nice.

查看更多
地球回转人心会变
3楼-- · 2019-04-30 18:35

The best way I've come across to determine if you're running on an Azure Website is to check for the presence of an environment variable specific to Azure Websites like WEBSITE_SITE_NAME. You could check this first, and if the variable does not exist, proceed with the RoleEnvironment.IsAvailable check.

See this answer for more specifics.

查看更多
登录 后发表回答