Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC Razor, Include JS / CSS files from another project

I've got a C# MVC project that uses Razor syntax.
To be able to reuse some code, I want to put some of my JavaScript and CSS files in a different project and include them somehow.
This is how my scripts are included at the moment:

<script src="@Url.Content("~/Scripts/bootstrap-typeahead.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/bootstrap-dropdown.js")" type="text/javascript"></script>

At the moment, the scripts are in the same project as the cshtml file but they should be placed in the Common.Web project instead...
What I want to do is this (doesn't work though):

<script src="@Url.Content("Common.Web/Scripts/bootstrap-typeahead.js")" type="text/javascript"></script>
<script src="@Url.Content("Common.Web/Scripts/bootstrap-dropdown.js")" type="text/javascript"></script>
like image 469
Martin Avatar asked Aug 07 '12 09:08

Martin


2 Answers

I do this very thing. However I embed the Javascript files and other content in another DLL and then call them from my razor syntax like so. Here is the code I use. In the View: Script example:

        <script [email protected]("GetEmbeddedResource", "Shared", new { resourceName = "Namespace.Scripts.jquery.qtip.min.js", pluginAssemblyName = @Url.Content("~/bin/Namespace.dll") }) type="text/javascript" ></script>

Image Example:

@Html.EmbeddedImage("corporate.gif", new { width = 150, height = 50})

Here is my helper methods:

        public static MvcHtmlString EmbeddedImage(this HtmlHelper htmlHelper, string imageName, dynamic htmlAttributes)
    {
        UrlHelper url = new UrlHelper(HttpContext.Current.Request.RequestContext);
        var anchor = new TagBuilder("img");
        anchor.Attributes["src"] = url.Action("GetEmbeddedResource", "Shared",
                                              new
                                                  {
                                                      resourceName = "Namespace.Content.Images." + imageName,
                                                      pluginAssemblyName = url.Content("~/bin/Namespace.dll")
                                                  });

        if (htmlAttributes != null)
        {
            string width = "";
            string height = "";
            PropertyInfo pi = htmlAttributes.GetType().GetProperty("width");
            if (pi != null)
                width = pi.GetValue(htmlAttributes, null).ToString();

            pi = htmlAttributes.GetType().GetProperty("height");
            if (pi != null)
                height = pi.GetValue(htmlAttributes, null).ToString();

            if (!string.IsNullOrEmpty(height))
                anchor.Attributes["height"] = height;

            if (!string.IsNullOrEmpty(width))
                anchor.Attributes["width"] = width;
        }
        return MvcHtmlString.Create(anchor.ToString());
    }

Lastly my shared Controller:

        [HttpGet]
    public FileStreamResult GetEmbeddedResource(string pluginAssemblyName, string resourceName)
    {
        try
        {
            string physicalPath = Server.MapPath(pluginAssemblyName);
            Stream stream = ResourceHelper.GetEmbeddedResource(physicalPath, resourceName);
            return new FileStreamResult(stream, GetMediaType(resourceName));
            //return new FileStreamResult(stream, GetMediaType(tempResourceName));
        }
        catch (Exception)
        {
            return new FileStreamResult(new MemoryStream(), GetMediaType(resourceName));
        }
    }

    private string GetMediaType(string fileId)
    {
        if (fileId.EndsWith(".js"))
        {
            return "text/javascript";
        }
        else if (fileId.EndsWith(".css"))
        {
            return "text/css";
        }
        else if (fileId.EndsWith(".jpg"))
        {
            return "image/jpeg";
        }
        else if (fileId.EndsWith(".gif"))
        {
            return "image/gif";
        }
        else if (fileId.EndsWith(".png"))
        {
            return "image/png";
        }
        return "text";
    }

Resource Helper:

    public static class ResourceHelper
{
    public static Stream GetEmbeddedResource(string physicalPath, string resourceName)
    {
        try
        {
            Assembly assembly = PluginHelper.LoadPluginByPathName<Assembly>(physicalPath);

            if (assembly != null)
            {
                string tempResourceName = assembly.GetManifestResourceNames().ToList().FirstOrDefault(f => f.EndsWith(resourceName));
                if (tempResourceName == null)
                    return null;
                return assembly.GetManifestResourceStream(tempResourceName);
            }
        }
        catch (Exception)
        {

        }

        return null;
    }
}  

Plugin Helper

public static T LoadPluginByPathName<T>(string pathName)
{
    string viewType = typeof(T).GUID.ToString();

    if (HttpRuntime.Cache[viewType] != null)
        return HttpRuntime.Cache[viewType] is T ? (T)HttpRuntime.Cache[viewType] : default(T);

    object plugin = Assembly.LoadFrom(pathName);
    if (plugin != null)
    {
        //Cache this object as we want to only load this assembly into memory once.
        HttpRuntime.Cache.Insert(viewType, plugin);
        return (T)plugin;
    }

    return default(T);
}

Remember that I am using these as embedded content!

like image 131
retslig Avatar answered Nov 04 '22 05:11

retslig


To my knowledge you can't do this as the path would lie outside of the website.

You can however do the following:

1) Put all the scripts you want to share in Common.Web\Scripts
2) For each script file in your Web application 'Add as Link' to your Common.Web Scripts (you don't even need to do this step; it is however nice to see what scripts your web app uses in VS)
3) Add a post-build event to your Web application that copies the scripts from Common.Web\Scripts to your WebApp\Scripts folder:

copy $(ProjectDir)..\Common.Web\Scripts* $(ProjectDir)\Scripts

so from your perspective in Visual Studio you will only have a single place to update your .js files that can be used by multiple projects.

like image 44
wal Avatar answered Nov 04 '22 05:11

wal