From 45db4f5dc7bb907fbab02b382506272a08d62999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E6=AD=A3?= Date: Tue, 14 Oct 2025 21:04:27 +0800 Subject: [PATCH 1/3] Expose the details of batch uploads and transfer the process of controlling progress to the caller # Conflicts: # Minio/ApiEndpoints/ObjectOperations.cs --- Minio/ApiEndpoints/IObjectOperations.cs | 65 ++++++++++++++++++- Minio/ApiEndpoints/ObjectOperations.cs | 14 ++-- Minio/Credentials/WebIdentityProvider.cs | 2 +- Minio/DataModel/Args/BucketArgs.cs | 8 +-- .../Args/CompleteMultipartUploadArgs.cs | 12 ++-- Minio/DataModel/Args/CopyObjectArgs.cs | 2 +- Minio/DataModel/Args/CopyObjectRequestArgs.cs | 2 +- Minio/DataModel/Args/EncryptionArgs.cs | 4 +- Minio/DataModel/Args/GetObjectArgs.cs | 2 +- .../DataModel/Args/NewMultipartUploadArgs.cs | 2 +- .../Args/NewMultipartUploadCopyArgs.cs | 4 +- .../Args/NewMultipartUploadPutArgs.cs | 2 +- Minio/DataModel/Args/ObjectArgs.cs | 8 +-- .../Args/ObjectConditionalQueryArgs.cs | 12 ++-- Minio/DataModel/Args/ObjectVersionArgs.cs | 4 +- Minio/DataModel/Args/ObjectWriteArgs.cs | 10 +-- .../DataModel/Args/PresignedGetObjectArgs.cs | 2 +- Minio/DataModel/Args/PutObjectArgs.cs | 20 +++--- Minio/DataModel/Args/PutObjectPartArgs.cs | 4 +- Minio/DataModel/Args/RemoveObjectsArgs.cs | 2 +- Minio/DataModel/Args/RemoveUploadArgs.cs | 2 +- Minio/DataModel/Args/RequestArgs.cs | 4 +- .../DataModel/Args/SelectObjectContentArgs.cs | 2 +- .../DataModel/Args/SetBucketLifecycleArgs.cs | 2 +- Minio/DataModel/Args/SetBucketTagsArgs.cs | 2 +- .../Args/SetObjectLockConfigurationArgs.cs | 2 +- .../DataModel/Args/SetObjectRetentionArgs.cs | 2 +- Minio/DataModel/Args/SetObjectTagsArgs.cs | 2 +- Minio/DataModel/Args/SetVersioningArgs.cs | 4 +- Minio/DataModel/Args/StatObjectArgs.cs | 2 +- 30 files changed, 134 insertions(+), 71 deletions(-) diff --git a/Minio/ApiEndpoints/IObjectOperations.cs b/Minio/ApiEndpoints/IObjectOperations.cs index 2dc35fdd90..6326ca9a38 100644 --- a/Minio/ApiEndpoints/IObjectOperations.cs +++ b/Minio/ApiEndpoints/IObjectOperations.cs @@ -1,4 +1,4 @@ -/* +/* * MinIO .NET Library for Amazon S3 Compatible Cloud Storage, * (C) 2017-2021 MinIO, Inc. * @@ -358,4 +358,67 @@ IAsyncEnumerable ListIncompleteUploadsEnumAsync(ListIncompleteUploadsArg /// When object is not found /// When configuration XML provided is invalid Task RemoveObjectTagsAsync(RemoveObjectTagsArgs args, CancellationToken cancellationToken = default); + + /// + /// Upload object part to bucket for particular uploadId + /// + /// + /// PutObjectArgs encapsulates bucket name, object name, upload id, part number, object data(body), + /// Headers, SSE Headers + /// + /// Optional cancellation token to cancel the operation + /// + /// This boolean parameter differentiates single part file upload and + /// multi part file upload as this function is shared by both. + /// + /// + /// When access or secret key is invalid + /// When bucket name is invalid + /// When object name is invalid + /// When bucket is not found + /// The file stream has been disposed + /// The file stream cannot be read from + /// The file stream is currently in a read operation + /// For encrypted PUT operation, Access is denied if the key is wrong + Task PutObjectSinglePartAsync(PutObjectArgs args, CancellationToken cancellationToken = default, bool singleFile = false); + + + /// + /// Remove object with matching uploadId from bucket + /// + /// RemoveUploadArgs Arguments Object which encapsulates bucket, object names, upload Id + /// Optional cancellation token to cancel the operation + /// + Task RemoveUploadAsync(RemoveUploadArgs args, CancellationToken cancellationToken); + + /// + /// Start a new multi-part upload request + /// + /// + /// NewMultipartUploadPutArgs arguments object encapsulating bucket name, object name, Headers, SSE + /// Headers + /// + /// Optional cancellation token to cancel the operation + /// + /// When access or secret key is invalid + /// When bucket name is invalid + /// When object name is invalid + /// When bucket is not found + /// When object is not found + /// For encrypted copy operation, Access is denied if the key is wrong + Task NewMultipartUploadAsync(NewMultipartUploadPutArgs args, CancellationToken cancellationToken = default); + + /// + /// Internal method to complete multi part upload of object to server. + /// + /// CompleteMultipartUploadArgs Arguments object with bucket name, object name, upload id, Etags + /// Optional cancellation token to cancel the operation + /// + /// When access or secret key is invalid + /// When bucket name is invalid + /// When object name is invalid + /// When bucket is not found + /// When object is not found + /// For encrypted copy operation, Access is denied if the key is wrong + Task CompleteMultipartUploadAsync(CompleteMultipartUploadArgs args, CancellationToken cancellationToken); } diff --git a/Minio/ApiEndpoints/ObjectOperations.cs b/Minio/ApiEndpoints/ObjectOperations.cs index 0bd6afe237..146eabcb36 100644 --- a/Minio/ApiEndpoints/ObjectOperations.cs +++ b/Minio/ApiEndpoints/ObjectOperations.cs @@ -1,4 +1,4 @@ -/* +/* * MinIO .NET Library for Amazon S3 Compatible Cloud Storage, * (C) 2017-2021 MinIO, Inc. * @@ -974,7 +974,7 @@ CancellationToken cancellationToken /// RemoveUploadArgs Arguments Object which encapsulates bucket, object names, upload Id /// Optional cancellation token to cancel the operation /// - private async Task RemoveUploadAsync(RemoveUploadArgs args, CancellationToken cancellationToken) + public async Task RemoveUploadAsync(RemoveUploadArgs args, CancellationToken cancellationToken) { args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); @@ -1006,7 +1006,7 @@ private async Task RemoveUploadAsync(RemoveUploadArgs args, CancellationToken ca /// The file stream cannot be read from /// The file stream is currently in a read operation /// For encrypted PUT operation, Access is denied if the key is wrong - private async Task PutObjectSinglePartAsync( + public async Task PutObjectSinglePartAsync( PutObjectArgs args, CancellationToken cancellationToken = default, bool singleFile = false @@ -1112,12 +1112,12 @@ private async Task> PutObjectPartAsync( ETag = etag, Size = (long)expectedReadSize, }; - etags[partNumber] = etag; if (!dataToCopy.IsEmpty) progressReport.TotalBytesTransferred += dataToCopy.Length; if (args.ObjectSize != -1) progressReport.Percentage = (int)(100 * partNumber / partCount); args.Progress?.Report(progressReport); + etags[partNumber] = etag; } // This shouldn't happen where stream size is known. @@ -1242,7 +1242,7 @@ private async Task MultipartCopyUploadAsync( /// When bucket is not found /// When object is not found /// For encrypted copy operation, Access is denied if the key is wrong - private async Task NewMultipartUploadAsync( + public async Task NewMultipartUploadAsync(( NewMultipartUploadPutArgs args, CancellationToken cancellationToken = default ) @@ -1273,7 +1273,7 @@ private async Task NewMultipartUploadAsync( /// When bucket is not found /// When object is not found /// For encrypted copy operation, Access is denied if the key is wrong - private async Task NewMultipartUploadAsync( + public async Task NewMultipartUploadAsync( NewMultipartUploadCopyArgs args, CancellationToken cancellationToken = default ) @@ -1339,7 +1339,7 @@ CancellationToken cancellationToken /// When bucket is not found /// When object is not found /// For encrypted copy operation, Access is denied if the key is wrong - private async Task CompleteMultipartUploadAsync( + public async Task CompleteMultipartUploadAsync( CompleteMultipartUploadArgs args, CancellationToken cancellationToken ) diff --git a/Minio/Credentials/WebIdentityProvider.cs b/Minio/Credentials/WebIdentityProvider.cs index ed8e05b756..7622dec9d2 100644 --- a/Minio/Credentials/WebIdentityProvider.cs +++ b/Minio/Credentials/WebIdentityProvider.cs @@ -1,4 +1,4 @@ -/* +/* * MinIO .NET Library for Amazon S3 Compatible Cloud Storage, * (C) 2021 MinIO, Inc. * diff --git a/Minio/DataModel/Args/BucketArgs.cs b/Minio/DataModel/Args/BucketArgs.cs index 3170e6ee6c..4b95923a3f 100644 --- a/Minio/DataModel/Args/BucketArgs.cs +++ b/Minio/DataModel/Args/BucketArgs.cs @@ -1,4 +1,4 @@ -/* +/* * MinIO .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2020, 2021 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,9 +25,9 @@ public abstract class BucketArgs : RequestArgs public bool IsBucketCreationRequest { get; set; } - internal string BucketName { get; set; } + public string BucketName { get; set; } - internal IDictionary Headers { get; set; } = new Dictionary(StringComparer.Ordinal); + public IDictionary Headers { get; set; } = new Dictionary(StringComparer.Ordinal); public T WithBucket(string bucket) { @@ -48,7 +48,7 @@ public virtual T WithHeaders(IDictionary headers) return (T)this; } - internal virtual void Validate() + public virtual void Validate() { Utils.ValidateBucketName(BucketName); } diff --git a/Minio/DataModel/Args/CompleteMultipartUploadArgs.cs b/Minio/DataModel/Args/CompleteMultipartUploadArgs.cs index 67609466b8..eb7a0913cc 100644 --- a/Minio/DataModel/Args/CompleteMultipartUploadArgs.cs +++ b/Minio/DataModel/Args/CompleteMultipartUploadArgs.cs @@ -19,9 +19,9 @@ namespace Minio.DataModel.Args; -internal class CompleteMultipartUploadArgs : ObjectWriteArgs +public class CompleteMultipartUploadArgs : ObjectWriteArgs { - internal CompleteMultipartUploadArgs() + public CompleteMultipartUploadArgs() { RequestMethod = HttpMethod.Post; } @@ -42,10 +42,10 @@ internal CompleteMultipartUploadArgs(MultipartCopyUploadArgs args) .ToDictionary(item => item.Key, item => item.First().Value, StringComparer.Ordinal); } - internal string UploadId { get; set; } + public string UploadId { get; set; } internal Dictionary ETags { get; set; } - internal override void Validate() + public override void Validate() { base.Validate(); if (string.IsNullOrWhiteSpace(UploadId)) @@ -54,13 +54,13 @@ internal override void Validate() throw new InvalidOperationException(nameof(ETags) + " dictionary cannot be empty."); } - internal CompleteMultipartUploadArgs WithUploadId(string uploadId) + public CompleteMultipartUploadArgs WithUploadId(string uploadId) { UploadId = uploadId; return this; } - internal CompleteMultipartUploadArgs WithETags(IDictionary etags) + public CompleteMultipartUploadArgs WithETags(IDictionary etags) { if (etags?.Count > 0) ETags = new Dictionary(etags); diff --git a/Minio/DataModel/Args/CopyObjectArgs.cs b/Minio/DataModel/Args/CopyObjectArgs.cs index 7b266b54df..4d57a5e4a1 100644 --- a/Minio/DataModel/Args/CopyObjectArgs.cs +++ b/Minio/DataModel/Args/CopyObjectArgs.cs @@ -41,7 +41,7 @@ public CopyObjectArgs() internal DateTime RetentionUntilDate { get; set; } internal bool ObjectLockSet { get; set; } - internal override void Validate() + public override void Validate() { Utils.ValidateBucketName(BucketName); if (SourceObject is null) diff --git a/Minio/DataModel/Args/CopyObjectRequestArgs.cs b/Minio/DataModel/Args/CopyObjectRequestArgs.cs index cdf45a54f4..9f47368390 100644 --- a/Minio/DataModel/Args/CopyObjectRequestArgs.cs +++ b/Minio/DataModel/Args/CopyObjectRequestArgs.cs @@ -170,7 +170,7 @@ public CopyObjectRequestArgs WithObjectLockRetentionDate(DateTime untilDate) return this; } - internal override void Validate() + public override void Validate() { Utils.ValidateBucketName(BucketName); //Object name can be same as that of source. if (SourceObject is null) throw new InvalidOperationException(nameof(SourceObject) + " has not been assigned."); diff --git a/Minio/DataModel/Args/EncryptionArgs.cs b/Minio/DataModel/Args/EncryptionArgs.cs index fb68315507..ea8daaff8e 100644 --- a/Minio/DataModel/Args/EncryptionArgs.cs +++ b/Minio/DataModel/Args/EncryptionArgs.cs @@ -1,4 +1,4 @@ -/* +/* * MinIO .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2021 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ namespace Minio.DataModel.Args; public abstract class EncryptionArgs : ObjectArgs where T : EncryptionArgs { - internal IServerSideEncryption SSE { get; set; } + public IServerSideEncryption SSE { get; set; } public T WithServerSideEncryption(IServerSideEncryption sse) { diff --git a/Minio/DataModel/Args/GetObjectArgs.cs b/Minio/DataModel/Args/GetObjectArgs.cs index c7204ebf71..e564b12067 100644 --- a/Minio/DataModel/Args/GetObjectArgs.cs +++ b/Minio/DataModel/Args/GetObjectArgs.cs @@ -34,7 +34,7 @@ public GetObjectArgs() internal string FileName { get; private set; } internal bool OffsetLengthSet { get; set; } - internal override void Validate() + public override void Validate() { base.Validate(); if (CallBack is null && string.IsNullOrEmpty(FileName)) diff --git a/Minio/DataModel/Args/NewMultipartUploadArgs.cs b/Minio/DataModel/Args/NewMultipartUploadArgs.cs index 7f12159dbf..82d187aff8 100644 --- a/Minio/DataModel/Args/NewMultipartUploadArgs.cs +++ b/Minio/DataModel/Args/NewMultipartUploadArgs.cs @@ -19,7 +19,7 @@ namespace Minio.DataModel.Args; -internal class NewMultipartUploadArgs : ObjectWriteArgs +public class NewMultipartUploadArgs : ObjectWriteArgs where T : NewMultipartUploadArgs { internal NewMultipartUploadArgs() diff --git a/Minio/DataModel/Args/NewMultipartUploadCopyArgs.cs b/Minio/DataModel/Args/NewMultipartUploadCopyArgs.cs index 29ec7b40c9..f224fe4ad0 100644 --- a/Minio/DataModel/Args/NewMultipartUploadCopyArgs.cs +++ b/Minio/DataModel/Args/NewMultipartUploadCopyArgs.cs @@ -19,7 +19,7 @@ namespace Minio.DataModel.Args; -internal class NewMultipartUploadCopyArgs : NewMultipartUploadArgs +public class NewMultipartUploadCopyArgs : NewMultipartUploadArgs { internal bool ReplaceMetadataDirective { get; set; } internal bool ReplaceTagsDirective { get; set; } @@ -27,7 +27,7 @@ internal class NewMultipartUploadCopyArgs : NewMultipartUploadArgs +public class NewMultipartUploadPutArgs : NewMultipartUploadArgs { internal override HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuilder requestMessageBuilder) { diff --git a/Minio/DataModel/Args/ObjectArgs.cs b/Minio/DataModel/Args/ObjectArgs.cs index c09bdc6713..6952533804 100644 --- a/Minio/DataModel/Args/ObjectArgs.cs +++ b/Minio/DataModel/Args/ObjectArgs.cs @@ -1,4 +1,4 @@ -/* +/* * MinIO .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,8 +23,8 @@ public abstract class ObjectArgs : BucketArgs { protected const string S3ZipExtractKey = "X-Minio-Extract"; - internal string ObjectName { get; set; } - internal ReadOnlyMemory RequestBody { get; set; } + public string ObjectName { get; set; } + public ReadOnlyMemory RequestBody { get; set; } public T WithObject(string obj) { @@ -38,7 +38,7 @@ public T WithRequestBody(ReadOnlyMemory data) return (T)this; } - internal override void Validate() + public override void Validate() { base.Validate(); Utils.ValidateObjectName(ObjectName); diff --git a/Minio/DataModel/Args/ObjectConditionalQueryArgs.cs b/Minio/DataModel/Args/ObjectConditionalQueryArgs.cs index ea17fdf8b3..caf026d94c 100644 --- a/Minio/DataModel/Args/ObjectConditionalQueryArgs.cs +++ b/Minio/DataModel/Args/ObjectConditionalQueryArgs.cs @@ -1,4 +1,4 @@ -/* +/* * MinIO .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2020, 2021 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,12 +21,12 @@ namespace Minio.DataModel.Args; public abstract class ObjectConditionalQueryArgs : ObjectVersionArgs where T : ObjectConditionalQueryArgs { - internal string MatchETag { get; set; } - internal string NotMatchETag { get; set; } - internal DateTime ModifiedSince { get; set; } - internal DateTime UnModifiedSince { get; set; } + public string MatchETag { get; set; } + public string NotMatchETag { get; set; } + public DateTime ModifiedSince { get; set; } + public DateTime UnModifiedSince { get; set; } - internal override void Validate() + public override void Validate() { base.Validate(); if (!string.IsNullOrEmpty(MatchETag) && !string.IsNullOrEmpty(NotMatchETag)) diff --git a/Minio/DataModel/Args/ObjectVersionArgs.cs b/Minio/DataModel/Args/ObjectVersionArgs.cs index da1ee425b2..271bb6897c 100644 --- a/Minio/DataModel/Args/ObjectVersionArgs.cs +++ b/Minio/DataModel/Args/ObjectVersionArgs.cs @@ -1,4 +1,4 @@ -/* +/* * MinIO .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ namespace Minio.DataModel.Args; public abstract class ObjectVersionArgs : EncryptionArgs where T : ObjectVersionArgs { - internal string VersionId { get; set; } + public string VersionId { get; set; } public T WithVersionId(string vid) { diff --git a/Minio/DataModel/Args/ObjectWriteArgs.cs b/Minio/DataModel/Args/ObjectWriteArgs.cs index da8ce8a461..0f277a5b2d 100644 --- a/Minio/DataModel/Args/ObjectWriteArgs.cs +++ b/Minio/DataModel/Args/ObjectWriteArgs.cs @@ -1,4 +1,4 @@ -/* +/* * MinIO .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2020, 2021 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,10 +22,10 @@ namespace Minio.DataModel.Args; public abstract class ObjectWriteArgs : ObjectConditionalQueryArgs where T : ObjectWriteArgs { - internal Tagging ObjectTags { get; set; } - internal ObjectRetentionConfiguration Retention { get; set; } - internal bool? LegalHoldEnabled { get; set; } - internal string ContentType { get; set; } + public Tagging ObjectTags { get; set; } + public ObjectRetentionConfiguration Retention { get; set; } + public bool? LegalHoldEnabled { get; set; } + public string ContentType { get; set; } public T WithTagging(Tagging tagging) { diff --git a/Minio/DataModel/Args/PresignedGetObjectArgs.cs b/Minio/DataModel/Args/PresignedGetObjectArgs.cs index b993a04250..e34c6fdcaf 100644 --- a/Minio/DataModel/Args/PresignedGetObjectArgs.cs +++ b/Minio/DataModel/Args/PresignedGetObjectArgs.cs @@ -29,7 +29,7 @@ public PresignedGetObjectArgs() internal int Expiry { get; set; } internal DateTime? RequestDate { get; set; } - internal override void Validate() + public override void Validate() { base.Validate(); if (!Utils.IsValidExpiry(Expiry)) diff --git a/Minio/DataModel/Args/PutObjectArgs.cs b/Minio/DataModel/Args/PutObjectArgs.cs index 8b416496e1..dbcb2c52f4 100644 --- a/Minio/DataModel/Args/PutObjectArgs.cs +++ b/Minio/DataModel/Args/PutObjectArgs.cs @@ -30,7 +30,7 @@ public PutObjectArgs() ContentType = "application/octet-stream"; } - internal PutObjectArgs(PutObjectPartArgs args) + public PutObjectArgs(PutObjectPartArgs args) { RequestMethod = HttpMethod.Put; BucketName = args.BucketName; @@ -44,14 +44,14 @@ internal PutObjectArgs(PutObjectPartArgs args) UploadId = args.UploadId; } - internal string UploadId { get; private set; } - internal int PartNumber { get; set; } - internal string FileName { get; set; } - internal long ObjectSize { get; set; } - internal Stream ObjectStreamData { get; set; } - internal IProgress Progress { get; set; } + public string UploadId { get; private set; } + public int PartNumber { get; set; } + public string FileName { get; set; } + public long ObjectSize { get; set; } + public Stream ObjectStreamData { get; set; } + public IProgress Progress { get; set; } - internal override void Validate() + public override void Validate() { base.Validate(); // Check atleast one of filename or stream are initialized @@ -152,13 +152,13 @@ public override PutObjectArgs WithHeaders(IDictionary headers) return this; } - internal PutObjectArgs WithUploadId(string id = null) + public PutObjectArgs WithUploadId(string id = null) { UploadId = id; return this; } - internal PutObjectArgs WithPartNumber(int num) + public PutObjectArgs WithPartNumber(int num) { PartNumber = num; return this; diff --git a/Minio/DataModel/Args/PutObjectPartArgs.cs b/Minio/DataModel/Args/PutObjectPartArgs.cs index 653cfc7c02..cd7acf1043 100644 --- a/Minio/DataModel/Args/PutObjectPartArgs.cs +++ b/Minio/DataModel/Args/PutObjectPartArgs.cs @@ -18,14 +18,14 @@ namespace Minio.DataModel.Args; -internal class PutObjectPartArgs : PutObjectArgs +public class PutObjectPartArgs : PutObjectArgs { public PutObjectPartArgs() { RequestMethod = HttpMethod.Put; } - internal override void Validate() + public override void Validate() { base.Validate(); if (string.IsNullOrWhiteSpace(UploadId)) diff --git a/Minio/DataModel/Args/RemoveObjectsArgs.cs b/Minio/DataModel/Args/RemoveObjectsArgs.cs index 688e232629..09c0bbc699 100644 --- a/Minio/DataModel/Args/RemoveObjectsArgs.cs +++ b/Minio/DataModel/Args/RemoveObjectsArgs.cs @@ -73,7 +73,7 @@ public RemoveObjectsArgs WithObjects(IList names) return this; } - internal override void Validate() + public override void Validate() { // Skip object name validation. Utils.ValidateBucketName(BucketName); diff --git a/Minio/DataModel/Args/RemoveUploadArgs.cs b/Minio/DataModel/Args/RemoveUploadArgs.cs index 60a4a10351..b8b5879aad 100644 --- a/Minio/DataModel/Args/RemoveUploadArgs.cs +++ b/Minio/DataModel/Args/RemoveUploadArgs.cs @@ -31,7 +31,7 @@ public RemoveUploadArgs WithUploadId(string id) return this; } - internal override void Validate() + public override void Validate() { base.Validate(); if (string.IsNullOrEmpty(UploadId)) diff --git a/Minio/DataModel/Args/RequestArgs.cs b/Minio/DataModel/Args/RequestArgs.cs index 3dbe3764ae..65ac9171a7 100644 --- a/Minio/DataModel/Args/RequestArgs.cs +++ b/Minio/DataModel/Args/RequestArgs.cs @@ -1,4 +1,4 @@ -/* +/* * MinIO .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ public abstract class RequestArgs // RequestMethod will be the HTTP Method for request variable, // which is of type HttpRequestMessage. // Will be one of the types: - HEAD, GET, PUT, DELETE. etc. - internal HttpMethod RequestMethod { get; set; } + public HttpMethod RequestMethod { get; set; } internal virtual HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuilder requestMessageBuilder) { diff --git a/Minio/DataModel/Args/SelectObjectContentArgs.cs b/Minio/DataModel/Args/SelectObjectContentArgs.cs index 660b8d583c..85eb62bcb6 100644 --- a/Minio/DataModel/Args/SelectObjectContentArgs.cs +++ b/Minio/DataModel/Args/SelectObjectContentArgs.cs @@ -30,7 +30,7 @@ public SelectObjectContentArgs() selectOptions = new SelectObjectOptions(); } - internal override void Validate() + public override void Validate() { base.Validate(); if (string.IsNullOrEmpty(selectOptions.Expression)) diff --git a/Minio/DataModel/Args/SetBucketLifecycleArgs.cs b/Minio/DataModel/Args/SetBucketLifecycleArgs.cs index 086f5f2382..916333db76 100644 --- a/Minio/DataModel/Args/SetBucketLifecycleArgs.cs +++ b/Minio/DataModel/Args/SetBucketLifecycleArgs.cs @@ -49,7 +49,7 @@ internal override HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuild return requestMessageBuilder; } - internal override void Validate() + public override void Validate() { base.Validate(); if (BucketLifecycle is null || BucketLifecycle.Rules.Count == 0) diff --git a/Minio/DataModel/Args/SetBucketTagsArgs.cs b/Minio/DataModel/Args/SetBucketTagsArgs.cs index 8d10451e95..972be5d479 100644 --- a/Minio/DataModel/Args/SetBucketTagsArgs.cs +++ b/Minio/DataModel/Args/SetBucketTagsArgs.cs @@ -51,7 +51,7 @@ internal override HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuild return requestMessageBuilder; } - internal override void Validate() + public override void Validate() { base.Validate(); if (BucketTags is null || BucketTags.Tags.Count == 0) diff --git a/Minio/DataModel/Args/SetObjectLockConfigurationArgs.cs b/Minio/DataModel/Args/SetObjectLockConfigurationArgs.cs index bfe40bc7a3..1ed7a2615e 100644 --- a/Minio/DataModel/Args/SetObjectLockConfigurationArgs.cs +++ b/Minio/DataModel/Args/SetObjectLockConfigurationArgs.cs @@ -35,7 +35,7 @@ public SetObjectLockConfigurationArgs WithLockConfiguration(ObjectLockConfigurat return this; } - internal override void Validate() + public override void Validate() { base.Validate(); if (LockConfiguration is null) diff --git a/Minio/DataModel/Args/SetObjectRetentionArgs.cs b/Minio/DataModel/Args/SetObjectRetentionArgs.cs index 75af87b33d..2364a35d92 100644 --- a/Minio/DataModel/Args/SetObjectRetentionArgs.cs +++ b/Minio/DataModel/Args/SetObjectRetentionArgs.cs @@ -33,7 +33,7 @@ public SetObjectRetentionArgs() internal ObjectRetentionMode Mode { get; set; } internal DateTime RetentionUntilDate { get; set; } - internal override void Validate() + public override void Validate() { base.Validate(); if (RetentionUntilDate.Equals(default)) diff --git a/Minio/DataModel/Args/SetObjectTagsArgs.cs b/Minio/DataModel/Args/SetObjectTagsArgs.cs index 093ad6fc9a..3f848e6a7e 100644 --- a/Minio/DataModel/Args/SetObjectTagsArgs.cs +++ b/Minio/DataModel/Args/SetObjectTagsArgs.cs @@ -46,7 +46,7 @@ internal override HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuild return requestMessageBuilder; } - internal override void Validate() + public override void Validate() { base.Validate(); if (ObjectTags is null || ObjectTags.Tags.Count == 0) diff --git a/Minio/DataModel/Args/SetVersioningArgs.cs b/Minio/DataModel/Args/SetVersioningArgs.cs index 0da8086076..846485e3bb 100644 --- a/Minio/DataModel/Args/SetVersioningArgs.cs +++ b/Minio/DataModel/Args/SetVersioningArgs.cs @@ -1,4 +1,4 @@ -/* +/* * MinIO .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,7 +30,7 @@ public SetVersioningArgs() CurrentVersioningStatus = VersioningStatus.Off; } - internal override void Validate() + public override void Validate() { Utils.ValidateBucketName(BucketName); if (CurrentVersioningStatus > VersioningStatus.Suspended) diff --git a/Minio/DataModel/Args/StatObjectArgs.cs b/Minio/DataModel/Args/StatObjectArgs.cs index d92876cfb7..e59951b85c 100644 --- a/Minio/DataModel/Args/StatObjectArgs.cs +++ b/Minio/DataModel/Args/StatObjectArgs.cs @@ -39,7 +39,7 @@ internal override HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuild return requestMessageBuilder; } - internal override void Validate() + public override void Validate() { base.Validate(); if (!string.IsNullOrEmpty(NotMatchETag) && !string.IsNullOrEmpty(MatchETag)) From 20781db9c0e826469c5b6864b375454351d1de8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E6=AD=A3?= Date: Thu, 25 Sep 2025 16:17:21 +0800 Subject: [PATCH 2/3] Support the use of streaming to upload empty files # Conflicts: # Minio/DataModel/Args/PutObjectArgs.cs --- Minio/DataModel/Args/PutObjectArgs.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Minio/DataModel/Args/PutObjectArgs.cs b/Minio/DataModel/Args/PutObjectArgs.cs index dbcb2c52f4..59bfc11bc2 100644 --- a/Minio/DataModel/Args/PutObjectArgs.cs +++ b/Minio/DataModel/Args/PutObjectArgs.cs @@ -47,7 +47,7 @@ public PutObjectArgs(PutObjectPartArgs args) public string UploadId { get; private set; } public int PartNumber { get; set; } public string FileName { get; set; } - public long ObjectSize { get; set; } + public long ObjectSize { get; set; } = -1; public Stream ObjectStreamData { get; set; } public IProgress Progress { get; set; } @@ -67,6 +67,9 @@ public override void Validate() " should be set."); if (!string.IsNullOrWhiteSpace(FileName)) Utils.ValidateFile(FileName); + // Check object size when using stream data + if (ObjectStreamData is not null && ObjectSize == -1) + throw new InvalidOperationException($"{nameof(ObjectSize)} must be set"); Populate(); } From a3f7956e0a1ff92686594bcf1631a99946062e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E6=AD=A3?= Date: Tue, 14 Oct 2025 21:38:51 +0800 Subject: [PATCH 3/3] Fix formatting issues and expose batch upload details --- Minio.Functional.Tests/FunctionalTest.cs | 2 +- Minio/ApiEndpoints/ObjectOperations.cs | 22 ++++++++++++------- Minio/HttpRequestMessageBuilder.cs | 28 ++++++++++++------------ 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/Minio.Functional.Tests/FunctionalTest.cs b/Minio.Functional.Tests/FunctionalTest.cs index f511c64ded..a684096390 100644 --- a/Minio.Functional.Tests/FunctionalTest.cs +++ b/Minio.Functional.Tests/FunctionalTest.cs @@ -1537,7 +1537,7 @@ internal static async Task RemoveObjects_Test3(IMinioClient minio) var tasks = new Task[count * 2]; List objectsList = []; await Setup_WithLock_Test(minio, bucketName).ConfigureAwait(false); - for (var i = 0; i < count * 2; ) + for (var i = 0; i < count * 2;) { tasks[i++] = PutObject_Task( minio, diff --git a/Minio/ApiEndpoints/ObjectOperations.cs b/Minio/ApiEndpoints/ObjectOperations.cs index 146eabcb36..56bd257cf5 100644 --- a/Minio/ApiEndpoints/ObjectOperations.cs +++ b/Minio/ApiEndpoints/ObjectOperations.cs @@ -1225,27 +1225,33 @@ private async Task MultipartCopyUploadAsync( // Complete multi part upload _ = await CompleteMultipartUploadAsync(completeMultipartUploadArgs, cancellationToken) .ConfigureAwait(false); - } - - /// - /// Start a new multi-part upload request - /// +/* 项目“Minio(netstandard2.0)”的未合并的更改 +在此之前: /// /// NewMultipartUploadPutArgs arguments object encapsulating bucket name, object name, Headers, SSE /// Headers /// /// Optional cancellation token to cancel the operation /// +在此之后: + /// +*/ + + } + + /// + /// Start a new multi-part upload request + /// + /// /// When access or secret key is invalid /// When bucket name is invalid /// When object name is invalid /// When bucket is not found /// When object is not found /// For encrypted copy operation, Access is denied if the key is wrong - public async Task NewMultipartUploadAsync(( + public async Task NewMultipartUploadAsync( NewMultipartUploadPutArgs args, - CancellationToken cancellationToken = default - ) + CancellationToken cancellationToken = default) { args?.Validate(); var requestMessageBuilder = await this.CreateRequest(args).ConfigureAwait(false); diff --git a/Minio/HttpRequestMessageBuilder.cs b/Minio/HttpRequestMessageBuilder.cs index 93419a0c7c..78f9dc3343 100644 --- a/Minio/HttpRequestMessageBuilder.cs +++ b/Minio/HttpRequestMessageBuilder.cs @@ -75,22 +75,22 @@ public HttpRequestMessage Request switch (key) { case "content-type": - { - val ??= "application/octet-stream"; - try { - request.Content.Headers.ContentType = new MediaTypeHeaderValue(val); + val ??= "application/octet-stream"; + try + { + request.Content.Headers.ContentType = new MediaTypeHeaderValue(val); + } + catch + { + var success = request.Content.Headers.TryAddWithoutValidation( + ContentTypeKey, + val + ); + } + + break; } - catch - { - var success = request.Content.Headers.TryAddWithoutValidation( - ContentTypeKey, - val - ); - } - - break; - } case "content-length": request.Content.Headers.ContentLength = Convert.ToInt32(