Peter Kellner
Peter Kellner

Reputation: 15498

How To Use an Attribute (maybe) to point at Layout Page I want

I've got an ASP.NET MVC4 project with standard controllers and views. I have to different master pages I use, depending on a global variable I can reach out and get based on the Request.Url.Host. I've written the code below but it is getting kind of bulky to put in every controller. I've gotten it pretty short but was hoping for a suggestion to make it much cleaner.

    private ActionResult IndexBase(string year)
    {
        var data = null; // real data here for model
        var localConfig = LocalConfig.GetLocalValues(Request.Url.Host, null, year);
        ViewResult view = localConfig.EventType == "svcc"
                ? View("Index", "~/Views/Shared/_Layout.cshtml", data)
                : View("Index", "~/Views/Shared/_LayoutConf.cshtml", data);

        return view;
    }

Upvotes: 1

Views: 48

Answers (1)

mfanto
mfanto

Reputation: 14418

I don't know if this solution works for you, but I would solve it with ViewModel's and a common base controller.

One of the nice things with Layouts is you can pass a base ViewModel with the properties common to all your pages (the users name, for example). In your case, you could store the path to the Layout.

First, the base class every ViewModel derives from:

public class MasterViewModel
{
    public string Name { get; set; }
    public string Layout { get; set; }
}

I prefer to use a 1:1 mapping of ViewModels to Views. That is, each action gets it's own ViewModel. For example: HomeIndexViewModel for /Home/Index, ProfileEditViewModel for /Profile/Edit, etc.

public class HomeIndexViewModel : MasterViewModel
{
    // properties you need for /Home/Index
}

To simplify creating the ViewModels, I add a generic method on a base controller that handles setting all these the common properties:

public class BaseController : Controller
{
    protected T CreateViewModel<T>() where T : MasterViewModel, new()
    {
        User user = db.GetUser(User.Identity.Name);

        var localConfig = LocalConfig.GetLocalValues(Request.Url.Host, null, year);

        return new T() 
        { 
            Name = user.Name,
            Layout = localConfig.EventType == "svcc" ? "~/Views/Shared/_Layout.cshtml"
                                                     : "~/Views/Shared/_LayoutConf.cshtml"
        }
    }
}

And finally, just use CreateViewModel() in each of your Actions and things should work:

public class HomeController : BaseController
{
    public ActionResult Index()
    {
         HomeIndexViewModel viewModel = CreateViewModel<HomeIndexViewModel>();

         return View(viewModel);
    }
}

Inside the Views, you can just set

@model HomeIndexViewModel

@{
    Layout = Model.Layout;
}

There's no need to duplicate the path anywhere, and changing the logic on which Layout to show requires you only change it in one place.

Upvotes: 1

Related Questions