Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Difficult to use dotless engine in asp.net outside of handler #179

Closed
mwrock opened this issue Apr 29, 2012 · 7 comments
Closed

Difficult to use dotless engine in asp.net outside of handler #179

mwrock opened this issue Apr 29, 2012 · 7 comments

Comments

@mwrock
Copy link
Contributor

mwrock commented Apr 29, 2012

First: Excellent library and thanks for your work in providing LESS compilation to the .net community.

I am the project owner of RequestReduce and I use dotless to provide LESS compilation of css that is then minified and bundled. I have my own caching, modules, handlers, config and so I like to call the dotless engine directly. This worked great up to 1.2.4 but I just upgraded to 1.3.2 and now I have to resort to some ugly Reflection in order to get access to the AspNetFactoryContainer. Previously I used new EngineFactory(config).GetEngine() but now if I call this where the config's Web property is true, I get a Pandora exception complaining about no IParameterSource. I see that there is now a way to specify that Parameters should be disabled which looks like it would get around that error, but I do want to use Parameters. So now I use this code:

        if (HttpContext.Current == null)
            engine = new EngineFactory(config).GetEngine();
        else
        {
            var dotLessAssembly = Assembly.GetAssembly(typeof (ContainerFactory));
            var factoryType = dotLessAssembly.GetType("dotless.Core.AspNetContainerFactory");
            var fac = (ContainerFactory)(factoryType.InvokeMember("", BindingFlags.CreateInstance, null, null, null));
            var locator = factoryType.InvokeMember("GetContainer", BindingFlags.InvokeMethod, null, fac, new object[] {config});
            engine =
                (ILessEngine)
                (dotLessAssembly.GetType("Microsoft.Practices.ServiceLocation.IServiceLocator").InvokeMember(
                    "GetInstance", BindingFlags.InvokeMethod, null, locator, new object[] {typeof (ILessEngine)}));
        }

While this works, it is fragile and aesthetically unattractive (unless you are in to that kind of thing). It would be great if your library could make some of this public or a bit more extensible. There are lots of options here and as long as I dont have to take a dependency on Pandora, it would work for me.

Thanks a bunch and thanks for creating dotless!

@lukeapage
Copy link
Member

Why do you have to use reflection? (Its public..?)

We moved asp related things into a separate assembly and it is merged (along with Pandora - you have a dependency on it already as its merged into dotless)

Is there something in particular you want us to change? A suggestion might help us understand the problem.

@mwrock
Copy link
Contributor Author

mwrock commented Apr 29, 2012

While it is declared public, after the ILMerge, everything in the new assembly is internal. You will probably want to add a internalize file and make sure that your own assemblies don't get internalized. However, this still leaves the ServiceLocator internalized which prevents me from calling GetContainer on the factory. Making that public probably is not a good idea though since many will use that assembly themselves and you dont want to add conflict.

Anyways, I realize this is all rather abstract and I'll try to clarify this in the form of a Pull Request which you may or may not want to accept but it will at least clarify my request. Thanks!

@lukeapage
Copy link
Member

yes, we absolutely do not want aspNet internalised.

If GetEngine accepted a ContainerFactory that would achieve what you wanted?

@mwrock
Copy link
Contributor Author

mwrock commented Apr 29, 2012

Yes. That would be awesome like a possum.

@lukeapage
Copy link
Member

Done!

Will you be desperate for a release or are you ok for a while?

@mwrock
Copy link
Contributor Author

mwrock commented Apr 29, 2012

Oh I'm fine. I just pushed a maintenance release to Nuget with the reflection code. Whenever you get around to releaseing this, I'll update to that. Thanks alot!

@ForNeVeR
Copy link

ForNeVeR commented Sep 12, 2016

You know guys what's interesting? I was able to use this API from F# like that:

open dotless.Core
open dotless.Core.configuration
open System.IO

let path = "C:\\Temp\\less"

let config = DotlessConfiguration()
let locator = ContainerFactory().GetContainer(config)
let engine = (locator.GetService (typeof<ILessEngine>)) :?> ILessEngine
engine.CurrentDirectory <- path

let fileName = Path.Combine (path, "main.less")
let content = File.ReadAllText fileName
let result = engine.TransformToCss (content, fileName)

Although an analogous C# program won't compile complaining about inconsistent accessibility:

var config = new DotlessConfiguration();
var cf = new ContainerFactory();
var locator = cf.GetContainer(config); // ← error CS0122: 'ContainerFactory.GetContainer(DotlessConfiguration)' is inaccessible due to its protection level
var engine = (ILessEngine)locator.GetService(typeof(ILessEngine));
engine.CurrentDirectory = path;

That's how I found that issue. Probably that's not a good idea to reference internal types (no matter of what kind) in a public API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants