2011-01-25 11 views
12

Napisałem metodę działania ASP.NET MVC, która odbiera nazwę pliku .less, przetwarza ją przez Less.Parse(<filename>) i wysyła przetworzony plik css.Jak mogę wyświetlać błędy podczas używania .less programowo?

Działa to poprawnie, dopóki kod .less jest poprawny, ale jeśli wystąpi błąd, kropka zwraca tylko pusty ciąg. Więc jeśli wystąpił błąd podczas przetwarzania pliku, moja metoda akcji zwraca pusty plik CSS.

Jak mogę wyświetlić komunikat o błędzie z dokładniejszym opisem błędu składni?

+0

Widziałeś SquishIt? http://www.codethinked.com/post/2010/05/26/SquishIt-The-Friendly-ASPNET-JavaScript-and-CSS-Squisher.aspx –

+0

@qstarin: Dzięki, ale już używam combres (http: //combres.codeplex.com/) do celów produkcyjnych i combres mogą zrobić wszystko, co robi squishit (plus trochę więcej). Nadal potrzebuję odpowiedzi na powyższe pytanie do celów rozwojowych. Powodem jest to, że nie lubię pracować z połączonym plikiem do pobrania wszystkich moich plików CSS, zamiast tego wolę osobne pliki. I wszystko działa dobrze, z wyjątkiem komunikatów o błędach ... –

+0

Jestem ciekawy, jakie użyteczne funkcje zapewnia, że ​​SquishIt nie? Przeglądając dokumentację Combres wygląda na to, że wykonują wiele takich samych zadań. SquishIt jednak obejmuje dotLess do jego przetwarzania. Właśnie dlatego wspomniałem o tym, ponieważ nie potrzebowałbyś osobnej akcji do wykonania kompilacji dotLess. –

Odpowiedz

14

DotLess parser pułapek Wyjątki i wysyła je do Logger. Fragment ze źródła bez kropki, że wykonuje to 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 ma przeciążenie, że trwa DotlessConfiguration obiekt, który zapewnia wiele właściwości, które można użyć:

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

Można zauważyć, że Logger właściwość jest typu Type. Niezależnie od rodzaju podać musi wdrożyć 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); 
} 

Jak widzieliśmy w pierwszym fragmencie, metoda Error na rejestratorze zostanie sprawdzony gdy wystąpi błąd podczas parsowania.

Jedną z lepszych rzeczy jest to, jak dokładnie instancja typu implementującego ILogger zostaje utworzona. Wewnętrznie, dotLess używa kontenera IoC, który jest wypiekany w bibliotece DLL. Po wywołaniu metody okazuje się, że ostatecznie zadzwoni pod numer Activator.CreateInstance, aby utworzyć instancję ILogger.

Mam nadzieję, że jest to co najmniej pomocne.

+0

Doskonały. Wielkie dzięki! :-) –

+1

Naprawdę powinienem przerobić API rejestratora nieco ... W chwili pisania tego tekstu miało to sens tylko z myślą o wewnętrznych celach .. ale dla zewnętrznych rozmówców jest to bardzo złe .. – Tigraine

+0

@ Tigraine: Mam nadzieję, że przynajmniej Odpowiednio wyjaśniłem, jak złapać rejestrowanie zdarzeń, nie byłem pewien, czy wszystko to udało mi się uzyskać, a zwłaszcza, jakie były konsekwencje związane z określeniem obiektu DotlessConfiguration z wypełnioną tylko klasą rejestrowania. Ponadto, jeśli przerabiasz to , Wskazywałbym na SimpleLoggingFramework lub Common.Logging jako dwie potencjalne fasady do rejestrowania systemów, choć szczerze mówiąc, może to powodować bałagan ze wszystkimi zależnościami ... Powodzenia. heh –

5

Właśnie spotkałem się z tym dzisiaj w moim projekcie RequestReduce. Zaczynałem tracić mniej -> css transformuje się, ponieważ były błędy parsowania, które zdawały się wchodzić do eteru. Dzięki odpowiedzi qes udało mi się wypracować rozwiązanie, w którym mógłbym zapisać błędy w strumieniu odpowiedzi. Oto moja 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; } 
} 

mijam to do konfiguracji wysłanym do EngineFactory:

  var engine = new EngineFactory(new DotlessConfiguration 
               { 
                CacheEnabled = false, 
                Logger = typeof (LessLogger) 
               } 
       ).GetEngine(); 

Dla celów testowych jednostkowych chciałem przekazać w moim HttpResponseBase że napisze błąd. To gdzie czułem rzeczy coraz brzydki rzęsiste odlewania uzyskać odniesienie do mojego Rejestrator:

  ((LessLogger)((LessEngine)((ParameterDecorator)engine).Underlying).Logger).Response = response; 

Mam nadzieję, że to pomaga i jeśli ktoś zna bardziej elegancki sposób, aby uzyskać odwołanie do rejestratora, proszę daj mi znać.

+0

Gdzie umieszczasz klasę "LessLogger'? – guanome

5

Możesz to zrobić bardzo łatwo dzięki web.config. W sekcji konfiguracji bezstykowej dodaj: logger="dotless.Core.Loggers.AspResponseLogger". To sprawi, że wyjście bez kropli będzie błędem zamiast pustego css.

Jako przykład podam poniższe przykłady. ("..." reprezentuje istniejące rzeczy w twoim web.config). W moim przykładzie poniżej pamięć podręczna ma ustawioną wartość false. Jest to przydatne do celów debugowania.Prawdopodobnie powinno być ustawione na prawdziwe w normalnych warunkach.

<configuration>  
    <configSections> 
      ... 
      <section name="dotless" type="dotless.Core.configuration.DotlessConfigurationSectionHandler,dotless.Core" /> 
     </configSections> 

     <dotless minifyCss="false" cache="false" 
      logger="dotless.Core.Loggers.AspResponseLogger" /> 
     ...  
</configuration>  
+3

Dodałem linię, która wygląda następująco Nic nie robi dla mnie? – Jacques

+0

Nie wiesz, dlaczego jest to oznaczone jako odpowiedź? –

+1

+1 Działa to - jeśli używasz czegoś takiego jak SquishIt, upewnij się, że odwołujesz się do mniej plików bezpośrednio w przeglądarce (lub cokolwiek innego), aby wyświetlić błędy – davidsleeps

0

Dla korzyści innych, rozwiązanie @ tony722 działa, jeśli po prostu odwołujesz się do plików .less ze swoich stron.

Ale jeśli zadzwonisz Less.Parse bezpośrednio, metoda ta będzie pisać żadnego błędu na Response:

var lessConfig = new DotlessConfiguration { Logger = typeof(AspResponseLogger) }; 
string css = Less.Parse(someInput, lessConfig); 
0

ten loguje się do okna wyjściowego w 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); 
+0

jest to rozwiązanie na własną rękę. Czy wymaga to wdrożenia programu rejestrującego, takiego jak poprzednie? – petersmm

1

używam klasy otoki wokół bez kropki , w następujący sposób:

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

Sztuką jest wykorzystanie własnej impozycji ntation interfejsu IStylizer, który jest wywoływany po napotkaniu błędu analizy w celu sformatowania wynikowego komunikatu o błędzie. To pozwala nam przechwytywać dyskretne fragmenty błędu, w przeciwieństwie do implementacji interfejsu ILogger, gdzie błąd jest już sformatowanym tekstem.

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); 
Powiązane problemy