sass / libsass-net

A lightweight wrapper around libsass
MIT License
94 stars 35 forks source link

Current version of Libsass-net throw a nullreference exception while runtime compiling on Azure web server #60

Open marinswk opened 6 years ago

marinswk commented 6 years ago

Hello, in the web application with which I'm working we are using Libsass-net for compiling some .scss on runtime, substituting some colour variables in the process.

The weird thing is that locally everything seems to work fine (even if sometimes the error occurs), while when publishing on an azure web server, the compiling works just one or two times fine, after that the sassCompiler.Compile() starts to throw nullreferenceexceptions.

the error trace is the sequent:

System.NullReferenceException: at LibSass.Compiler.SassExterns64.sass_compile_file_context (LibSass.NET, Version=4.0.0.0, Culture=neutral, PublicKeyToken=null) at LibSass.Compiler.Context.SassSafeFileContextHandle.CompileInternalContext (LibSass.NET, Version=4.0.0.0, Culture=neutral, PublicKeyToken=null) at LibSass.Compiler.Context.SassSafeContextHandle.CompileContext (LibSass.NET, Version=4.0.0.0, Culture=neutral, PublicKeyToken=null)

while the code and the sobstitution that im using is the sequent:

private static CustomImportDelegate _customImportDelegate;
private SassImport[] SassImportDelegate(string currentImport, string parentImport, ISassOptions sassOptions)
        {
                var sassImport = new List<SassImport>();
                var variablesImport = new SassImport();

                if (currentImport.EndsWith("_variables_00_backend"))
                {
                    variablesImport.Data = _colorString;
                }
                else
                {
                    variablesImport.Path = currentImport;
                }
                sassImport.Add(variablesImport);
                return sassImport.ToArray();

        }

private string GenerateCss(string path)
        {
                _customImportDelegate = SassImportDelegate;
                Telemetrytrace($"path is {path}");
                var sassOptions = new SassOptions
                {
                    InputPath = HttpContext.Current.Server.MapPath(path),
                    Importers = new[]{ _customImportDelegate },
                    IncludeSourceComments = false,
                    OutputStyle = SassOutputStyle.Compressed,              
                };

                var sassCompiler = new SassCompiler(sassOptions);
                var sassResult = sassCompiler.Compile();
                return sassResult.Output;   
        }

Is there anyone that had the same problem? any solution out there?

thanks in advance! cheers.

darrenkopp commented 6 years ago

Where are you using this at (http handler, etc). The first thing that stands out is the static variable _customImportDelegate. I don't think that is re-usable across multiple requests / threads, so I'm guessing that is why you start running into null ref exceptions. You could easily just reference SassImportDelegate in the importers array since a new one is created on each call.

You need to cache this output somewhere tho and synchronize locking though, if you haven't already done that. Prob don't want to compile the css on each request

marinswk commented 6 years ago

The function is used in an api controller. So your suggestion is to just get rid of the static variable? this didn't solve the problem, unfortunately.

yes, this is already handled, the css should be compiled just once then stored, I didn't report the full code for convenience.

marinswk commented 6 years ago

hello, I've changed the code passing the importer directly into the importes array as you suggested and getting rid of the static variable, unfortunately, this seems not to solve the problem. After deployment, the recompiling works fine but after some time of asking the recompiling of the files, I start to get the null-reference exceptions. Do you have more hints on why this might happen?

the code now looks like this:

private SassImport[] SassImportDelegate(string currentImport, string parentImport, ISassOptions sassOptions)
        {
            try
            {
                var sassImport = new List<SassImport>();
                var variablesImport = new SassImport();

                if (currentImport.EndsWith("_variables_00_backend"))
                {
                    variablesImport.Data = _colorString;
                }
                else
                {
                    variablesImport.Path = currentImport;
                }
                sassImport.Add(variablesImport);
                return sassImport.ToArray();
            }
            catch (Exception exception)
            {
                TelemetryClient(exception);
                throw;
            }
        }

private string GenerateCss(string path)
        {
            try
            {
                CustomImportDelegate _customImportDelegate = SassImportDelegate;
                var sassOptions = new SassOptions
                {
                    InputPath = HttpContext.Current.Server.MapPath(path),
                    Importers = new[]{ _customImportDelegate },
                    IncludeSourceComments = false,
                    OutputStyle = SassOutputStyle.Compressed       
                };

                var sassCompiler = new SassCompiler(sassOptions);
                var sassResult = sassCompiler.Compile();
                return sassResult.Output;
            }
            catch (Exception exception)
            {
                TelemetryClient(exception);
                return string.Empty;
            }      
        }