1

First look at the sample controller code. There you'll find two statements which are repetitive-

public class DashboardController : Controller
{
    //the following line is repetitive for every controller.
    String ConnectionString = WebConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
    public ActionResult Index()
    {
        try
        {
            //codes
        }
        catch (Exception Ex)
        {
            //The following line is repetitive for every action method.
            var path = HttpContext.Server.MapPath("~/App_Data");
            ExceptionLog.Create(Ex, path);
        }
        return View("AdminDashboard");
    }
}

I would like to avoid such repetition. Is there any way to do it which can work for the entire application as global variable?

4
  • 4
    Create a BaseController and inherit all your controllers from it Commented Oct 15, 2015 at 11:37
  • @StephenMuecke I was going to suggest that Commented Oct 15, 2015 at 11:38
  • WebConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString; as this connection string itself is global in your app lifecycle, why dont you directly use it? Commented Oct 15, 2015 at 11:40
  • Thanks Stephen Mueke. Would you please provide a sample snippet so that I can grab the concept in detail? Specially with the "App_Data" path. Commented Oct 15, 2015 at 11:40

4 Answers 4

4

If it were me, and there were frequent configuration options I needed to access, I would create/expose some kind of IAppConfiguration which I could drop in to my controllers (using dependency injection). Something like:

public interface IAppConfguration
{
    String MyConnectionString { get; }
    String ServerPath { get; }
}
public class AppConfiguration : IAppConfiguration
{
    private readonly HttpContext context;
    public AppConfiguration(HttpContext context)
    {
        this.context = context;
    }

    public String MyConnectionString
    {
        get { return COnfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
    }
    public String ServerPath
    {
        get { return context.Server.MapPath("~/"); }
    }
}

Then you can extend it for different circumstances, sub-sites/areas, etc. Then, bring it in via the controller's constructor:

public class MyController : Controller
{
    private readonly IAppConfiguration config;
    public MyController()
        : this(new AppConfiguration(HttpContext.Current))
    {
    }
    public MyController(IAppConfiguration config)
    {
        this.config = config;
    }

    // reference config.ServerPath or config.MyConnectionString;
}

Taking it a step further, you could add a factory atop this, bring that in as a reference instead, and allow you to get configuration settings for other environments. e.g.

IAppConfiguration config = configFactory.GetConfig(/* environment */);

The thing I like about this approach is allows me to substitute out settings for local [unit/integration] testing. Using base controllers/static classes would make it very difficult to substitute out these values at a later time.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks Brad. Can I use this technique in a base controller approach?
@s.k.paul - combine the approach i've given with this example and you're on your way.
@s.k.paul" You can, but base controllers become more difficult to emulate in tests (if that's of concern to you). I avoid controller inheritence because it's (typically) a pain to be consistent. However, you could create a static extension (e.g. public static void LoadException(this Controller controller, Exception ex) in LogExceptions class.) But I'd keep things broken out by module and bring them in.
@Brad, : this(new AppConfiguration(HttpContext.Current)) gives error - object reference is required. Any help?
If you use DI, you can either use that as your config, or throw that into a static method and pass that method in c'tor. Just used that to show an example of building the class.
3

Here is an example using a base controller approach:

public abstract class BaseController : Controller
{
    protected string ConnectionString = WebConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;

    protected void LogException(Exception ex)
    {
        var path = HttpContext.Server.MapPath("~/App_Data");
        ExceptionLog.Create(Ex, path);
    }    
}

public class DashboardController : BaseController
{
    public ActionResult Index()
    {
        try
        {
            string conn = base.ConnectionString;
            //codes
        }
        catch (Exception ex)
        {
            base.LogException(ex);
        }
        return View("AdminDashboard");
    }
}

3 Comments

There you have redundant repeatable try-catch block that do absolutely equal work in every action of every controller.
It's just one approach - one benefit is that a view can be returned within the try and if an exception is raised, once the catch block has exited, a different view can be returned
@Ric Thanks. I think this is the simplest way out.
1

To avoid exception catching you can log it in OnError event handler in global.asax.cs:

protected void Application_Error(object sender, EventArgs e)
{
    HttpContext ctx = HttpContext.Current;

    Exception ex = ctx.Server.GetLastError();

    var path = HttpContext.Server.MapPath("~/App_Data");
    ExceptionLog.Create(Ex, path);
}

you can use connection string name "MyConnectionString" instead of WebConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString when pass it to dbcontext or ADO Connection.

But more rightful way is to inject (with Dependency Injection) in controller class that will be responsible for work with database instead of creating it in controller and passing there connection string.

Comments

0

You can inherit controller and then use it for all other controllers, have a look at similar question How can I inherit an ASP.NET MVC controller and change only the view?.

But this will be only accessible in controllers, you can also create a class with static method or property returning back the connection string. This can be used in any path of code where you have access to the class.

2 Comments

And the bad design is? Having a central class returning the value? Thats was example by Brad is doing in principle.
I would not create object everytime for given case, though will make it configurable if needed. Anyways OP got his answer happy for him :) . Thanks for your response.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.