美文网首页
.net-mvc项目插件化编程

.net-mvc项目插件化编程

作者: 浅谈码生活 | 来源:发表于2020-12-09 10:59 被阅读0次

在了解插件化编程之前,要先想清楚MVC项目的运行原理及CLR查找和加载程序集的方式
1).MVC项目的运行原理
2).CLR查找和加载程序集的方式

通过上述文章,可以了解到,程序运行初CRL会将所有的可以加载的程序集进行加载,之后将扫描程序集内所有的Controller并添加到RouteTable中,到此我们的插件程序集内的控制器将可以被实例化, 但还无法找到我们控制器对应的视图

1.先将框架的插件资源包拆解,分别复制到“2”中的程序集目录及“3”中的Razor视图页目录:

//作用:项目启动最先执行当前函数的“Initialize”方法
[assembly: PreApplicationStartMethod(typeof(BKYL.Web.Main.PreApplicationInit), "Initialize")]
namespace BKYL.Web.Main
{
public class PreApplicationInit
{
    static PreApplicationInit()
    {
        PluginFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/Plugins/Plugins"));
        ShadowCopyFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/Plugins/PluginsDlls"));
        ViewsFolder = HostingEnvironment.MapPath("~/Plugins/PluginsViews");
        ContentFolder = HostingEnvironment.MapPath("~/Content");
    }
    /// <summary>
    /// 插件所在目录信息
    /// </summary>
    private static readonly DirectoryInfo PluginFolder;
    /// <summary>
    /// 程序运行时指定的dll目录
    /// </summary>
    private static readonly DirectoryInfo ShadowCopyFolder;
    /// <summary>
    /// 视图所在文件夹
    /// </summary>
    private static readonly string ViewsFolder;
    /// <summary>
    /// content
    /// </summary>
    private static readonly string ContentFolder;
   
    public static void Initialize()
    {
        try
        {
            Directory.CreateDirectory(ShadowCopyFolder.FullName);
            //清空插件dll运行目录中的文件
            //foreach (var f in ShadowCopyFolder.GetFiles("*.dll", SearchOption.AllDirectories))
            //{
            //    f.Delete();
            //}
            foreach (var item in PluginFolder.GetDirectories())
            {
                foreach (var item1 in item.GetDirectories())
                {
                    CopyDirectory(item1.FullName, Path.Combine(ShadowCopyFolder.FullName, item1.Name), true);
                }
            }

            foreach (var plug in PluginFolder.GetFiles("*.dll", SearchOption.AllDirectories).Where(i => i.Directory.Parent.Name == "Plugins"))
            {
                var path = Path.Combine(ShadowCopyFolder.FullName, plug.Name);
                if (File.Exists(path))
                {
                    var time = File.GetLastWriteTime(path);
                    if (plug.LastWriteTime != time)
                    {
                        File.Copy(plug.FullName, path, true);
                    }
                }
                else
                {
                    File.Copy(plug.FullName, path, true);
                }
            }

            var assemblys = ShadowCopyFolder.GetFiles("*.dll", SearchOption.AllDirectories).Select(x => AssemblyName.GetAssemblyName(x.FullName)).Select(x => Assembly.Load(x.FullName));
            foreach (var a in assemblys)
            {
                var dllName = a.ManifestModule.Name.Replace(".dll", "");
                if (PluginRegistryCache.PluginRegistryDic == null)
                {
                    PluginRegistryCache.Load();
                }
                if (!PluginRegistryCache.PluginRegistryDic.ContainsKey(dllName.ToLower()))
                {
                    continue;
                }
                var startUpClassName = PluginRegistryCache.PluginRegistryDic[dllName.ToLower()];
                var fileNames = a.GetManifestResourceNames();
                //  var ms= a.GetModules();
                string pluginsName = ViewsFolder + "/" + dllName;
                string contentName = ContentFolder + "/" + dllName;
                //创建plugin文件夹
                if (!Directory.Exists(pluginsName))
                {
                    Directory.CreateDirectory(pluginsName);
                }
                //创建content文件夹
                if (!Directory.Exists(contentName))
                {
                    Directory.CreateDirectory(contentName);
                }

                for (int i = 0; i < fileNames.Length; i++)
                {
                    var fileStream = a.GetManifestResourceStream(fileNames[i]);
                    if (fileNames[i].Contains(".css") || fileNames[i].Contains(".js") ||
                        fileNames[i].Contains(".png") || fileNames[i].Contains(".jpg") ||
                        fileNames[i].Contains(".gif"))
                    {
                        var f = fileNames[i].Replace(dllName + ".", "");
                        FileCopy(f, contentName, fileStream);
                    }
                    if (fileNames[i].Contains(".cshtml"))
                    {
                        var f = fileNames[i].Replace(dllName + ".", "");
                        FileCopy(f, pluginsName, fileStream);
                    }
                }
                //加载dll启动方法
                if (!string.IsNullOrWhiteSpace(startUpClassName))
                {
                    IStartUp start = (IStartUp)a.CreateInstance(dllName + "." + startUpClassName);
                    if (start != null)
                    {
                        start.Load();
                    }
                }

                BuildManager.AddReferencedAssembly(a);
            }
        }
        catch (Exception ex)
        {
            Log.WriteLine("插件程序文件复制出现异常," + ex.Message);
            throw;
        }
    }
    //拷贝文件
    private static bool CopyDirectory(string SourcePath, string DestinationPath, bool overwriteexisting)
    {
        bool ret = false;
        try
        {
            SourcePath = SourcePath.EndsWith(@"\") ? SourcePath : SourcePath + @"\";
            DestinationPath = DestinationPath.EndsWith(@"\") ? DestinationPath : DestinationPath + @"\";

            if (Directory.Exists(SourcePath))
            {
                if (Directory.Exists(DestinationPath) == false)
                    Directory.CreateDirectory(DestinationPath);

                foreach (string fls in Directory.GetFiles(SourcePath))
                {
                    FileInfo flinfo = new FileInfo(fls);
                    flinfo.CopyTo(DestinationPath + flinfo.Name, overwriteexisting);
                }
                foreach (string drs in Directory.GetDirectories(SourcePath))
                {
                    DirectoryInfo drinfo = new DirectoryInfo(drs);
                    if (CopyDirectory(drs, DestinationPath + drinfo.Name, overwriteexisting) == false)
                        ret = false;
                }
            }
            ret = true;
        }
        catch (Exception ex)
        {
            ret = false;
        }
        return ret;
    }
    private static void FileCopy(string f, string contentName, Stream fileStream)
    {
        var file = f.Split('.');
        for (int j = 1; j < file.Length - 2; j++)
        {
            contentName = contentName + "/" + file[j];
            if (!Directory.Exists(contentName))
            {
                Directory.CreateDirectory(contentName);
            }
        }

        var vPath = contentName + "/" + file[file.Length - 2] + "." + file[file.Length - 1];
        if (File.Exists(vPath))
        {
            File.Delete(vPath);
        }
        FileStream fs = new FileStream(vPath, FileMode.OpenOrCreate);
        fileStream.Position = 0;
        fileStream.CopyTo(fs);
        fileStream.Close();
        fs.Close();
    }
}

 }

2.配置插件Dll文件位置:

<!--程序集绑定标签-->
 <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="Plugins/PluginsDlls/" />
</assemblyBinding >

3.自定义Razor视图引擎:

public class CustomRazor : RazorViewEngine
{
    /// <summary>
    /// 定义视图页所在地址。
    /// </summary>
    private string[] _viewLocationFormats = new[]
    {
        // "~/Views/Parts/{0}.cshtml",
        "~/Plugins/PluginsViews/{pluginFolder}/{1}/{0}.cshtml",
        "~/Plugins/PluginsViews/{pluginFolder}/Shared/{0}.cshtml",
        "~/Views/{1}/{0}.cshtml",
        "~/Views/Shared/{0}.cshtml",
    };
    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
        try
        {
            Log.WriteLine("开始加载视图", "info");
            string ns = controllerContext.Controller.GetType().Namespace;
            string controller = controllerContext.Controller.GetType().Name.Replace("Controller", "");
            //说明是插件中的控制器,View目录需要单独处理
            var nameplace = ns.ToLower().Replace(".controllers", "");
            Log.WriteLine(nameplace + "插件视图","info");
            if (PluginRegistryCache.PluginRegistryDic.ContainsKey(nameplace))
            {
                Log.WriteLine(nameplace + "插件视图","info");
                var pluginsFolder = ns.Replace(".Controllers", "");
                ViewLocationFormats = ReplacePlaceholder(pluginsFolder);
            }
        }
        catch (Exception e)
        {
            Log.WriteDebug(e.Message + "插件视图");
        }
        return base.FindView(controllerContext, viewName, masterName, useCache);
    }
    /// <summary>
    /// 替换pluginFolder占位符
    /// </summary>
    /// <param name="folderName"></param>
    private string[] ReplacePlaceholder(string folderName)
    {
        string[] tempArray = new string[_viewLocationFormats.Length];
        if (_viewLocationFormats != null)
        {
            for (int i = 0; i < _viewLocationFormats.Length; i++)
            {
                tempArray[i] = _viewLocationFormats[i].Replace("{pluginFolder}", folderName);
            }
        }
        return tempArray;
    }
}

4.在“Global.asax”文件中替换视图引擎:

//加载自定义视图引擎
ViewEngines.Engines.Clear();
var myEngine = new CustomRazor();
ViewEngines.Engines.Add(myEngine);

相关文章

网友评论

      本文标题:.net-mvc项目插件化编程

      本文链接:https://www.haomeiwen.com/subject/buzcgktx.html