Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can C# Library Code know it's hosting application type without System.Web.dll?

Tags:

c#

.net

iis

We are developing several applications in Visual Studio 2010 using C# and .NET 4.0 on Windows. Two SilverLight applications using services from several WCF projects. Another is a console application.

We want to put some "common" functionality in a separated Library project in order to factorize and reuse code. This library needs to know if the application is hosted (IIS, ASP.NET...) like the WCF services or is running as a console application, due to different file path handling.

Googling this question, people indicates the use of System.Web.dll in order to know if the code is hosted, using HttpContext, HostingEnvironment.IsHosted... The problem is that such approach requires to include a reference to System.Web int he Library project, being not acceptable if this Library will be referenced by a Console project with Client Profile.

The idea is to use another technique that do not involve the use of System.Web assembly.

like image 887
David Oliván Ubieto Avatar asked Mar 01 '11 12:03

David Oliván Ubieto


Video Answer


3 Answers

If you only need to get the path to a file in the folder containing the application (as in the comment on question), you can use:

Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "filename")

For an ASP.NET application, this will be the root folder (same as MapPath("~/" + filename)), for a console application it will be the folder containing the executable.

From the comment to the original question:

when running a as console application, just use the filename as a relative path

I wouldn't recommend using a relative path. This will be relative to the current working directory, which may not be the same as the application directory.

like image 51
Joe Avatar answered Nov 14 '22 20:11

Joe


There are several ways to check if an application is ASP.NET or not.

Check the name of the configuration file

if ("web.config".Equals(Path.GetFileName(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile), StringComparison.OrdinalIgnoreCase))
{
    // ASP.NET application
}

An ASP.NET application does not have an entry assembly

if (Assembly.GetEntryAssembly() == null)
{
    // ASP.NET application
}

An ASP.NET application uses shadow copies of all .dll files. However, I'm not sure if this is possible in other types of applications.

if (AppDomain.CurrentDomain.ShadowCopyFiles)
{
    // ASP.NET application (probably)
}
like image 21
Coder Avatar answered Nov 14 '22 22:11

Coder


Another reflection idea: use System.Web, but through reflection:

  1. use AppDomain.CurrentDomain.GetAssemblies() to see if System.Web is loaded; if not, you're not hosted
  2. if it is loaded, use reflection to call HostingEnvironment.IsHosted

Turns out that's easier said than done, but this seems to do the trick:

public static bool IsHosted()
{
  try
  {
    var webAssemblies = AppDomain.CurrentDomain.GetAssemblies()
      .Where(a => a.FullName.StartsWith("System.Web"));
    foreach(var webAssembly in webAssemblies)
    {
      var hostingEnvironmentType = webAssembly.GetType("System.Web.Hosting.HostingEnvironment");
      if (hostingEnvironmentType != null)
      {
        var isHostedProperty = hostingEnvironmentType.GetProperty("IsHosted",
          BindingFlags.GetProperty | BindingFlags.Static | BindingFlags.Public);
        if (isHostedProperty != null)
        {
          object result = isHostedProperty.GetValue(null, null);
          if (result is bool)
          {
            return (bool) result;
          }
        }
      }
    }
  }
  catch (Exception)
  {
    // Failed to find or execute HostingEnvironment.IsHosted; assume false
  }
  return false;
}

The reflection is probably expensive so execute once and cache the result. I'm also not sure what the best way to find the specific assembly and type is, but this way works.

like image 40
Rup Avatar answered Nov 14 '22 20:11

Rup