I've written an ASP.NET MVC action method that receives a .less file name, processes it via Less.Parse(<filename>)
and outputs the processed css file.
This works fine as long as the .less code is valid, but if there is an error, dotLess just returns an empty string. So if there is an error processing the file, my action method returns an empty css file.
How can I output an error message with a closer description of the syntax error instead?
The dotLess parser traps Exceptions and outputs them to a Logger. The snippet from dotLess's source that performs this is 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
has an overload that takes a DotlessConfiguration
object, which provides several properties that you can use:
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; }
}
You will notice that the Logger
property is of type Type
. Whatever type you supply must implement 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);
}
As we saw in the first snippet, the Error
method on the logger will get called when an error is encountered during parsing.
Now, the one sticky point of all this is how exactly an instance of the type that implements ILogger
gets instantiated. Internally, dotLess uses an IoC container that is baked into the DLL. Following the method calls, it appears that it will eventually call Activator.CreateInstance
to instantiate your ILogger.
I hope this is at least somewhat helpful.
I just faced this today in my RequestReduce project. I was getting blank less -> css transforms because there were parse errors that appeared to be going into the ether. Thanks to qes's answer I was able to work out a solution where I could write the errors to the response stream. Here is my 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; }
}
I pass this into the Configuration sent to the EngineFactory:
var engine = new EngineFactory(new DotlessConfiguration
{
CacheEnabled = false,
Logger = typeof (LessLogger)
}
).GetEngine();
For unit testing purposes I wanted to pass in my HttpResponseBase that would write the error. This is where I felt things getting ugly with some nasty casting to get a reference to my logger:
((LessLogger)((LessEngine)((ParameterDecorator)engine).Underlying).Logger).Response = response;
I hope this helps out and if someone knows of a more elegant way to get a reference to the logger, please let me know.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With