从MVC5或Web API 2控制器操作返回生成的CSS

tac*_*cos 2 css asp.net-mvc less asp.net-web-api2

在我们的多租户应用程序中,我们需要自定义每个租户使用的样式.

我们目前计划在客户端上以下列方式使用LESS和变量:

  1. 从服务器下载相关的LESS文件
  2. 调用Web服务以获取配置对象
  3. 形成具有变量的有效LESS的字符串
  4. 使用less.js编译器根据这些变量和步骤1中的固定LESS文件编译LESS

这种方法有许多缺点:

  • 客户可能会表现得很糟糕
  • 有些浏览器有问题 less.js
  • 编译需要时间

我们宁愿在服务器上处理这项工作,所以粗略地说,这发生在服务器上:

  1. 客户端请求下载一个大的编译样式表 - GET content/styles/{tenantName}.css
  2. 使用tenantName服务器获取配置
  3. 使用模板和适当的变量(可能string.Format或更复杂的东西)
  4. 服务器将LESS编译为CSS字符串
  5. 服务器返回适当的CSS字符串 Content-Type

这是我的问题:

  1. 这是实现上述结果的不寻常或不受欢迎的方式吗?
  2. 如果没有为服务器端JavaScript设置架构,我如何将LESS编译成CSS?
  3. 我必须在控制器操作或路由配置中做什么才能让客户端认为服务器返回一个常规的旧CSS文件,完成缓存控制,而不是修改?

ben*_*ery 6

您可以使用BundleTransformer来编译LESS服务器端.

它可能取决于您希望如何提供文件.如果您知道所有租户,那么只需添加每个租户应用程序的捆绑URL到捆绑包配置.

 var themeStyles = new CustomStyleBundle("~bundles/theme/tenant").Include("~/Content/theme.less");
 themeStyles.Builder = new ThemeBuilder();
 BundleTable.Bundles.Add(themeStyles);
Run Code Online (Sandbox Code Playgroud)

如果您没有,并且租户在我们的情况下是灵活的,那么为您的主题添加以下控制器操作.

    [Route("bundles/theme/{id}")]
    public ContentResult Theme(string id)
    {
        var tenantThemePath = string.Format("~/bundles/theme/{0}", id);

        // Check that bundle has not already been added.
        if (BundleTable.Bundles.All(x => x.Path != tenantThemePath))
        {
            var themeStyles = new CustomStyleBundle(tenantThemePath ).Include("~/Content/theme.less");

            themeStyles.Builder = new ThemeBuilder();

            BundleTable.Bundles.Add(themeStyles);
        }

        var context = new BundleContext(HttpContext, BundleTable.Bundles, institutionPath);

        var response = BundleTable.Bundles.GetBundleFor(tenantThemePath).GenerateBundleResponse(context);

        Response.Cache.SetCacheability(response.Cacheability);

        return Content(response.Content, response.ContentType);
    }
Run Code Online (Sandbox Code Playgroud)

BundleTransformer的ThemeBuilder实现

public class ThemeBuilder : IBundleBuilder
{
    public string BuildBundleContent(Bundle bundle, BundleContext context, IEnumerable<BundleFile> files)
    {
        var lessTranslator = bundle.Transforms.OfType<StyleTransformer>()
            .Where(x => x != null)
            .Select(x => x.Translators.OfType<LessTranslator>().FirstOrDefault())
            .FirstOrDefault();

        if (lessTranslator == null)
        {
            return string.Empty;
        }

        lessTranslator.GlobalVariables = GetThemeVariables();

        return string.Empty;
    }

    private string GetThemeVariables()
    {
        // Simplified for brevity
        // This will be translated to less variables by the BundleTransformer
        // themeColour should correspond to a variable name in your less file.  
        return string.Format("themeColour={0}", themeColour);
    }

}
Run Code Online (Sandbox Code Playgroud)

您将需要远离获取主题颜色,我们将这些变量存储在HttpContext存储中,以便我们可以使用GetThemeVariables方法中的扩展方法将它们拉出来.

我希望这有帮助.

更新 我扩展了我的原始答案,并创建了一个包含主题的更可重用的方式.

演示网站:http://bundletransformer-theme-builder.azurewebsites.net/

GitHub回复:https://github.com/benembery/bundle-transformer-theme-builder