views:

591

answers:

3

Hello. I have a base controller abstract class, which my other controllers inherit. This class needs to load a local xml file in order to create some buttons for the master page. Given that the ControllerContext is null at this stage, what is the best practice for loading the file? (When running on the webserver, I get the following error: Could not find a part of the path 'c:\windows\system32\inetsrv\Content\Xml\Buttons.xml'.)

Current code is

using System.Web.Mvc;
using Site1.Models;

namespace Site1.Controllers
{

    [SkyArts.Models.Master]
    public abstract class BaseController : Controller
    {
        public BaseController()
        {
            XDocument buttonsXmlDoc = XDocument.Load("Content/Xml/Buttons.xml");
        }
    }
}

The document is actually loaded from a Model class, but I've left this out for brevity.

As a side issue, would you put xml files in Content or in App_Data?

+1  A: 

Alternative to overriding Initialize, but I think that's the best method.

I use Server.MapPath to resolve the path to the document root. I would also use App_Data so that the raw file can't be downloaded.

var buttonsXmlDoc = XDocument.Load( HttpContext
                                      .Current
                                      .Server
                                      .MapPath( "~/App_Data/Buttons.xml" ) );

EDIT:based on your comment, you could reference the Server object from HttpContext.Current or move the loading of the XML to the Initialize method as others have noted. I recommend the latter, but I'll update my answer with the former as an alternative.

tvanfosson
Server object is null, presumably because this is in the constructor of the base controller.
darasd
+2  A: 

Don't call it in the constructor. Override the Initialize method. ControllerContext will be non-null there. Or use lazy instantiation.

Craig Stuntz
+2  A: 

I think the solution to your problem is a combination of what people have mentioned here. Override Initialize and load your XML document there. The Server property should be valid at that point. Also, use Server.MapPath to retrieve the resource from within your web site directory hierarchy.

using System.Web.Mvc;
using Site1.Models;

namespace Site1.Controllers
{

    [SkyArts.Models.Master]
    public abstract class BaseController : Controller
    {
        protected override void Initialize(RequestContext rc)
        {
            base.Initialize(rc);

            XDocument buttonsXmlDoc = XDocument.Load(
                Server.MapPath("~/Content/Xml/Buttons.xml"));
        }
    }
}

Additionally, note that when calling Server.MapPath, use the application rooted path to the resource (i.e. begin the path with the tilde character "~") -- this is the reason you're seeing the error Could not find a part of the path 'c:\windows\system32\inetsrv\Content\Xml\Buttons.xml'.

When you don't use Server.MapPath, any relative file system paths are relative to the executing process, which in this case would be IIS. Calling Server.MapPath will translate the resource you've specified as relative to your web site's virtual directory hierarchy to a physical file system path.

As for your side issue regarding the location of the XML file, I would recommend that App_Data is used since files stored in that folder are not served when requested.

Peter Meyer