MVC Razor,包含来自另一个项目的 JS/CSS 文件

Posted

技术标签:

【中文标题】MVC Razor,包含来自另一个项目的 JS/CSS 文件【英文标题】:MVC Razor, Include JS / CSS files from another project 【发布时间】:2012-08-04 07:00:47 【问题描述】:

我有一个使用 Razor 语法的 C# MVC 项目。 为了能够重用一些代码,我想将我的一些 javascript 和 CSS 文件放在不同的项目中,并以某种方式包含它们。 这就是我的脚本目前包含在内的方式:

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

目前,这些脚本与 cshtml 文件位于同一个项目中,但它们应该放在 Common.Web 项目中... 我想做的是这个(虽然不起作用):

<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>

【问题讨论】:

如果有人回答了您的问题,请将其标记为有。 你有没有想过这样做的好方法? 【参考方案1】:

我就是这样做的。但是,我将 Javascript 文件和其他内容嵌入到另一个 DLL 中,然后像这样从我的剃刀语法中调用它们。这是我使用的代码。 在视图中: 脚本示例:

        <script src=@Url.Action("GetEmbeddedResource", "Shared", new  resourceName = "Namespace.Scripts.jquery.qtip.min.js", pluginAssemblyName = @Url.Content("~/bin/Namespace.dll") ) type="text/javascript" ></script>

图片示例:

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

这是我的辅助方法:

        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());
    

最后是我的共享控制器:

        [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";
    

资源助手:

    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;
    
  

插件助手

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);

请记住,我将这些用作嵌入内容!

【讨论】:

听起来这可能是一个不错的解决方案。但是,您没有提供ResourceHelper 中使用的PluginHelper 的代码。没有它我无法测试它。另外,为了确保资源将被嵌入,我需要做的就是在属性的构建操作中将它们标记为“嵌入资源”吗? 我现在已经为插件助手编辑了上面的内容。更正您需要做的就是在该文件的属性下的构建操作字段中添加标记为嵌入式资源。对所有文件执行此操作。 这种技术可能会在高流量站点上导致一些性能问题。就个人而言,我不建议使用嵌入式资源。 Orchard CMS 有一个有趣的技术来包含来自其他项目的文件,所以我会检查一下! @Bevan 非常感谢指向相关 Orchard 文档的链接。 我没有尝试图像的示例代码,但其余部分都很完美。 :)【参考方案2】:

据我所知,您不能这样做,因为路径会位于网站之外。

但是,您可以执行以下操作:

1) 把你要分享的所有脚本放在 Common.Web\Scripts 2) 对于您的 Web 应用程序 'Add as Link' 中的每个脚本文件到您的 Common.Web 脚本(您甚至不需要执行此步骤;但是很高兴看到您的 Web 应用程序在 VS 中使用了哪些脚本 em>) 3) 向您的 Web 应用程序添加一个构建后事件,将脚本从 Common.Web\Scripts 复制到您的 WebApp\Scripts 文件夹:

复制 $(ProjectDir)..\Common.Web\Scripts* $(ProjectDir)\Scripts

因此,从您在 Visual Studio 中的角度来看,您将只有一个位置来更新可供多个项目使用的 .js 文件。

【讨论】:

我没有使用过 TFS,但我猜它会起作用,因为它会尊重构建后事件。【参考方案3】:

而不是使用Url 助手使用相对寻址。您尝试做的事情毫无意义,因为帮助程序用于解析与其项目相关的路径。

由于您正在尝试使用另一个项目的资源,因此可以假设您预先知道要在哪里部署每个项目。尽管我不喜欢这种做法,但我可以想到一个务实的解决方案。


如果您的两个应用程序位于 url:

http://www.mysite.com/app1
http://www.mysite.com/Common.Web

你可以这样称呼:

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

意思是,解决我的应用程序根文件夹,上一层,然后下路径的其余部分。

【讨论】:

【参考方案4】:

我在寻找相同答案时发现了这个问题。感谢之前的发帖人,他们明确指出,仅使用 Visual Studio 无法做到这一点:您将总是得到原始文件的副本,或不完整的传送文件集。 p>

每当我拥有简单的通用功能时,我不希望重新发明***,因此我的硬盘上有一个用于存放通用脚本的文件夹: /通用/Javascript

我的网络项目位于: /项目名称

所以我的常用脚本位于我的网络项目之外。

我通过源代码管理解决了这个问题。大多数源代码控制存储库都具有在另一个目录中显示文件的功能。我的步骤是:

    在我的 VS 项目下创建空文件夹:/ProjectName/Scripts/Common 将空文件夹提交到源代码管理 使用 Subversion(我的源代码管理),我设置了一个“extern”,以便我的公共文件链接到新文件夹。其他源代码控制软件可能会将此称为“链接”或其他类似的东西。 更新了新文件夹,我的常用 Javascript 文件进来了,现在可以添加到我在 Visual Studio 中的 Web 项目中。

显然,我通过更改 Visual Studio 中的文件并提交它们来测试这一点。这些更改确实反映在位于 /Common/Javascript 中的原始文件中。

我现在可以简单地向需要使用相同功能的任何其他 Web 项目添加一个 extern:当然,现在更改这些文件会带来额外的风险,因为我可能会意外破坏使用它们的其他项目。虽然我可以配置一个 extern 来使用文件的特定版本,但这不是我现在想要做的;我会等待这种复杂性发生的时候。

【讨论】:

以上是关于MVC Razor,包含来自另一个项目的 JS/CSS 文件的主要内容,如果未能解决你的问题,请参考以下文章

htmlhelper 不包含 ASP.NET MVC RAZOR 中的剑道定义

在 ASP.NET MVC 5 中从数据库加载 Razor 视图

获取 RadioButton 值 Razor MVC

应用程序找不到位于另一个项目中的 Razor 页面

ASP.NET MVC 3、Razor 视图和可移植区域

如何使用 Asp.net MVC Razor 将隐藏字段值从一个控制器传递到另一个控制器