How do I specify different Layouts in the ASP.NET Core MVC

纵然是瞬间 提交于 2019-12-20 10:28:05

问题


I would like to have 2 separate Layouts in my application. Let say one is for the Public section of the website and the other is empty for some reasons we need.

Before Core I could do this to define a filter:

public class LayoutInjecterAttribute : ActionFilterAttribute
{
    private readonly string _masterName;
    public LayoutInjecterAttribute(string masterName)
    {
        _masterName = masterName;
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);
        var result = filterContext.Result as ViewResult;
        if (result != null)
        {
            result.MasterName = _masterName;
        }
    }

}

Now the ViewResult do not have the MasterName property. Is it possible to do now, and not to use in the View the layout definition.


回答1:


You can still do something very similar to your original approach, using ViewData to pass around the layout name (Although I would create it as a Result Filter):

public class ViewLayoutAttribute : ResultFilterAttribute
{
    private string layout;
    public ViewLayoutAttribute(string layout)
    {
        this.layout = layout;
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        var viewResult = context.Result as ViewResult;
        if (viewResult != null)
        {
            viewResult.ViewData["Layout"] = this.layout;
        }
    }        
}

Then in the _ViewStart.cshtml file:

@{
    Layout = (string)ViewData["Layout"] ?? "_Layout";
}

Finally, assuming you create a new layout like Views/Shared/_CleanLayout.cshtml, you can use that attribute on any controller or action:

[ViewLayout("_CleanLayout")]
public IActionResult About()
{
    //...
}



回答2:


This is how I am using multiple layouts in my ASP.NET core MVC application.

You can try like this-

In _ViewStart.cshtml specify default _Layout like this-

@{
    Layout = "_Layout";
}

If you want to set page specific layout then in that page.cshtml, you can assign other view like this-

@{
    Layout = "~/Views/Shared/_Layout_2.cshtml";
    ViewData["Title"] = "Page Title";
}

See if this helps.




回答3:


If you want to have a different layout based on some condition, you could use this code in the _ViewStart.cshtml file:

@{
    if (some condition)
    {
        Layout = "_Layout1";
    }
    else if (some other condition)
    {
        Layout = "_Layout2";
    }
    etc.
}

I use this in one of my projects. In my case the condition is User.IsInRole("admin") and my _ViewStart.cshtml file is as follows:

@{
    if (User.IsInRole("admin"))
    {
        Layout = "_AdminLayout";
    }
    else
    {
        Layout = "_Layout";
    }
}

Since there are only two roles in my project, which result in only one condition, this workaround is not too bad in my case. I hope someone with in a similar situation will find this useful :)




回答4:


In ASP.NET Core 2.0, I was inspired by the answer of @Daniel J.G.

I made a ViewLayoutAttribute:

[AttributeUsage(AttributeTargets.Class)]
public class ViewLayoutAttribute : Attribute
{
    public ViewLayoutAttribute(string layoutName)
    {
        this.LayoutName = layoutName;
    }

    public string LayoutName { get; }
}

Exemple of a controller class:

[ViewLayout("_Layout2")]
public class MyController : Controller 
{
// Code
}

And I created an extension to get this very attribute from the ViewContext:

  public static class RazorExtensions
  {
        /// <summary>
        /// Gets the <see cref="ViewLayoutAttribute"/> from the current calling controller of the
        /// <see cref="ViewContext"/>.
        /// </summary>
        public static ViewLayoutAttribute GetLayoutAttribute(this ViewContext viewContext)
        {
            // See if Razor Page...
            if (viewContext.ActionDescriptor is CompiledPageActionDescriptor actionDescriptor)
            {
                // We want the attribute no matter what.
                return Attribute.GetCustomAttribute(actionDescriptor.ModelTypeInfo, typeof(ViewLayoutAttribute)) as ViewLayoutAttribute;
            }

            // See if MVC Controller...

            // Property ControllerTypeInfo can be seen on runtime.
            var controllerType = (Type)viewContext.ActionDescriptor
                .GetType()
                .GetProperty("ControllerTypeInfo")?
                .GetValue(viewContext.ActionDescriptor);

            if (controllerType != null && controllerType.IsSubclassOf(typeof(Microsoft.AspNetCore.Mvc.Controller)))
            {
                return Attribute.GetCustomAttribute(controllerType, typeof(ViewLayoutAttribute)) as ViewLayoutAttribute;
            }

            // Nothing found.
            return null;
        }
    }

And in _ViewStart.cshtml:

@using MyApp.Extensions

@{
    Layout = ViewContext.GetLayoutAttribute()?.LayoutName ?? "_Layout";
}



回答5:


You can use IViewLocationExpander interface to render view as you want. Please refer this link Working with IViewLocationExpander in mvc for more details

Regards,

Rohit



来源:https://stackoverflow.com/questions/39870298/how-do-i-specify-different-layouts-in-the-asp-net-core-mvc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!