Skip to content

Unable to delete an attachment with special characters in the file name #830

@IvanTheBearable

Description

@IvanTheBearable

Category

  • Bug

Describe the bug

Attempting to delete a SharePoint list attachment with special characters in the file name produces an exception.

Steps to reproduce

Given:

  • spListItem = a PnP.Core.Model.SharePoint.ListItem
  • The list item has an attachment with a name like FW You're all booked to fly XXX on 27 Feb 2020, reference XXXX.eml (note the ' in "You're")
await spListItem.EnsurePropertiesAsync(p => p.AttachmentFiles);
IAttachment[] oldAttachmentsArray = spListItem.AttachmentFiles.AsRequested().ToArray();
for (int i=oldAttachmentsArray.Count()-1; i>=0; i--)
{
    try
    {
        await oldAttachmentsArray[i].DeleteAsync();
    } catch (Exception ex)
    {
        LogException(ex, "Failed to delete existing attachment '{AttachmentName}'.", new object[1] { oldAttachmentsArray[i].FileName });
    }
}

The DeleteAsync above produces a "SharePoint Rest service exception" with an error code of "Microsoft.SharePoint.Client.InvalidClientQueryException" and the message "The expression "web/lists/getbyid(guid'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')/items(244)/attachmentfiles/getbyfilename('FW You're all booked to fly XXX on 27 Feb 2020, reference XXXX.eml')" is not valid."

Expected behavior

The attachment should be deleted without an exception.

Environment details (development & target environment)

  • SDK version: [PnP.Core 1.6.0]
  • OS: [Windows 10]
  • SDK used in: [Azure Function App]
  • Framework: [.NET Core v3.1]
  • Browser(s): [N/A]
  • Tooling: [Visual Studio 2022]
  • Additional details: The more context you can provide, the easier it is (and therefore quicker) to help.

Additional context

I did some searching of the repo in hopes of spotting an easy fix, or at least saving someone a bit of time. I'm guessing the problem starts in src/sdk/PnP.Core/Model/SharePoint/Core/Internal/Attachment.cs:

[SharePointType("SP.Attachment", Uri = "_api/web/lists/getbyid(guid'{List.Id}')/items({Parent.Id})/attachmentfiles/getbyfilename('{Id}')", LinqGet = "_api/web/lists/getbyid(guid'{List.Id}')/items({Parent.Id})/attachmentfiles")]
    internal sealed class Attachment : BaseDataModel<IAttachment>, IAttachment

There needs to be some mechanism to encode that {Id}. AttachmentCollection.FileUpload (which works) encodes the file name like this:

var encodedServerFileName = WebUtility.UrlEncode(newFile.FileName.Replace("'", "''")).Replace("+", "%20");
string fileCreateRequest = $"_api/web/lists/getbyid(guid'{{List.Id}}')/items({{Parent.Id}})/attachmentfiles/addusingpath(decodedUrl='{encodedServerFileName}')";

Metadata

Metadata

Assignees

Labels

area: model 📐Related to the core SDK modelsbugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions