动态更改MVC可插入模式中的视图布局

时间:2017-01-15 08:46:29

标签: asp.net-mvc razor plugins asp.net-mvc-5 asp.net-mvc-areas

关于情景的一些解释但请耐心等待!!!

我已经实现了一个可插入的MVC应用程序,它可以注册主项目的Areas文件夹中存在的插件。

每个插件都有一些视图和控制器 我想为插件中的视图设置布局(插件对主应用程序中的主布局一无所知)

所以我调查了一些渲染视图的方法,我想要渲染...

在主应用程序中,我PluginBootstrapper会将区域文件夹中的所有插件注册为:

public class PluginBootstrapper
{
    public static readonly List<Assembly> PluginAssemblies = new List<Assembly>();

    public static void Init()
    {
        var fullPluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Areas");

        foreach (var file in Directory.EnumerateFiles(fullPluginPath, "*Plugin*.dll", SearchOption.AllDirectories))
            PluginAssemblies.Add(Assembly.LoadFile(file)); 
        PluginAssemblies.ForEach(BuildManager.AddReferencedAssembly); 
        // Add assembly handler for strongly-typed view models
        AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
    } 
    private static Assembly AssemblyResolve(object sender, ResolveEventArgs resolveArgs)
    {
        var currentAssemblies = AppDomain.CurrentDomain.GetAssemblies();
        // Check we don't already have the assembly loaded
        foreach (var assembly in currentAssemblies)
        {
            if (assembly.FullName == resolveArgs.Name || assembly.GetName().Name == resolveArgs.Name)
            {
                return assembly;
            }
        }

        return null;
    }
}

致电Init()并在assembly档案中注册插件:

    [assembly: PreApplicationStartMethod(
  typeof(PluginBootstrapper), "Init")]

另一方面,每个插件都可以在单独的解决方案中开发,因此开发的插件有自己的AreaRegistration实现,例如我有其中一个:

 public class SettingPluginAreaRegistration : AreaRegistration
{
    public override string AreaName
    {
        get { return "SettingPlugin"; }
    } 

    public override void RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute(
            "SettingPlugin",
            "SettingPlugin/{controller}/{action}/{id}",
            new { action = "Index", id = UrlParameter.Optional }
            );
    }
}

我知道如何在View中设置布局,但是当所有视图都在同一个项目中并且Views知道主要布局在哪里时,这是正确的方法,但是在插件视图中必须知道主要布局在主应用程序中的位置?

例如在插件视图中:

  @{
    ViewBag.Title = "Plugin View Title";
    Layout = "the address of main layout in main application";
}

正如this link提到的另一种方式是_ViewStart,但这也不是正确的方法,因为每个插件都拥有它自己的_ViewStart

这样做有一个很好的模式,比如实施WebViewPage来覆盖Layout

   public abstract class SitePage<T> : System.Web.Mvc.WebViewPage<T>
{
    public override string Layout
    {
        get
        {
            return base.Layout;
        }

        set
        {
            base.Layout = value;
        }
    }
}

或创建一个界面来设置Layout并强制插件视图实现该界面,并通过Init()PluginBootstrapper或其他内容中的反射来更改布局?

UPDATE1:

WebPageBase方法中注册插件时是否可以加载所有Init()类型,并通过反射为每个类型设置Layout

UPDATE2:

糟糕的方式

 public class BaseController : Controller
{
    private string _masterName;
    public string MasterLayout
    {
        get
        {
            return _masterName;
        }
        set
        {
            _masterName = value;
        }
    }
}
控制器

    public class SettingController : BaseController
    {
        public ActionResult Index()
        { 
            var myView = View();
            myView.MasterName = MasterLayout;
            return myView;
        }
}

Init() PluginBootstrapper中的这样的内容:

var fullPluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Areas");

        foreach (var file in Directory.EnumerateFiles(fullPluginPath, "*Plugin*.dll", SearchOption.AllDirectories))
            PluginAssemblies.Add(Assembly.LoadFile(file));  
        foreach (Assembly plugin in PluginAssemblies)
        {
            BuildManager.AddReferencedAssembly(plugin);
            var controllers = plugin.DefinedTypes.Where(x => x.BaseType.Name == "BaseController");
            foreach (Type t in controllers)
            {
                // t.InvokeMember("MasterLayout", BindingFlags.SetProperty);
                PropertyInfo propertyInfo = t.GetProperty("MasterLayout"); 
                if (propertyInfo != null)
                    propertyInfo.SetValue(t, /*Convert.ChangeType(*/"~/Views/Shared/_Wrapper.cshtml"/*, propertyInfo.PropertyType)*/, null);
            }
        }

或硬代码MasterLayout始终返回特定的布局地址。

我认为UPDATE2不是正确的方式......

提前感谢。

0 个答案:

没有答案