Adventures on the edge

Learning new development technologies
    "When living on the bleeding edge - you sometimes have to bleed" -BillKrat

ASP.NET MVC–ASPNET_ENV not working

It is recommended that you familiarize yourself with Working with Multiple Environments, it is a comprehensive article that goes into detail on how to configure your application for Development, Staging, and Production.  


One of the first things I encountered was that the launchSettings.json file was not available under Properties (reference bottom pane of figure 1).   A second issue I encountered was that the StartupDevelopment and StartupStaging class methods were not not being invoked as expected – the application defaulted to the Startup class methods.

StartupDevelopment
Figure 1

To resolve the first issue I switched over to the “web” profile (discussed in the article) and set the ASPNET_ENV value to Staging.   There was an asterisk indicating that the project’s Debug setting was changed.  Once I clicked the save button (see #3 top of figure 2) the launchSettings.json file was created (ref figure 3).

StartupStaging
Figure 2

PropertiesShows
Figure 3

The second issue required me to step through the source code.  Where the Startup conventions worked for methods, e.g., ConfigureDevelopment() was invoked, I could not get my StartupDevelopment class to be recognized by application – it kept defaulting to the Startup class.

In reviewing the source code, line 61 of figure 4 is looking for the startup assembly name (in this case GwnBible) and then StartupDevelopment as set on line 55.  I had created my StartupDevelopment and StartupStaging classes under an Environment folder which was part of the namespace (line 6 of middle pane) – this prevented the classes from being discovered by the StartupLoader.  Once I changed the namespace to GwnBible everything started working as expected.

StartupSource
Figure 4

LinqPad–“cannot access a non-static member… via nested type 'UserQuery.SqlStorageDal'”

The actual complete LinqPad error follows:

“Cannot access a non-static member of outer type 'System.Data.Entity.DbContext' via nested type 'UserQuery.SqlStorageDal'”

This occurs when you attempt to access the data context tables or commands (such as SaveChanges) from within classes; it only appears to work within the Main() context of LinqPad.  Since I am using LinqPad to design the data access layer for my Entity Framework data context this was going to be quite restrictive – I’d like to complete the basic work here and transfer the classes into my final project without refactoring.

My workaround was to create some private fields (reference bottom right pane in image below) and then provide it instances from within the Main() method.  I can then access these private fields from my class code (top right pane in image below).   When I migrate this code into my live projects I can copy/paste these private fields into my class and set references from my constructor or initialization code.

Code

ASP.NET MVC - Setting up an Area (beta7)

“The scenario that areas address is being able to partition your application into discrete areas of functionality. It helps make managing a large application more manageable and allows for creating distinct applets that you can drop into an application” -- Phil Haack  read more

Setting up an Area under ASP.NET MVC (beta7) is rather straight forward. 

  1. Apply the [Area(“YourArea”)] attribute to your controller
  2. Setup your Areas\<YourArea>\Views* folder comparable to normal views
  3. Configure an “areaRoute” in your Startup.Configure method.

* The following locations are searched for view files:
/Areas/<YourArea>/Views/Home/Index.cshtml
/Areas/<YourArea>/Views/Shared/Index.cshtml
/Views/Shared/Index.cshtml.

Note: My HomeController actually resides in a separate PocArea project.

AreaCode

ASP.NET MVC - Server.MapPath (beta7)

Server is currently not available under the new HttpContext but there are two ways to get the traditional MapPath results.  

  1. You can use the extension method MapPath for the IHostingEnvironment interface.
  2. You can retrieve the path from the IApplicationEnvironment instance.

Both of these are easily accessible via constructor injection, by placing them in the HomeController constructor as shown below you can easily extract the path you are looking for.

public HomeController(
IApplicationEnvironment appEnv,
IHostingEnvironment server)
{
var wwwRoot = server.MapPath("web.config");
var webConfig = new FileInfo(wwwRoot);
var isWebConfig = webConfig.Exists;

var svrPath = server.MapPath("Views/Home")
.Replace(@"\wwwroot", "");
var isDirSvr = Directory.Exists(svrPath);

var envPath = appEnv.ApplicationBasePath
+ @"\Views\Home";
var isDirEnv = Directory.Exists(envPath);
}
Code

ASP.NET MVC4 - Setting up Dependency Injection (Unity) Revised

Back in 2011 I wrote an article after studying Brad Wilson’s article on controllers; I based my UnityControllerFactory on his work; the controller factory is how you hook an IOC container into MVC 4.   It is possible that since 2011 there are newer/improved ways of doing this, but I opted to simply blow the dust off of old code, build a new ASP.NET MVC 4 website from Visual Studio 2012, plug in my old project, and update the article to help a fellow developer in this forum thread.

The following animated gif displays the output of this SOURCE CODE when you click on the refresh button in the browser.   Note that the page will default to the “Foo2” implementation upon startup because of the the following Web.Config setting:

<appSettings>
<add key ="DefaultFoo" value="Foo2"/>
AnimatedMVC4
Figure 1.  Refresh button being hit on Index page.
 

From that point on the AppSettings will be maintained in memory and can be updated as needed - in our case we use the AppSettings “DefaultFoo” setting to determine whether we are going to use Foo1 or Foo2 (they both implement IFoo).

In the source code you’ll find a Gwn.Library.Controller project, it contains the necessary framework components to quickly standup a MVC 4 website using Unity dependency injection - it also contains the mock classes (Foo stuff).   Lines 35 and 36 in the top pane of figure 2 are responsible for swapping out the implementation used by lines 22-30.

To setup a new project to utilize my Dependency Injection hook, it will take four steps:

  1. Create your ASP.NET MVC 4 website
  2. Right click on references and select Manage NuGet packages to install the Microsoft Unity IOC package.
  3. Add a reference to the Gwn.Library.Controller project
  4. Update the Controller and Global.asax classes with the content highlighted in yellow boxes.

That’s pretty much it - everything else is gravy after that.

MVC4Source

Figure 2 source code updates to applicable classes

The ControllerFactoryInitialize() method on line 28 in the bottom pane of figure 2 above is what “hooks” our UnityControllerFactory class into the framework.  

We can use a new RegisterTypes() override, provided by the HttpApplicationBase class, to register our implementation in the Unity container.   By default, registrations are “Transient” which means a new implementation is instantiated each request from the container.   We need AppSettings to be a singleton because it not only pulls in the AppSettings into a collection (which we only want to do once) but also permits us to update that collection programmatically so I use the following parameter:
    new ContainerControlledLifetimeManager()
to let Unity know it will be a singleton - it is not a singleton in the true sense (static class) but within the context that the same instance is always served up when requested.

With my AppSettings being a singleton I can now use the following code:
   AppSettings.SetSettings(DefaultFoo, toggleKey);
on line 36 of figure 2 (top pane) to update the value to a toggled state.

Note above on lines 35 and 36 (bottom pane) that I register two implementations of IFoo - I give them names that match their class names for convenience.  This allows me to to programmatically select the concrete class to use for the IFoo implementation by simply getting the current setting (which will be “Foo1” or “Foo2”). 

Reference the GetDefaultFoo() method below - I invoke the following:
    var configKey = _settings.GetSettings(“DefaultFoo”)
    var returnValue = _provider.Resolve<IFoo>(configKey); 

The first time I call this method the value will come from what was pulled in from the App.Config and subsequent use will come from any updates made to the AppSettings.          

using Gwn.Library.Controller.Interfaces;
using Microsoft.Practices.Unity;

namespace Gwn.Library.Controller.Mocks
{
public class FooFactory
{
private readonly IUnityContainer _provider;
private readonly IAppSettings _settings;

/// <summary>
/// Initializes a new instance of the FooFactory class.
/// Using construction injection to set the implementation
/// for IUnityContainer and IAppSettings
/// </summary>
/// <param name="provider">The provider.</param>
/// <param name="settings">The settings.</param>
public FooFactory(
IUnityContainer provider, IAppSettings settings)
{
_provider = provider;
_settings = settings;
}

/// <summary>
/// Gets the default foo based on Web.Config setting.
/// </summary>
/// <returns>IFoo.</returns>
public IFoo GetDefaultFoo()
{
// Get the "defaultFoo" setting from the Web.Config file
var configKey = _settings.GetSetting("DefaultFoo");

// Use named value to retrieve IFoo
var returnValue = _provider.Resolve<IFoo>(configKey);
return returnValue;
}
}
}

Note in our AppSettings constructor below that I pull the settings from the Web.config file into our _appSettings field.   The SetSettings will add or update collection values as applicable.
using System.Linq;
using System.Web.Configuration;
using Gwn.Library.Controller.Interfaces;
using System.Collections.Specialized;

namespace Gwn.Library.Controller.Implementation
{
public class AppSettings : IAppSettings
{
private readonly NameValueCollection _appSettings;
public AppSettings()
{
_appSettings = WebConfigurationManager.AppSettings;
}

public string GetSetting(string key)
{
return _appSettings.AllKeys.Any(k => k == key)
? _appSettings[key]
: "";
}

public void SetSetting(string key, string value)
{
if (_appSettings.AllKeys.Any(k => k == key))
_appSettings[key] = value; // Update
else
_appSettings.Add(key, value); // Add
}
}
}