Reputation: 4479
I'm using ASP.NET MVC 4 and have a situation where Im saving some data in a MasterController because I want to pre-load some data in a cross-site nav bar.
abstract class MasterController : Controller
{
FakeObject MyData { get; set; }
if (this.MyData == null)
{
this.MyData = // do something crazy and load lots of data
}
}
every controller inherits from the MasterController
class HomeController : MasterController
{
ActionResults Index()
{
return View();
}
}
The problem is that everytime there is a post back, MyData gets overwritten. I'm trying to find a way to store this data and retrieve it between PostBacks without using SessionState. Could this be done? Perhaps my use of the MasterController is incorrect.
I tried the following, but it doesn't work :(
TempData.Add("mydata", MyData);
TempData.Keep("mydata");
Upvotes: 1
Views: 1315
Reputation: 93484
If this is basically static data, you can use the builtin cache.
abstract class MasterController : Controller
{
public MasterController() { if (Cache["Foo"] == null) Cache["Foo"] = Something; }
}
class HomeController : MasterController
{
ActionResults Index()
{
return View(Cache["Foo"]);
}
}
Upvotes: 1
Reputation: 42495
I'm not sure where your if(String.IsNullOrEmpty...
is being used (I think you're missing a containing member; that's not valid code.
However, I think you may want to consider dependency injection and loose coupling, rather than hardcoding business logic in a controller. Here are two suggestions.
Option 1: Dependency Injection and TempData
public interface IFakeObjectFactory
{
FakeObject Create();
}
public class FakeObjectFactory : IFakeObjectFactory
{
public FakeObject Create()
{
// create FakeObject
}
}
Then your controllers would look more like this:
public abstract class MasterController : Controller
{
protected IFakeObjectFactory FakeObjectFactory { get; private set; }
private FakeObject _myData;
protected FakeObject EnsureMyData()
{
if (_myData != null) return _myData;
_myData = TempData["myData"] as FakeObject ?? FakeObjectFactory.Create();
TempData["myData"] = _myData;
}
protected MasterController(IFakeObjectFactory fakeDataFactory)
{
FakeDataFactory = fakeDataFactory;
}
}
public class HomeController : MasterController
{
public HomeController(IFakeObjectFactory fakeObjectFactory)
: base(fakeObjectFactory)
{ }
ActionResults Index()
{
ViewBag.MyData = EnsureMyData();
return View(); // you could also use MyData as the view model, rather than using ViewBag above. not sure what you need from here.
}
}
Now, you can use an Inversion of Control container to create your controller and inject dependencies for you (some popular IoC are Ninject and Autofac). If you don't feel you are ready for that, you can always hardcode creating an instance of the factory in your EnsureMyData
method, and get rid of the constructor parameters in HomeController
and MasterController
.
The benefit of using a factory interface and dependency injection is that you can create, test, and maintain the factory separately from your controller. You can also swap out implementations in the future if need be very easily.
Option 2: Use a static readonly field
Another option, if MyData
is constant, is that you can make it a static member of MasterController
, rather than using TempData
.
public abstract MasterController : Controller
{
public static readonly FakeData MyData;
static MasterController()
{
// Initialize MyData
}
}
public HomeController : MasterController
{
public ActionResult Index()
{
ViewBag.MyData = MyData;
View(); // you could also use MyData as the view model, rather than using ViewBag above. not sure what you need from here.
}
}
This approach I do not recommend unless the logic is dead simple or you just don't care and want something quick and dirty. Testing singletons and static methods is a pain in the butt.
Upvotes: 1