Hello,
Im running into an issue when trying to programatically replace/override certain less attributes. I have installed all the required libraries and the web.config is configured properly (i believe. see attached config), but I am doing something slightly different.
We offer our customers the ability to override a specific set of parameters which are optional query params to an MVC endpoint. We originally were using dotLess to replace the less attributes but now that we're moving to bootstrap 3 we want to update our libs to use bundletransformer.
What im looking for is an example of how to programatically parse and replace those specified attributes and stream back the preprocessed css.
The way i have it setup now is that i have a main less file (defaults.less) that contains the default attributes and values as well as an import of more application specific less files.
defaults.less file:
```
//Default Overrideable Attributes
@appFontFamily: "Helvetica Neue", Helvetica, Arial, sans-serif;
@appFontSize: 13px;
@appFontColor: #333333;
@appBorderRadius: 4px;
@appBackgroundColor: #ffffff;
@appPrimaryColor: #3484d6;
@appWarningColor: #D66934;
@appSuccessColor: #4FD634;
//-Default Overrideable Attributes
@appHighlightFontColor: lighten(@appPrimaryColor,20%);
@appLowlightFontColor: darken(@appPrimaryColor,25%);
@appButtonBgColor: lighten(@appFontColor,50%);
@appButtonFontColor: darken(@appFontColor,20%);
@appButtonPrimaryBgColor: lighten(@appPrimaryColor,25%);
@appButtonPrimaryFontColor: darken(@appPrimaryColor,20%);
@appButtonSuccessBgColor: lighten(@appSuccessColor,25%);
@appButtonSuccessFontColor: darken(@appSuccessColor,20%);
@appButtonWarningBgColor: lighten(@appWarningColor,20%);
@appButtonWarningFontColor: @appBackgroundColor;
@appPadSize: round(1.5 * @appFontSize);
@appHeaderSize: @appPadSize * 3.5;
@import "ss.less";
```
What we want is to load this less file, replace the Default Overrideable Attributes with the values we have on the query string and then process all the less and imports to produce the final css.
The endpoint that streams back the css looks like this (warning, ugly code):
```
var paramCollection = Request.QueryString;
Func<IJsEngine> jsEngineInstance = () => (new MsieJsEngine());
var vfsWrapper = new VirtualFileSystemWrapper();
var relativePathResolver = new CommonRelativePathResolver();
var lessConfig = new LessSettings();
var translator = new LessTranslator(jsEngineInstance, vfsWrapper, relativePathResolver, lessConfig);
//{
// IeCompat = true,
// JavascriptEnabled = true,
// ModifyVariables = CreateLessOverrides(paramCollection)
//};
var lessFile = System.Web.HttpContext.Current.Server.MapPath("~/Content/less/defaults.less");
var rawLess = System.IO.File.ReadAllText(lessFile);
var stylesheet = translator.PreprocessStylesheet(rawLess, lessFile, new LessImportOptions(".less"));
var dependencies = new DependencyCollection();
translator.FillDependencies(lessFile, stylesheet, dependencies);
return new ContentResult { Content = stylesheet.Content, ContentType = "text/css" };
```
Everything works until i get to the FillDependencies method. I get the following exception:
```
System.ArgumentException was unhandled by user code
HResult=-2147024809
Message=The relative virtual path 'E:/ui-service/UiService/Content/less/ss.less' is not allowed here.
Source=System.Web
StackTrace:
at System.Web.Hosting.HostingEnvironment.MapPathActual(VirtualPath virtualPath, Boolean permitNull)
at System.Web.Hosting.MapPathBasedVirtualPathProvider.CacheLookupOrInsert(String virtualPath, Boolean isFile)
at BundleTransformer.Less.Translators.LessTranslator.LessStylesheetExists(String assetUrl)
at BundleTransformer.Less.Translators.LessTranslator.FillDependencies(String rootAssetUrl, LessStylesheet parentStylesheet, DependencyCollection dependencies)
at Surescripts.UiService.Controllers.Mvc.LessParserController.Index(String s) in e:\ui-service\UiService\Controllers\Mvc\LessParserController.cs:line 42
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49()
InnerException:
```
I did some research and found a few spots that mention that this exception had been fixed so i made certain i was on the latest lib version ( BundleTransformer.Less/.Core (version 1.8.29.0) ).
It looks like someone else is having similar questions on [SO](http://stackoverflow.com/questions/16945938/bundletransformer-less-inject-variables-depending-on-context-request) but it hasnt been replied to.
I've tried different @imports of ss.less (./ss.less, etc) but that doesnt seem to work either. I've also tried just using the main LessTranslator constructor without the VirtualFileSystem/CommonRelativePathResolve/LessSettings params without any luck either.
One note is that the application is loaded in a virtual directory in IIS (if that matters).
Any advice or direction/examples would be greatly appreciated.
Thanks,
Jake
Comments: Hello, Jake! I did not immediately understand what you mean. Problem is that you are trying to use BundleTransformer.Less as a LESS-compiler (like dotless). Actually, BundleTransformer.Less is highly specialized solution which can only be used together with the [Microsoft ASP.NET Web Optimization Framework](http://aspnetoptimization.codeplex.com/). I recommend you to look the source code of following files: [`AssetHandlerBase.cs`](https://bundletransformer.codeplex.com/SourceControl/latest#BundleTransformer.Core/HttpHandlers/AssetHandlerBase.cs) and [`LessAssetHandlerBase.cs`](https://bundletransformer.codeplex.com/SourceControl/latest#BundleTransformer.Less/HttpHandlers/LessAssetHandlerBase.cs). The following code can solve your problem: ``` ... const string variablesToOverride = @"font-family-base='Comic Sans MS';" + "body-bg=lime;" + "font-size-h1=50px"; IAsset asset = new Asset("~/Content/less/bootstrap-3.1.1/bootstrap.less"); var lessTranslator = new LessTranslator { GlobalVariables = string.Empty, ModifyVariables = variablesToOverride, UseNativeMinification = true, IsDebugMode = false }; IAsset processedAsset = lessTranslator.Translate(asset); return new ContentResult { Content = processedAsset.Content, ContentType = "text/css" }; ... ``` By way, I gave my answer to the question [«BundleTransformer.Less inject variables depending on context/request»](http://stackoverflow.com/questions/16945938/bundletransformer-less-inject-variables-depending-on-context-request). If my solution for some reason is not suitable, then I recommend you to see the [LessCoffee](http://github.com/duncansmart/LessCoffee) project.
Im running into an issue when trying to programatically replace/override certain less attributes. I have installed all the required libraries and the web.config is configured properly (i believe. see attached config), but I am doing something slightly different.
We offer our customers the ability to override a specific set of parameters which are optional query params to an MVC endpoint. We originally were using dotLess to replace the less attributes but now that we're moving to bootstrap 3 we want to update our libs to use bundletransformer.
What im looking for is an example of how to programatically parse and replace those specified attributes and stream back the preprocessed css.
The way i have it setup now is that i have a main less file (defaults.less) that contains the default attributes and values as well as an import of more application specific less files.
defaults.less file:
```
//Default Overrideable Attributes
@appFontFamily: "Helvetica Neue", Helvetica, Arial, sans-serif;
@appFontSize: 13px;
@appFontColor: #333333;
@appBorderRadius: 4px;
@appBackgroundColor: #ffffff;
@appPrimaryColor: #3484d6;
@appWarningColor: #D66934;
@appSuccessColor: #4FD634;
//-Default Overrideable Attributes
@appHighlightFontColor: lighten(@appPrimaryColor,20%);
@appLowlightFontColor: darken(@appPrimaryColor,25%);
@appButtonBgColor: lighten(@appFontColor,50%);
@appButtonFontColor: darken(@appFontColor,20%);
@appButtonPrimaryBgColor: lighten(@appPrimaryColor,25%);
@appButtonPrimaryFontColor: darken(@appPrimaryColor,20%);
@appButtonSuccessBgColor: lighten(@appSuccessColor,25%);
@appButtonSuccessFontColor: darken(@appSuccessColor,20%);
@appButtonWarningBgColor: lighten(@appWarningColor,20%);
@appButtonWarningFontColor: @appBackgroundColor;
@appPadSize: round(1.5 * @appFontSize);
@appHeaderSize: @appPadSize * 3.5;
@import "ss.less";
```
What we want is to load this less file, replace the Default Overrideable Attributes with the values we have on the query string and then process all the less and imports to produce the final css.
The endpoint that streams back the css looks like this (warning, ugly code):
```
var paramCollection = Request.QueryString;
Func<IJsEngine> jsEngineInstance = () => (new MsieJsEngine());
var vfsWrapper = new VirtualFileSystemWrapper();
var relativePathResolver = new CommonRelativePathResolver();
var lessConfig = new LessSettings();
var translator = new LessTranslator(jsEngineInstance, vfsWrapper, relativePathResolver, lessConfig);
//{
// IeCompat = true,
// JavascriptEnabled = true,
// ModifyVariables = CreateLessOverrides(paramCollection)
//};
var lessFile = System.Web.HttpContext.Current.Server.MapPath("~/Content/less/defaults.less");
var rawLess = System.IO.File.ReadAllText(lessFile);
var stylesheet = translator.PreprocessStylesheet(rawLess, lessFile, new LessImportOptions(".less"));
var dependencies = new DependencyCollection();
translator.FillDependencies(lessFile, stylesheet, dependencies);
return new ContentResult { Content = stylesheet.Content, ContentType = "text/css" };
```
Everything works until i get to the FillDependencies method. I get the following exception:
```
System.ArgumentException was unhandled by user code
HResult=-2147024809
Message=The relative virtual path 'E:/ui-service/UiService/Content/less/ss.less' is not allowed here.
Source=System.Web
StackTrace:
at System.Web.Hosting.HostingEnvironment.MapPathActual(VirtualPath virtualPath, Boolean permitNull)
at System.Web.Hosting.MapPathBasedVirtualPathProvider.CacheLookupOrInsert(String virtualPath, Boolean isFile)
at BundleTransformer.Less.Translators.LessTranslator.LessStylesheetExists(String assetUrl)
at BundleTransformer.Less.Translators.LessTranslator.FillDependencies(String rootAssetUrl, LessStylesheet parentStylesheet, DependencyCollection dependencies)
at Surescripts.UiService.Controllers.Mvc.LessParserController.Index(String s) in e:\ui-service\UiService\Controllers\Mvc\LessParserController.cs:line 42
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49()
InnerException:
```
I did some research and found a few spots that mention that this exception had been fixed so i made certain i was on the latest lib version ( BundleTransformer.Less/.Core (version 1.8.29.0) ).
It looks like someone else is having similar questions on [SO](http://stackoverflow.com/questions/16945938/bundletransformer-less-inject-variables-depending-on-context-request) but it hasnt been replied to.
I've tried different @imports of ss.less (./ss.less, etc) but that doesnt seem to work either. I've also tried just using the main LessTranslator constructor without the VirtualFileSystem/CommonRelativePathResolve/LessSettings params without any luck either.
One note is that the application is loaded in a virtual directory in IIS (if that matters).
Any advice or direction/examples would be greatly appreciated.
Thanks,
Jake
Comments: Hello, Jake! I did not immediately understand what you mean. Problem is that you are trying to use BundleTransformer.Less as a LESS-compiler (like dotless). Actually, BundleTransformer.Less is highly specialized solution which can only be used together with the [Microsoft ASP.NET Web Optimization Framework](http://aspnetoptimization.codeplex.com/). I recommend you to look the source code of following files: [`AssetHandlerBase.cs`](https://bundletransformer.codeplex.com/SourceControl/latest#BundleTransformer.Core/HttpHandlers/AssetHandlerBase.cs) and [`LessAssetHandlerBase.cs`](https://bundletransformer.codeplex.com/SourceControl/latest#BundleTransformer.Less/HttpHandlers/LessAssetHandlerBase.cs). The following code can solve your problem: ``` ... const string variablesToOverride = @"font-family-base='Comic Sans MS';" + "body-bg=lime;" + "font-size-h1=50px"; IAsset asset = new Asset("~/Content/less/bootstrap-3.1.1/bootstrap.less"); var lessTranslator = new LessTranslator { GlobalVariables = string.Empty, ModifyVariables = variablesToOverride, UseNativeMinification = true, IsDebugMode = false }; IAsset processedAsset = lessTranslator.Translate(asset); return new ContentResult { Content = processedAsset.Content, ContentType = "text/css" }; ... ``` By way, I gave my answer to the question [«BundleTransformer.Less inject variables depending on context/request»](http://stackoverflow.com/questions/16945938/bundletransformer-less-inject-variables-depending-on-context-request). If my solution for some reason is not suitable, then I recommend you to see the [LessCoffee](http://github.com/duncansmart/LessCoffee) project.