Search code examples
ruby-on-railsasp.net-mvcdatabaseviewdata

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


Solution

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