Search code examples
c#htmlasp.net-mvcmefrazorengine

ASP MVC Cannot find Views from imported MEF module


I am trying to access a View from within a compiled and imported MEF module as a .dll in a self created Modules directory in my project.

After composing the MEF dlls I try to navigate to the configured module URL to check if the module and its controls were properly imported and everything looked fine as the controller was trying to fetch the right ActionView but the problem is the .cshtml file cannot be found is what im thinking.

I also have a customViewEngine that handles the mapping of the Module Views according to the folder specified.

The code for customViewEngine

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Dependency_Injection_MEF_MVC.Components;

public class CustomViewEngine : RazorViewEngine
{
    private List<string> _plugins = new List<string>();

    public CustomViewEngine(List<string> pluginFolders)
    {
        //_plugins = pluginFolders;

        DirectoryInfo d = new DirectoryInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules/temp/"));//Assuming Test is your Folder
        FileInfo[] Files = d.GetFiles("*.dll"); //Getting Text files
        foreach (FileInfo file in Files)
        {
            _plugins.Add(file.Name.Substring(0, file.Name.IndexOf('.')));
        }


        ViewLocationFormats = GetViewLocations();
        MasterLocationFormats = GetMasterLocations();
        PartialViewLocationFormats = GetViewLocations();
    }

    public string[] GetViewLocations()
    {
        var views = new List<string>();
        views.Add("~/Views/{0}");

        _plugins.ForEach(plugin =>
            views.Add("~/Modules/temp/" + plugin + "/Views/Home/{0}")
        );

        return views.ToArray();
    }

    public string[] GetMasterLocations()
    {
        var masterPages = new List<string>();

        masterPages.Add("~/Views/Shared/{0}.cshtml");

        _plugins.ForEach(plugin =>
            masterPages.Add("~/Modules/temp/" + plugin + "/Views/Shared/{0}.cshtml")
        );

        return masterPages.ToArray();
    }
}

I get this error, analyzing it I can see that the last two places it checked is where it should reside but the View engine fails to find it even though it is there.

enter image description here

so tl:dr

Created sperate projects to compose them as MEF parts in a main project, after composing them I tried to test it by navigating to the webpage of the Module's controller where I am greeted with the above error.


Solution

  • This had to do with DLL file locking, essentially I just had to create a shadow copy of the module dll's which should allow you to access all the contents.

    This is the piece of code I used that I found online and works perfectly. Might have to change the path definition in your project.

    private static void genShadowCopy(List<string> pluginFolders){
    
    
    
        DirectoryInfo PluginFolder = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory + "/Modules/");
    
    
        DirectoryInfo ShadowCopyFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/Modules/temp"));
    
        String shadowFullPath = ShadowCopyFolder.FullName;
    
        Directory.CreateDirectory(ShadowCopyFolder.FullName);
        //clear out old plugins in previous shadowcopyfolder)
        foreach (var f in ShadowCopyFolder.GetFiles("*.dll", SearchOption.AllDirectories))
        {
            f.Delete();
        }
        //shadow copy files
        foreach (var plug in PluginFolder.GetFiles("*.dll", SearchOption.AllDirectories))
        {
            var di = Directory.CreateDirectory(ShadowCopyFolder.FullName);
            // NOTE: You cannot rename the plugin DLL to a different name, it will fail because the assembly name is part if it's manifest
            // (a reference to how assemblies are loaded: http://msdn.microsoft.com/en-us/library/yx7xezcf )
    
            String dif = di.FullName + plug.Name;
    
            File.Copy(plug.FullName, Path.Combine(di.FullName, plug.Name), true);
    
        }