我编写了一个 ASP.NET MVC 操作方法,它接收一个 .less 文件名,通过它处理它Less.Parse(<filename>)
并输出处理后的 css 文件。
只要 .less 代码有效,它就可以正常工作,但如果出现错误,dotLess 只会返回一个空字符串。因此,如果处理文件时出错,我的操作方法会返回一个空的 css 文件。
我怎样才能输出一条错误消息,其中包含对语法错误的更详细描述?
我编写了一个 ASP.NET MVC 操作方法,它接收一个 .less 文件名,通过它处理它Less.Parse(<filename>)
并输出处理后的 css 文件。
只要 .less 代码有效,它就可以正常工作,但如果出现错误,dotLess 只会返回一个空字符串。因此,如果处理文件时出错,我的操作方法会返回一个空的 css 文件。
我怎样才能输出一条错误消息,其中包含对语法错误的更详细描述?
dotLess 解析器捕获异常并将它们输出到记录器。执行此操作的 dotLess 源代码片段是LessEngine.TransformToCss
:
public string TransformToCss(string source, string fileName)
{
try
{
Ruleset ruleset = this.Parser.Parse(source, fileName);
Env env = new Env();
env.Compress = this.Compress;
Env env2 = env;
return ruleset.ToCSS(env2);
}
catch (ParserException exception)
{
this.Logger.Error(exception.Message);
}
return "";
}
Less.Parse
有一个接受一个DotlessConfiguration
对象的重载,它提供了几个可以使用的属性:
public class DotlessConfiguration
{
// Properties
public bool CacheEnabled { get; set; }
public Type LessSource { get; set; }
public Type Logger { get; set; }
public LogLevel LogLevel { get; set; }
public bool MinifyOutput { get; set; }
public int Optimization { get; set; }
public bool Web { get; set; }
}
您会注意到该Logger
属性的类型为Type
。无论您提供什么类型,都必须实现dotless.Core.Loggers.ILogger
:
public interface ILogger
{
// Methods
void Debug(string message);
void Error(string message);
void Info(string message);
void Log(LogLevel level, string message);
void Warn(string message);
}
正如我们在第一个片段中看到的,Error
当解析过程中遇到错误时,记录器上的方法将被调用。
现在,所有这一切的一个难点是实现的类型的实例是如何ILogger
被实例化的。在内部,dotLess 使用嵌入到 DLL 中的 IoC 容器。在方法调用之后,它似乎最终会调用Activator.CreateInstance
以实例化您的 ILogger。
我希望这至少有点帮助。
我今天在我的RequestReduce项目中遇到了这个问题。我得到了更少的空白 - > css 转换,因为似乎有解析错误进入以太。感谢 qes 的回答,我能够找到一个解决方案,我可以将错误写入响应流。这是我的 dotless.Core.Loggers.ILogger:
public class LessLogger : ILogger
{
public void Log(LogLevel level, string message)
{
}
public void Info(string message)
{
}
public void Debug(string message)
{
}
public void Warn(string message)
{
}
public void Error(string message)
{
Response.Write(message);
}
public HttpResponseBase Response { get; set; }
}
我将它传递到发送到 EngineFactory 的配置中:
var engine = new EngineFactory(new DotlessConfiguration
{
CacheEnabled = false,
Logger = typeof (LessLogger)
}
).GetEngine();
出于单元测试的目的,我想传入会写错误的 HttpResponseBase。这就是我觉得通过一些讨厌的铸造来获得对我的记录器的引用的事情变得丑陋的地方:
((LessLogger)((LessEngine)((ParameterDecorator)engine).Underlying).Logger).Response = response;
我希望这会有所帮助,如果有人知道一种更优雅的方式来获取对记录器的引用,请告诉我。
您可以使用 web.config 轻松完成此操作。在您的无点配置部分中,添加以下内容:logger="dotless.Core.Loggers.AspResponseLogger"
. 这将使无点输出错误而不是空白 css。
我已将以下内容作为示例。(“...”代表 web.config 中的现有内容)。在我下面的示例中,缓存设置为 false。这对于调试目的很有用。在正常情况下,它可能应该设置为 true。
<configuration>
<configSections>
...
<section name="dotless" type="dotless.Core.configuration.DotlessConfigurationSectionHandler,dotless.Core" />
</configSections>
<dotless minifyCss="false" cache="false"
logger="dotless.Core.Loggers.AspResponseLogger" />
...
</configuration>
我在 dotless 周围使用了一个包装类,如下所示:
public class LessParser : IStylizer
{
public string ErrorFileName { get; private set; }
public int ErrorLineNumber { get; private set; }
public int ErrorPosition { get; private set; }
public string ErrorMessage { get; private set; }
string IStylizer.Stylize(Zone zone)
{
ErrorFileName = zone.FileName;
ErrorLineNumber = zone.LineNumber;
ErrorPosition = zone.Position;
ErrorMessage = zone.Message;
return String.Empty;
}
public string Compile(string lessContent, string lessPath)
{
var lessEngine = new EngineFactory(new DotlessConfiguration
{
CacheEnabled = false,
DisableParameters = true,
LogLevel = LogLevel.Error,
MinifyOutput = true
}).GetEngine();
lessEngine.CurrentDirectory = lessPath;
/* uncomment if DisableParameters is false
if (lessEngine is ParameterDecorator)
lessEngine = ((ParameterDecorator)lessEngine).Underlying;
*/
/* uncomment if CacheEnabled is true
if (lessEngine is CacheDecorator)
lessEngine = ((CacheDecorator)lessEngine).Underlying;
*/
((LessEngine)lessEngine).Parser.Stylizer = this;
return lessEngine.TransformToCss(lessContent, null);
}
public FileInfo SyncCss(FileInfo lessFile)
{
var cssFile = new FileInfo(
lessFile.FullName.Substring(0, lessFile.FullName.Length - lessFile.Extension.Length) + ".css");
if (!cssFile.Exists || cssFile.LastWriteTimeUtc < lessFile.LastWriteTimeUtc)
{
string cssContent = Compile(ReadFileContent(lessFile), lessFile.DirectoryName);
if (String.IsNullOrEmpty(cssContent))
return null;
using (var stream = cssFile.Open(FileMode.Create))
using (var writer = new StreamWriter(stream, Encoding.UTF8))
{
writer.Write(cssContent);
}
}
return cssFile;
}
public string ReadFileContent(FileInfo file)
{
using (var reader = file.OpenText())
{
return reader.ReadToEnd();
}
}
}
诀窍是使用自己的IStylizer
接口实现,在遇到解析错误时调用该接口来格式化生成的错误消息。这允许我们捕获错误的离散部分,这与ILogger
错误已经是格式化文本的接口实现不同。
var parser = new LessParser();
var lessFile = new FileInfo("C:\\temp\\sample.less"));
var cssFile = parser.SyncCss(lessFile);
if (cssFile != null)
Console.WriteLine(parser.ReadFileContent(cssFile));
else
Console.WriteLine("Error '{3}' in {0}, line {1}, position {2}",
parser.ErrorFileName, parser.ErrorLineNumber, parser.ErrorPosition, parser.ErrorMessage);
为了他人的利益,如果您只是从页面中引用 .less 文件,@tony722 的解决方案就可以工作。
但是如果你Less.Parse
直接调用,这个方法会将任何错误写入Response
:
var lessConfig = new DotlessConfiguration { Logger = typeof(AspResponseLogger) };
string css = Less.Parse(someInput, lessConfig);
这将记录到 VS 中的输出窗口:
var config = dotless.Core.configuration.DotlessConfiguration.GetDefault();
config.Logger = new dotless.Core.Loggers.DiagnosticsLogger(dotless.Core.Loggers.LogLevel.Debug).GetType();
config.MinifyOutput = minified;
css= Less.Parse(css, config);