2012-06-07 122 views
1

我正在使用ASP.NET MVC 4,并且由于我想在跨站点导航栏中预加载一些数据,所以我在MasterController中保存了一些数据。ASP.NET MVC持久化数据

abstract class MasterController : Controller 
{ 
    FakeObject MyData { get; set; } 

    if (this.MyData == null) 
    { 
     this.MyData = // do something crazy and load lots of data 
    } 
} 

每个控制器从MasterController

class HomeController : MasterController 
{ 
    ActionResults Index() 
    { 
     return View(); 
    } 
} 

的问题是,每次有一个回继承,迈德特被覆盖。 我试图找到一种方法来存储这些数据,并在不使用SessionState的情况下在PostBack之间检索它。这可以做到吗?也许我对MasterController的使用不正确。

我尝试以下,但它不工作:(

TempData.Add("mydata", MyData); 
TempData.Keep("mydata"); 

回答

1

我不知道您的if(String.IsNullOrEmpty...正在使用(我想你错过了一个包含成员;这不是有效的代码。

不过,我想你可能要考虑依赖注入和松散耦合,而不是一个控制器硬编码的业务逻辑这里有两个建议

选项1:。依赖注入和TempDa TA

public interface IFakeObjectFactory 
{ 
     FakeObject Create(); 
} 

public class FakeObjectFactory : IFakeObjectFactory 
{ 
     public FakeObject Create() 
     { 
      // create FakeObject 
     } 
} 

然后你的控制器看起来会像这样:

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. 
    } 
} 

现在,你可以使用控制容器的反转来创建控制器和你注入依赖(一些流行的IoC是Ninject和Autofac)。如果您觉得自己已经做好了准备,您可以在EnsureMyData方法中始终使用硬编码创建工厂实例,然后摆脱HomeControllerMasterController中的构造函数参数。

使用工厂界面和依赖项注入的好处是您可以独立于控制器创建,测试和维护工厂。如果需要非常容易,您也可以在将来更换实施方案。

选项2:使用一个静态只读字段

另一种选择,如果MyData是不变的,就是你可以把它的MasterController静态成员,而不是使用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. 
    } 
} 

这种方法我不推荐,除非逻辑是死的简单,或者你根本不关心和想要的东西快速和肮脏。测试单例和静态方法是一个令人头痛的问题。

+0

对不起,我更新了代码。之前使用过一个字符串,并决定将其称为FakeObject,但忘记更新虚拟代码。 –

+0

同意,国际奥委会会好得多,但在这种情况下,这是一个小测试应用程序,投入国际奥委会是矫枉过正。我应该在我的问题中澄清。所以我的主要目标是快速完成,在这种情况下,硬编码完全可以。无论如何,关于国际奥委会你绝对正确。 –

+0

当然,正如我所说的,你可以消除两个控制器上的'IFakeObjectFactory'参数和'MasterController'上的属性,并且只需在'EnsureMyData'内部以硬编码的方式创建工厂。 – HackedByChinese

1

如果这基本上是静态数据,则可以使用内置缓存。

abstract class MasterController : Controller 
{ 
    public MasterController() { if (Cache["Foo"] == null) Cache["Foo"] = Something; } 
} 

class HomeController : MasterController 
{ 
    ActionResults Index() 
    { 
     return View(Cache["Foo"]); 
    } 
} 
+0

尽管在这种情况下,使用缓存比使用Session更好,因为我不关心每个用户会话,但所有用户都存在相同的数据。我希望能够使用TempData,ViewBag或ViewData来完成这个任务,并希望有一种方法。如果有人有更优雅的解决方案,我会继续讨论这个问题。如果不是,我会回来标记答案。 –

+2

@Tomaszewski - 仅供参考,TempData将会话用于存储,并且不可靠,因为一旦您访问它,它就会被删除。因此,如果用户刷新页面,它就消失了。至于ViewBag/ViewData,这些都是可能的,但它们是特定于操作方法的,所以它们本质上不是全球性的。 –

+0

是的,我同意。就像我上面所说的,我尝试使用包含.Keep()方法的TempData,但无济于事。 –