Как вывести ошибки при использовании.less программно?
Я написал метод действия ASP.NET MVC, который получает имя файла.less, обрабатывает его через Less.Parse(<filename>)
и выводит обработанный файл CSS.
Это работает нормально, пока код.less действителен, но если возникает ошибка, dotLess просто возвращает пустую строку. Поэтому, если при обработке файла возникает ошибка, мой метод действия возвращает пустой файл CSS.
Как я могу вывести сообщение об ошибке с более подробным описанием синтаксической ошибки вместо этого?
7 ответов
Анализатор dotLess перехватывает исключения и выводит их в Logger. Фрагмент из источника 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 использует контейнер IoC, который запекается в DLL. После вызова метода кажется, что он в конечном итоге вызовет Activator.CreateInstance
создать экземпляр вашего ILogger.
Я надеюсь, что это по крайней мере несколько полезно.
Вы можете сделать это очень легко с помощью 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>
Я только что столкнулся с этим сегодня в моем проекте 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;
Я надеюсь, что это поможет, и если кто-то знает более элегантный способ получить ссылку на регистратор, пожалуйста, дайте мне знать.
Я использую класс-оболочку вокруг 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);
Для пользы других, решение @tony722 работает, если вы просто ссылаетесь на файлы.less со своих страниц.
Но если вы позвоните Less.Parse
напрямую, этот метод запишет любую ошибку в Response
:
var lessConfig = new DotlessConfiguration { Logger = typeof(AspResponseLogger) };
string css = Less.Parse(someInput, lessConfig);
Это будет регистрировать любые ошибки синтаксического анализа LESS в консоли отладки:
var config = dotless.Core.configuration.DotlessConfiguration.GetDefault();
config.Logger = new dotless.Core.Loggers.ConsoleLogger(dotless.Core.Loggers.LogLevel.Debug).GetType();
var lessCSS = Less.Parse("your css source", config);
Это входит в окно вывода в 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);