Unexpected "An item with the same key has already been added" exception during import

Topics: Troubleshooting
Jun 27, 2014 at 11:20 AM
Edited Jun 27, 2014 at 3:00 PM
Hello. I would appreciate any help or advice with the following issue.

EDIT

In summary. During a custom import I am indirectly doing a ContentItem.Get for the admin user. This causes a permission check on the logged in admin user (same user), which creates an entry in the session dictionary. When flow returns to the original get request it goes bang with the exception "An item with the same key has already been added" because the permission check added an entry to the session dictionary and AFTER the if exists check for original ContentItem.Get.

END EDIT

I'm getting a "An item with the same key has already been added" exception thrown and I'm not sure how to resolve it. It occurs in DefaultContentManagerSession:Store. It is trying to insert a duplicate into the dictionary there.

I am doing an import of a single item in a recipe from the front end. The first addition to the map is an authentication check of the the user (admin) (not under my control) and the second is when I try to do a GetUser of admin or do a ResolveIdentity to get its contents item.

This is part of my custom import:
<Orchard>
  <Recipe>
    <Name>Generated by Orchard.ImportExport</Name>
    <Author>admin</Author>
    <ExportUtc>2014-06-26T20:03:40.3183565Z</ExportUtc>
  </Recipe>
  <MediaGallery>
    <GalleryCollectionToGallery GalleryCollectionPart="/alias=/User.UserName=admin" GalleryPart="/alias=Gallery\/98\/123/Identifier=992584cd7c2548e69007ab0f81e93ddc" />
  </MediaGallery>
</Orchard>
This is my code block:
ContentIdentity contentIdentity = new ContentIdentity(galleryCollectionToGalleryImportExportViewModel.GalleryCollectionPartIdentifier);
if (galleryCollectionToGalleryImportExportViewModel.GalleryCollectionPartIdentifier.Contains("User.UserName"))
{
    //IUser user = _membershipService.GetUser(contentIdentity.Get("User.UserName"));
    //galleryCollectionItem = user.ContentItem;

    galleryCollectionItem = _contentManager.ResolveIdentity(contentIdentity);
}
else
{
    galleryCollectionItem = _contentManager.ResolveIdentity(contentIdentity);
}
I originally tried to use _membershipService.GetUser(contentIdentity.Get("User.UserName")); but that chucked the error so, went back to resolve identity and manually changed the priority of UserResolverSelector to beat alias as it was returning my home page as the content item!

So I am trying to add the content id of admin user and Gallery to a custom table but need to resolve the ID's.

Problem is that it looks up admin twice and goes bang.

Many thanks in advance.
Jun 27, 2014 at 2:14 PM
OK, I have isolated the reason for my issue. This is the full call stack where the problem happens before the exception occurs.
    Orchard.Framework.dll!Orchard.ContentManagement.DefaultContentManager.Get(int id, Orchard.ContentManagement.VersionOptions options, Orchard.ContentManagement.QueryHints hints) Line 223    C#
    Orchard.Framework.dll!Orchard.ContentManagement.DefaultContentManager.Get(int id, Orchard.ContentManagement.VersionOptions options) Line 131    C#
    Orchard.Framework.dll!Orchard.ContentManagement.DefaultContentManager.Get(int id) Line 127  C#
    Orchard.Framework.dll!Orchard.Security.Providers.FormsAuthenticationService.GetAuthenticatedUser() Line 133 C#
    Orchard.Core.dll!Orchard.Core.Common.Handlers.CommonPartHandler.AssignCreatingOwner(Orchard.ContentManagement.Handlers.InitializingContentContext context, Orchard.Core.Common.Models.CommonPart part) Line 89  C#
    Orchard.Framework.dll!Orchard.ContentManagement.Handlers.ContentHandler.InlineStorageFilter<Orchard.Core.Common.Models.CommonPart>.Initializing(Orchard.ContentManagement.Handlers.InitializingContentContext context, Orchard.Core.Common.Models.CommonPart instance) Line 131 C#
    Orchard.Framework.dll!Orchard.ContentManagement.Handlers.StorageFilterBase<Orchard.Core.Common.Models.CommonPart>.Orchard.ContentManagement.Handlers.IContentStorageFilter.Initializing(Orchard.ContentManagement.Handlers.InitializingContentContext context) Line 32  C#
    Orchard.Framework.dll!Orchard.ContentManagement.Handlers.ContentHandler.Orchard.ContentManagement.Handlers.IContentHandler.Initializing(Orchard.ContentManagement.Handlers.InitializingContentContext context) Line 222 C#
    Orchard.Framework.dll!Orchard.ContentManagement.DefaultContentManager.New.AnonymousMethod__5(Orchard.ContentManagement.Handlers.IContentHandler handler) Line 119   C#
    Orchard.Framework.dll!Orchard.InvokeExtensions.Invoke<Orchard.ContentManagement.Handlers.IContentHandler>(System.Collections.Generic.IEnumerable<Orchard.ContentManagement.Handlers.IContentHandler> events, System.Action<Orchard.ContentManagement.Handlers.IContentHandler> dispatch, Orchard.Logging.ILogger logger) Line 17    C#
    Orchard.Framework.dll!Orchard.ContentManagement.DefaultContentManager.New(string contentType) Line 119  C#
>   Orchard.Framework.dll!Orchard.ContentManagement.DefaultContentManager.Get(int id, Orchard.ContentManagement.VersionOptions options, Orchard.ContentManagement.QueryHints hints) Line 219    C#
    Orchard.Framework.dll!Orchard.ContentManagement.DefaultContentManager.Get(int id, Orchard.ContentManagement.VersionOptions options) Line 131    C#
    Orchard.Framework.dll!Orchard.ContentManagement.DefaultContentQuery.Slice.AnonymousMethod__2(Orchard.ContentManagement.Records.ContentItemVersionRecord x) Line 163 C#
    [External Code] 
    Orchard.Framework.dll!Orchard.Utility.Extensions.ReadOnlyCollectionExtensions.ToReadOnlyCollection<Orchard.ContentManagement.ContentItem>(System.Collections.Generic.IEnumerable<Orchard.ContentManagement.ContentItem> enumerable) Line 8  C#
    Orchard.Framework.dll!Orchard.ContentManagement.DefaultContentQuery.Slice(int skip, int count) Line 161 C#
    Orchard.Framework.dll!Orchard.ContentManagement.DefaultContentQuery.ContentQuery<Orchard.ContentManagement.ContentItem>.Orchard.ContentManagement.IContentQuery<T>.List() Line 262  C#
    Orchard.Framework.dll!Orchard.ContentManagement.ContentQueryExtensions.List<Orchard.ContentManagement.ContentItem>(Orchard.ContentManagement.IContentQuery query) Line 138  C#
    Orchard.Users.dll!Orchard.Users.Services.UserResolverSelector.ResolveIdentity(Orchard.ContentManagement.ContentIdentity identity) Line 33   C#
    Orchard.Framework.dll!Orchard.ContentManagement.DefaultContentManager.ResolveIdentity(Orchard.ContentManagement.ContentIdentity contentIdentity) Line 580   C#
    DU.MediaGallery.dll!DU.MediaGallery.Services.GalleryService.ImportGalleryCollectionToGallery(DU.MediaGallery.ViewModels.GalleryCollectionToGalleryImportExportViewModel galleryCollectionToGalleryImportExportViewModel) Line 519   C#
Now let me annotate:

Orchard.Framework.dll!Orchard.ContentManagement.DefaultContentManager.Get(int id, Orchard.ContentManagement.VersionOptions options, Orchard.ContentManagement.QueryHints hints) Line 219
            // return item if obtained earlier in session
            if (session.RecallVersionRecordId(versionRecord.Id, out contentItem)) {
                if (options.IsDraftRequired && versionRecord.Published) {
                    return BuildNewVersion(contentItem);
                }
                return contentItem;
            }

            // allocate instance and set record property
            contentItem = New(versionRecord.ContentItemRecord.ContentType.Name);
            contentItem.VersionRecord = versionRecord;

            // store in session prior to loading to avoid some problems with simple circular dependencies
            session.Store(contentItem);
The content item (admin user) is not found in all the checks so does a new to get the content item.
    Orchard.Framework.dll!Orchard.Security.Providers.FormsAuthenticationService.GetAuthenticatedUser() Line 133 C#
This causes an authentication check which in turn does a get for the content item. The same block of code above. Again this is not found so does a new. On returning the content item it is stored in the session.

When the call stack unwinds and my original request for a new content item is completed store fails because it was added by the permissions check and it is AFTER the check to see if it already exists in the dictionary.

What daft thing am I doing wrong here please?
Mar 18, 2015 at 4:49 PM
I am having a similar issue....I have a Web Api Controller and am trying to get information about a user. When I try and get the contentItem for a User account
ex. var myUser = _contentManager.Get(408);
and that user is logged in, I get the following exception "An item with the same key has already been added."
This is coming from the following code in the DefaultContentManagerSession.cs
    public void Store(ContentItem item) {
            _itemByVersionRecordId.Add(item.VersionRecord.Id, item);

            // is it the Published version ?
            if (item.VersionRecord.Latest && item.VersionRecord.Published)
            {
                _publishedItemsByContentRecordId[item.Id] = item;
            }
    }
The code is trying to add the item a second time (and the VersionRecordId is already the key for the first time the user was added). Again, this only happens when the user with this Id is logged in. If the user logs out, I can get the ContentItem without issue.