Hello all,
I am currently working on a new pet project.
All is going well so far but I am dealing with trying to create new CSS & JS files pragmatically by using the shiny new FileService in an Umbraco Authuroised Web Api Controller and the Umbraco.Core.Models
I am trying to read an existing CSS file elsewhere in the application not the /css folder however when I am trying to use it with the following code below, the CSS file is not saved/moved to the /css folder as I would expect.
var testPath = "~/App_Plugins/test/css/hello-world.css";
var testFilePath = HostingEnvironment.MapPath(testPath);
var css = new Stylesheet(testFilePath);
var isValid = fileService.ValidateStylesheet(css);
//Save CSS File
fileService.SaveStylesheet(css);
Unless the FileService for CSS & JS is not meant to be used in this way and simply for reading file contents?
Do I just use System.IO to copy to the file from one place to another instead then?
IFileSystem is only implemented for media, that is why it is the only one that exists in config. There's a feature request on the tracker that's been there for quite some time to implement it for JS, css, etc
From the looks of it you are not setting the content on the StyleSheet object, which is what is used when saving the file. Passing the path in the constructor will only give the StyleSheet object a name as far as I remember.
You should be able to do something like css.Content = "body{color: orange;}"; and then save/validate. By default it will be saved to the /CSS folder. If you need to change the path you have to use the old way via appSettings (if that still works), as Shannon mentioned its not implemented in the "new" IFileSystem provider yet.
Sorry for the delayed reply, been mega busy :S
@Morten I will try doing css.Content but my gut feeling with using the API is that if I am providing a path to an existing CSS or JS file that it would read the file contents so I do not need to have to set the Content property.
@Shannon sorry totally lost about IFileSystem is this what allows me to configure where files are saved, stored & loaded from? If so I do not need to worry about that too much right now.
My gut feeling is that doing a IO.File.Copy() may be better as using FileSystem requires me to create a new object, read the existing source file contents and then set that on the CSS or JS file using the .Content property.
Or am I missing the whole point of the FileService API?
@Shannon thanks mate for the replies. Yeh I have no desire to use IFileSystem right now for this pet project.
I may put in a feature request to FileService & the StyleSheet & JavaScript Core.Models to have different signatures.
1: No arguments, so we create a new CSS file and set the name, alias & contents via it's properties
var css = new Stylesheet();
2: Name as an argument
var css = new StyleSheet("myCssFile");
3: Path to an existing file (Reads the file, sets name, alias & contents from file passed in)
var css = new StyleSheet("~/app_plugins/some.css");
Would this be something that is plausible to do as a feature request if I add to the issue tracker, as I don't want to add it if it can't or is unlikely to be implemented at any point in the future?
Mate, constructors are used to create models, not to perform any logical lookups - this was the biggest problem with the old APIs. Constructors should never DO anything.
If you want to get a stylesheet by path or name, that is part of the Service not the model.
OK no problem, then I just have a small issue with the current approach then of having to pass in a path to the StyleSheet & JavaScript when new'ing up their models, there is no option to provide an empty constructor at all currently.
So I have to do
var css = new Stylesheet(testFilePath);
Hence my automatic assumption by providing a path that the file contents would automatically be read and some other voodoo logic done when new'ing up the model.
The constructor just sets the path of how it will be saved. If you want to 'get' an existing stylesheet then you'd use the IFileService
If you want to create a new one, give it a name. The service knows that it always goes under /css so by giving a relative path that is where it will save. The below would save to /css/hello-world.css and the .Content property sets content on the object which gets saved to the file.
var css = new Stylesheet("hello-world.css");
css.Content = "put your file content here....";
var isValid = fileService.ValidateStylesheet(css);
//Save CSS File
fileService.SaveStylesheet(css);
I realize that passing in the path might seem a bit pointless as css and scripts are "restricted" to certain folders by default. But as far as I remember it doesn't have to be a path. A file name would do.
The Name and Alias are "extracted" from the path that is being passed into the ctor.
And, you can't have a file (css/script/etc) without a path/filename so an empty ctor won't make things easier IMO.
After your example Shannon I now see how it should be used, the path is the name of the file or path to the new file I want to create in the /css folder as opposed to a path to an existing file to read.
So the example you gave is great, however I run into one small problem. When calling validateStylesheet on the FileService I get the following exception, but if I comment the check out for validating the file then it works & the file is saved to the /css folder.
System.ArgumentException was caught
HResult=-2147024809
Message=The relative virtual path 'hello-world.css' is not allowed here.
Source=System.Web
StackTrace:
at System.Web.VirtualPath.FailIfRelativePath()
at System.Web.Hosting.HostingEnvironment.MapPathActual(VirtualPath virtualPath, Boolean permitNull)
at System.Web.Hosting.HostingEnvironment.MapPathInternal(VirtualPath virtualPath)
at System.Web.Hosting.HostingEnvironment.MapPath(VirtualPath virtualPath)
at System.Web.Hosting.HostingEnvironment.MapPath(String virtualPath)
at Umbraco.Core.IO.IOHelper.MapPath(String path, Boolean useHttpContext)
at Umbraco.Core.IO.IOHelper.MapPath(String path)
at Umbraco.Core.IO.IOHelper.VerifyEditPath(String filePath, IEnumerable`1 validDirs)
at Umbraco.Core.Models.Stylesheet.IsValid()
at Umbraco.Core.Services.FileService.ValidateStylesheet(Stylesheet stylesheet)
at Umbraco.Template.Wizard.Controllers.ImportTemplateWizardController.ProcessCss(CssFiles json) in c:\inetpub\wwwroot\Umbraco-Template-Wizard\Umbraco.Template.Wizard\Umbraco.Template.Wizard\Controllers\ImportTemplateWizardController.cs:line 48
InnerException:
Using FileService to Save CSS & JS
Hello all,
I am currently working on a new pet project.
All is going well so far but I am dealing with trying to create new CSS & JS files pragmatically by using the shiny new FileService in an Umbraco Authuroised Web Api Controller and the Umbraco.Core.Models
I am trying to read an existing CSS file elsewhere in the application not the /css folder however when I am trying to use it with the following code below, the CSS file is not saved/moved to the /css folder as I would expect.
Unless the FileService for CSS & JS is not meant to be used in this way and simply for reading file contents?
Do I just use System.IO to copy to the file from one place to another instead then?
Look forward to your thoughts guys & girls
Cheers,
Warren :)
IFileSystem is only implemented for media, that is why it is the only one that exists in config. There's a feature request on the tracker that's been there for quite some time to implement it for JS, css, etc
From the looks of it you are not setting the content on the StyleSheet object, which is what is used when saving the file. Passing the path in the constructor will only give the StyleSheet object a name as far as I remember.
You should be able to do something like css.Content = "body{color: orange;}"; and then save/validate. By default it will be saved to the /CSS folder. If you need to change the path you have to use the old way via appSettings (if that still works), as Shannon mentioned its not implemented in the "new" IFileSystem provider yet.
Hope this helps,
Morten
Sorry for the delayed reply, been mega busy :S
@Morten I will try doing css.Content but my gut feeling with using the API is that if I am providing a path to an existing CSS or JS file that it would read the file contents so I do not need to have to set the Content property.
@Shannon sorry totally lost about IFileSystem is this what allows me to configure where files are saved, stored & loaded from? If so I do not need to worry about that too much right now.
My gut feeling is that doing a IO.File.Copy() may be better as using FileSystem requires me to create a new object, read the existing source file contents and then set that on the CSS or JS file using the .Content property.
Or am I missing the whole point of the FileService API?
Thanks
Warren :)
IFileSystem = a virtual file system that you can configure, as you said to store and load files from. We only have 1 configurable IFileSystem = media.
Apart from media, do not use IFileSystem :)
The FileService will perform the IO operations for files for you iirc.
@Shannon thanks mate for the replies. Yeh I have no desire to use IFileSystem right now for this pet project.
I may put in a feature request to FileService & the StyleSheet & JavaScript Core.Models to have different signatures.
1: No arguments, so we create a new CSS file and set the name, alias & contents via it's properties
2: Name as an argument
3: Path to an existing file (Reads the file, sets name, alias & contents from file passed in)
Would this be something that is plausible to do as a feature request if I add to the issue tracker, as I don't want to add it if it can't or is unlikely to be implemented at any point in the future?
Cheers,
Warren
Mate, constructors are used to create models, not to perform any logical lookups - this was the biggest problem with the old APIs. Constructors should never DO anything.
If you want to get a stylesheet by path or name, that is part of the Service not the model.
OK no problem, then I just have a small issue with the current approach then of having to pass in a path to the StyleSheet & JavaScript when new'ing up their models, there is no option to provide an empty constructor at all currently.
So I have to do
Hence my automatic assumption by providing a path that the file contents would automatically be read and some other voodoo logic done when new'ing up the model.
The constructor just sets the path of how it will be saved. If you want to 'get' an existing stylesheet then you'd use the IFileService
If you want to create a new one, give it a name. The service knows that it always goes under /css so by giving a relative path that is where it will save. The below would save to /css/hello-world.css and the .Content property sets content on the object which gets saved to the file.
I realize that passing in the path might seem a bit pointless as css and scripts are "restricted" to certain folders by default. But as far as I remember it doesn't have to be a path. A file name would do. The Name and Alias are "extracted" from the path that is being passed into the ctor.
And, you can't have a file (css/script/etc) without a path/filename so an empty ctor won't make things easier IMO.
Thanks Guys for the replies.
After your example Shannon I now see how it should be used, the path is the name of the file or path to the new file I want to create in the /css folder as opposed to a path to an existing file to read.
Thanks for being patient with me :)
Cheers,
Warren
OK I spoke too soon :-P
So the example you gave is great, however I run into one small problem. When calling validateStylesheet on the FileService I get the following exception, but if I comment the check out for validating the file then it works & the file is saved to the /css folder.
is working on a reply...