I am trying to programmatically upload files to the media-section of umbraco backend, and set tags on them.
I have added a property which is of the type "Tags" with property type alias "tags" to the mediatype "Image", and tested that I can manually add tags by typing in the field. This works fine.
Now, I want to set tags programmatically using the following code:
var buffer = await file.ReadAsByteArrayAsync();
var stream = new MemoryStream(buffer);
var mediaService = Services.MediaService;
var image = mediaService.CreateMedia(filename, parentId, "Image");
image.SetValue("umbracoFile", filename, stream);
mediaService.Save(image);
// Tags
List<string> separators = new List<string>() { "¤¤" };
var tags = tagString.Split(separators.ToArray(), StringSplitOptions.RemoveEmptyEntries).Take(3);
image.SetTags("tags", tags, true);
id = image.Id;
What happens is that the tables cmsTags and cmsTagRelationship gets populated, but no tags show up when I look at the properties of the image.
It also seems like it breaks the editor. I can no longer type new tags in the field and have them turn the blue color. They just stay black, and if I type something else, it replaces what I typed before.
I have tried various combinations of calling .Save before and after setting tags on the images, and also getting the image to a new variable after the save, setting tags, and saving again.
I have checked the tables cmsTags, cmsTagRelationShip, cmsPropertyType, cmsDataType and cmsContentType, and the tags I create programmatically looks just like the ones create manually.
It would seem that I am missing something.
Should the tags be created before setting them on the images (and
how?).
Ps. Just tried adding a row to cmsTags, and one to cmsTagRelationship.
This behaves just like the ones created programmatically (i.e. not showing up in the property on the image).
I then tried a simple experiment, just retrieving an existing image, setting tags, and saving. That doesn't seem to work either.
I still get the "Error: Duplicates in a repeater are not allowed. Repeater: tag in model.value" in the console when viewing the image in the backoffice.
The code has now been boiled down to:
var service = Services.MediaService;
var item = service.GetById(2120);
var tags = new List<string>() { "Test1", "Test2", "Test3" };
item.SetTags("tags", tags, true);
service.Save(item);
I still get the rows in cmsTags and cmsTagRelationship, and everything seems to look OK in the DB.
I'm thinking the next step is to compare the entire DB to see how it looks when 1) Tags are entered manually. 2) Tag are created with SetTags.
There must be something that SetTags doesn't do, which is needed for the tags to show correctly.
Kinda weird, though, that SetTags doesn't look up the storage type set on the data type, and just use that as default.
But I can live with using the overload. Maybe even look up the selected storage type on the datatype, and pass that back in the overload (if somebody changes the storag type in the future).
I know this is a little old, but I was looking at the code, shouldn't the storage group "default" use what is set in the control, instead of default? Am I missing something?
Setting tags on images via IContentBase
I am trying to programmatically upload files to the media-section of umbraco backend, and set tags on them.
I have added a property which is of the type "Tags" with property type alias "tags" to the mediatype "Image", and tested that I can manually add tags by typing in the field. This works fine.
Now, I want to set tags programmatically using the following code:
What happens is that the tables cmsTags and cmsTagRelationship gets populated, but no tags show up when I look at the properties of the image.
It also seems like it breaks the editor. I can no longer type new tags in the field and have them turn the blue color. They just stay black, and if I type something else, it replaces what I typed before.
I have tried various combinations of calling .Save before and after setting tags on the images, and also getting the image to a new variable after the save, setting tags, and saving again.
I have checked the tables cmsTags, cmsTagRelationShip, cmsPropertyType, cmsDataType and cmsContentType, and the tags I create programmatically looks just like the ones create manually.
It would seem that I am missing something.
BR. Kenneth.
Ps. Just tried adding a row to cmsTags, and one to cmsTagRelationship. This behaves just like the ones created programmatically (i.e. not showing up in the property on the image).
Hi Kenneth,
Not sure if you just haven't pasted the code but are you saving the IContent after calling SetTags?
Thanks,
Tom
Hi Tom,
Yes, I have tried various combinations of:
Create image, save, set tags
Create image, set tags, save
Create image, save, get image to new variable, set tags, save.
This is the code as it is presently (not working):
BR. Kenneth.
Do you get any errors in the browser console when viewing the page in Umbraco?
Thanks,
Tom
Aha! Yes. I get the following:
BR. Kenneth.
The things I am trying to tag on are things like product number, brand, type etc., given as parts of the filename.
I loop through a lot of images, so some of them are bound to have the same brand, f.ex.
I'm not sure if the same term exists more than once in the filename, but maybe I should do a distinct on my "tags" variable?
Hi Kenneth,
Maybe trying calling .Distinct() on the tags array when passing it to SetTags. That error message makes it sound as if there are duplicate tags.
Thanks,
Tom
Thanks, I will try that. Seems likely.
BR. Kenneth.
Calling Distinct() made no difference.
I then tried a simple experiment, just retrieving an existing image, setting tags, and saving. That doesn't seem to work either.
I still get the "Error: Duplicates in a repeater are not allowed. Repeater: tag in model.value" in the console when viewing the image in the backoffice.
The code has now been boiled down to:
I still get the rows in cmsTags and cmsTagRelationship, and everything seems to look OK in the DB.
I'm thinking the next step is to compare the entire DB to see how it looks when 1) Tags are entered manually. 2) Tag are created with SetTags.
There must be something that SetTags doesn't do, which is needed for the tags to show correctly.
BR. Kenneth.
BR. Kenneth.
OK, so I did the following:
1) Start with no tags on any image.
2) Add a tag to an image.
3) Make a DB backup.
4) Add a second tag to the image.
5) Write down which tables had new/updated data
6) Make a DB backup.
7) Add a third tag programmatically using .SetTags().
8) Compare DB after third tag was added.
So, all the same tables were touched, which were the following:
Contentversion - update versiondate field
Contentxml - update xml field
Cmspropertydata - update datanvarchar field
Cmstag - insert 1 row
Cmstagrelationship - insert 1 row
Cmscacheinstruction - insert 1 row
Umbracolog - insert 1 row
Umbraconode - update 2 rows
Umbracoserver - update 2 rows
However, the one called cmsPropertyData looks different after adding the third tag using SetTags.
Looks like the data is no longer represented as a JSON array, but just a comma-separated list of the tags. Could this be a bug?
I noticed in the Tags data type, that I can choose between "JSON" and "CSV in "Storage Type".
Mine is set to "JSON".
Could it be that SetTags does not take this into account, and just always store it as CSV, whereas manually entering tags will honor "Storage Type"?
BR. Kenneth.
Hi Kenneth,
Looking at the Umbraco source it looks like by default it sets the storage type to CSV when calling SetTags()
https://github.com/umbraco/Umbraco-CMS/blob/bfbc6595fb165063fde40f653fbc27feb112a858/src/Umbraco.Core/Models/ContentExtensions.cs#L691
However there does seem to be an overload for this extension method which allows you to specify the storage type:
https://github.com/umbraco/Umbraco-CMS/blob/bfbc6595fb165063fde40f653fbc27feb112a858/src/Umbraco.Core/Models/ContentExtensions.cs#L706
Hope this helps.
Thanks,
Tom
Yup. That did the trick :-)
Kinda weird, though, that SetTags doesn't look up the storage type set on the data type, and just use that as default.
But I can live with using the overload. Maybe even look up the selected storage type on the datatype, and pass that back in the overload (if somebody changes the storag type in the future).
Thanks a lot for all your help!
BR. Kenneth.
No worries, glad you have it all working now :)
I know this is a little old, but I was looking at the code, shouldn't the storage group "default" use what is set in the control, instead of default? Am I missing something?
is working on a reply...