Accessing a database object (and other important data) in the View
I know it's a bad practice to use database in the view. However, I'm also passing the User
object and I wonder how I can make it easy to use.
I love the way it works in Ruby On Rails. You just create an @instance_variable
in before_filter
and call it from the controllers and from the views.
You can't do this in ASP.NET MVC though. So I created a class with all the data I need to pass to the view (DataContext and User):
public class XData
{
public DBDataContext DB { get; set; }
public User User { get; set;开发者_开发百科 }
}
In controller's Initialize method I get all the data:
public XData X;
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
X = new XData();
X.DB = ...;
X.User = ....;
}
Works great: I can get the database object from the view like this:
<%= Model.X.DB.Users.First().Name %>
In order to pass the data to the view, I have to do the following:
public ActionResult Foo()
{
return View(new FooModel
{
X = X,
HelloMessage = "Hello world!"
});
}
The thing I don't like here is that I always have to write the X = X
thing. How can I initialize that automatically?
Thanks
I've seen a similar problem where a lot of controllers return a similar model with only a few customizations. In this case, create an abstract base model that other models derive from, and a function that returns the particular model you need with the base X = X
and so forth already set.
For example, consider this:
public abstract class MyBaseModel
{
public User User { get; set; }
}
public class FooModel : MyBaseModel
{
public string FooMessage { get; set; }
}
public class BarModel : MyBaseModel
{
public string BarMessage { get; set; }
}
public class MyController : Controller
{
public ActionResult Foo()
{
var model = this.GetModel<FooModel>();
// Set the properties on FooModel.
model.FooMessage = "Hello world!"
return View(model);
}
public ActionResult Bar()
{
var model = this.GetModel<BarModel>();
// Set the properties on BarModel.
model.BarMessage = "Hello world 2!"
return View(model);
}
protected T GetModel<T>() where T : MyBaseModel, new()
{
T model = new T();
// Set the properties on MyBaseModel.
model.User = ...;
return model;
}
}
If you want to share MyBaseModel
and GetModel
among many controllers, extract it out to a ModelProvider
or something similar that is supplied to each controller, ideally through dependency injection.
You could place X in ViewData and write an HtmlHelper extension method to access X or override the View method of the controller and add a little reflection logic that maps every instance property of the controller to properties with matching names of your model (I guess Automapper could help here...)
I think you'll need to start by making your view strongly typed:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Namespace.XData>" %>
and in your controller:
public ActionResult Foo()
{
var X = new XData();
X.User = ....;
X.SomeProperty = ...;
X.Message = "Hello world!";
return View(X);
}
which allows you to access the object in your view like so:
<%: Model.User.UserName %>
<%: Model.Message %>
精彩评论