Embed Asp.Net MVC views in class library dll

If you’re anything like me, you may want to define asp.net mvc views in class library, so that it can be used from anywhere. However, it’s not an easy task, regarding the MVC architecture of asp.net mvc. The view normally be placed at Views folder physically, making us unaware of possibility to embed the view and controller to shared library (dll).

Define view in library

Create the view file

You can create the view file inside library project. If you cannot find the view template from add file, you can choose text file then rename the extension as cshtml (razor) or aspx.

Set the view as embedded resource

The view file need to be set as embedded resource during compilation, so that the file can be referenced from other projects.

Set the build action into embedded resource

Set the build action into embedded resource

How to make asp.net mvc find embedded view

There is a way to tell asp.net mvc to look up from specific source. One of them is embedded view. It can also get from database but I haven’t tried that or need a case for that.

To tell the asp.net mvc to look up at embedded resource, first we need to define a VirtualFile (System.Web.Hosting.VirtualFile). VirtualFile class can act as a “false” view file. When accessed, it can read the embedded resource file and return it instead of serving the asp.net mvc engine with physical file. Next step, we need to supply asp.net mvc with VirtualPathProvider class that can direct the engine into finding and serving the VirtualFile instead of physical file. Both of the files that will make it possible to serve asp.net views from source other than physical file.

Here’s the code for both class (with supporting class):

    public class EmbeddedResourcePathConfiguration
    {
        public EmbeddedResourcePathConfiguration(string rootNameSpace, string viewFolderName, Assembly resourceAssembly)
        {
            this.RootNameSpace = rootNameSpace;
            this.ViewFolderName = viewFolderName;
            this.ResourceAssembly = resourceAssembly;
        }
        public string RootNameSpace { get; set; }
        public string ViewFolderName { get; set; }
        public Assembly ResourceAssembly { get; set; }
        public string ViewNameSpace
        {
            get
            {
                return RootNameSpace + "." + ViewFolderName;
            }
        }

    }

    public class EmbeddedResourceNameProvider
    {
        private EmbeddedResourcePathConfiguration configuration = null;
        public EmbeddedResourcePathConfiguration Configuration
        {
            get { return configuration; }
            set { configuration = value; }
        }

        public string GetResourceName(string virtualPath)
        {
            var resourcename = virtualPath
                .Substring(virtualPath.IndexOf(configuration.ViewNameSpace));

            return resourcename;
        }
    }

    public class EmbeddedVirtualFile : VirtualFile
    {
        public EmbeddedVirtualFile(string virtualPath, EmbeddedResourcePathConfiguration configuration)
            : base(virtualPath)
        {
            this.configuration = configuration;
            EmbeddedResourceNameProvider.Configuration = configuration;
        }
        private EmbeddedResourcePathConfiguration configuration = null;

        EmbeddedResourceNameProvider embeddedResourceNameProvider = new EmbeddedResourceNameProvider();
        public EmbeddedResourceNameProvider EmbeddedResourceNameProvider
        {
            get { return embeddedResourceNameProvider; }
            set { embeddedResourceNameProvider = value; }
        }

        public override Stream Open()
        {
            string resourcePath = EmbeddedResourceNameProvider.GetResourceName(VirtualPath);
            return configuration.ResourceAssembly.GetManifestResourceStream(resourcePath);
        }
    }
    public class EmbeddedViewPathProvider : VirtualPathProvider
    {
        EmbeddedResourceNameProvider embeddedResourceNameProvider = new EmbeddedResourceNameProvider();
        public EmbeddedResourceNameProvider EmbeddedResourceNameProvider
        {
            get { return embeddedResourceNameProvider; }
            set { embeddedResourceNameProvider = value; }
        }

        private EmbeddedResourcePathConfiguration configuration = null;
        public EmbeddedViewPathProvider(EmbeddedResourcePathConfiguration configuration)
        {
            this.EmbeddedResourceNameProvider.Configuration = configuration;
            this.configuration = configuration;
        }

        private bool IsVirtualFile(string virtualPath)
        {
            return virtualPath.Contains(configuration.ViewNameSpace);
        }

        private bool ResourceFileExists(string virtualPath)
        {
            var resourcename = EmbeddedResourceNameProvider.GetResourceName(virtualPath);
            var result = resourcename != null && configuration.ResourceAssembly.GetManifestResourceNames().Contains(resourcename);
            return result;
        }

        public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
        {
            if (IsVirtualFile(virtualPath))
            {
                return new System.Web.Caching.CacheDependency(configuration.ResourceAssembly.Location);
            }
            return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
        }

        public override bool FileExists(string virtualPath)
        {
            if (IsVirtualFile(virtualPath))
            {
                bool exists = ResourceFileExists(virtualPath);
                return exists;
            }
            else
            {
                return base.FileExists(virtualPath);
            }
        }

        public override VirtualFile GetFile(string virtualPath)
        {
            if (IsVirtualFile(virtualPath))
            {
                return new EmbeddedVirtualFile(virtualPath, configuration);
            }
            else
            {
                return base.GetFile(virtualPath);
            }
        }
    }

Register the path provider into applications

The last step is to register the path provider to application. You can use the following code at global.asax, inside Application_Start.

EmbeddedResourcePathConfiguration configuration =
                    new EmbeddedResourcePathConfiguration(
                        rootNameSpace: "HtmlViewTemplate",
                        viewFolderName: "Views",
                        resourceAssembly: Assembly.Load("HtmlViewTemplate"));
                HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedViewPathProvider(configuration));
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s