AmazonS3Client را برای پارسپک بسازید
نمونهٔ .NET تنظیم ServiceURL، path-style و Region امضا را در یک AmazonS3Config متمرکز میکند. عملیات شبکه async است، Response و Stream بهدرستی Dispose میشوند و لینکهای موقت GET و PUT هم از همان Client ساخته میشوند.

برنامه هر عملیات را از یک زیرفرمان اجرا میکند و نتیجه را JSON برمیگرداند. فایل آزمایشی در Prefix مجزای tutorial/ قرار میگیرد.
اجرای مراحل از ابتدا باعث میشود خطای اتصال، مجوز و نبودن Object را از هم تمیز بدهید.
پیشنیاز و نصب SDK
اول کتابخانه همین پوشه را نصب کنید. بدون این قدم، نمونه اجرا نمیشود.
(cd examples/csharp && dotnet restore && dotnet build --no-restore)examples/csharp/
├── .env # پس از کپیکردن فایل نمونه ساخته میشود
├── ParspackS3.csproj # وابستگیهای .NET
└── Program.cs # Client و هفت فرمان مدیریت فایلساخت فایل .env
پنج مقدار را از پنل فضای ابری پارسپک کپی کنید. معنی هر متغیر و شکل معمول Endpoint در صفحه شروع آمده است.
upload با خطای امضا میخوابد.cp examples/.env.example examples/csharp/.envPARSPACK_S3_ENDPOINT=https://c123456.parspack.net
PARSPACK_S3_BUCKET=c123456
PARSPACK_S3_REGION=us-east-1
PARSPACK_S3_ACCESS_KEY=YOUR_ACCESS_KEY
PARSPACK_S3_SECRET_KEY=YOUR_SECRET_KEY| متغیر | چه چیزی در آن میگذارید | اگر اشتباه باشد |
|---|---|---|
PARSPACK_S3_ENDPOINT | آدرس HTTPS پنل، بدون / در انتها؛ شکل معمول https://c123456.parspack.net | Timeout یا خطای امضا |
PARSPACK_S3_BUCKET | نام باکت؛ اغلب با شناسه داخل Endpoint یکی است | NoSuchBucket |
PARSPACK_S3_REGION | فقط برای امضای Signature V4 است. اگر پنل Region نداد، us-east-1 را ثابت نگه دارید | SignatureDoesNotMatch |
PARSPACK_S3_ACCESS_KEY / SECRET_KEY | کلیدهای API از پنل؛ فقط روی سرور | AccessDenied یا خطای امضا |
فایل .env را Commit نکنید. Access Key و Secret Key فقط روی سرور میمانند؛ مرورگر فقط لینک کوتاهعمر میگیرد.
اتصال برنامه به فضای پارسپک
Client را یک بار با مقدارهای .env بسازید. همین شیء برای هر هفت فرمان کافی است.
ServiceURL میرود، نه فیلدی به نام Endpoint. AuthenticationRegion همان Region امضاست؛ اگر پنل چیزی نگفت us-east-1 را عوض نکنید. ForcePathStyle باید true باشد تا URL به شکل /bucket/key ساخته شود.GetObjectMetadataAsync است؛ مشخصات فایل را میدهد و خود فایل را نمیآورد. لینک موقت با GetPreSignedURLAsync ساخته میشود. Access Key و Secret Key فقط روی سرور میمانند. در ASP.NET Core همین Client را یک بار در DI ثبت کنید.Dictionary<string, string> env = LoadDotEnv();
string endpoint = Required(env, "PARSPACK_S3_ENDPOINT").TrimEnd('/');
string bucket = Required(env, "PARSPACK_S3_BUCKET");
var config = new AmazonS3Config
{
ServiceURL = endpoint,
AuthenticationRegion = Required(env, "PARSPACK_S3_REGION"),
ForcePathStyle = true,
MaxErrorRetry = 3,
};
var credentials = new BasicAWSCredentials(
Required(env, "PARSPACK_S3_ACCESS_KEY"),
Required(env, "PARSPACK_S3_SECRET_KEY")
);
using var s3 = new AmazonS3Client(credentials, config);آپلود فایل با PutObjectAsync
اولین فرمان سناریو: فایل محلی را با یک نام مشخص در باکت بگذارید.
./hello.txt است؛ داخل باکت با نام tutorial/hello.txt ذخیره میشود. اسلش پوشه واقعی نمیسازد، فقط بخشی از نام است. ETag اثر انگشت محتواست. اگر همین نام از قبل در باکت باشد، محتوای قبلی عوض میشود.PutObjectResponse response = await s3.PutObjectAsync(new PutObjectRequest
{
BucketName = bucket,
Key = "tutorial/hello.txt",
FilePath = "./hello.txt",
ContentType = "text/plain",
});
Console.WriteLine(response.ETag);| پارامتر | مثال | کاربرد |
|---|---|---|
Bucket | از .env | محل ذخیره Object |
Key | tutorial/hello.txt | نام کامل Object در S3 |
FilePath | ./hello.txt | فایل موجود روی سیستم |
ContentType | text/plain | نوع محتوای فایل |
(cd examples/csharp && dotnet run -- upload ./hello.txt tutorial/hello.txt)اگر tutorial/hello.txt از قبل وجود داشته باشد، Upload جدید همان Key را جایگزین میکند.
فهرست فایلها و مشخصات یک فایل
بعد از آپلود، اول ببینید فایل در فهرست هست؛ بعد حجم و نوع را بدون دانلود بخوانید.
list tutorial/ خود فایل را نمیآورد؛ فقط نام، حجم و زمان تغییر فایلهایی را برمیگرداند که با این Prefix شروع میشوند. اگر آرایه خالی بود، یا آپلود انجام نشده یا Prefix را اشتباه نوشتهاید.head وقتی لازم است که فقط بخواهید بدانید فایل هست یا نه، یا حجم و نوعش چیست. اگر Key نباشد معمولاً 404 میگیرید. این فرمان را با دانلود عوض نکنید؛ بدنه فایل را منتقل نمیکند.string? continuationToken = null;
do
{
ListObjectsV2Response response = await s3.ListObjectsV2Async(new ListObjectsV2Request
{
BucketName = bucket,
Prefix = "tutorial/",
ContinuationToken = continuationToken,
});
foreach (S3Object item in response.S3Objects)
{
Console.WriteLine($"${item.Key} — ${item.Size}");
}
continuationToken = response.IsTruncated == true ? response.NextContinuationToken : null;
} while (continuationToken is not null);(cd examples/csharp && dotnet run -- list tutorial/)GetObjectMetadataResponse info = await s3.GetObjectMetadataAsync(new GetObjectMetadataRequest
{
BucketName = bucket,
Key = "tutorial/hello.txt",
});
Console.WriteLine(info.ContentLength);
Console.WriteLine(info.Headers.ContentType);(cd examples/csharp && dotnet run -- head tutorial/hello.txt)tutorial/ بگذارید، فقط فایلهایی که نامشان با این مقدار شروع میشود دیده میشوند.IsTruncated درست است، صفحه بعدی را دریافت کنید.دانلود روی سرور
فایل را از باکت بگیرید و روی دیسک همین برنامه بنویسید. این کار لینک برای کاربر نمیسازد.
using GetObjectResponse response = await s3.GetObjectAsync(new GetObjectRequest
{
BucketName = bucket,
Key = "tutorial/hello.txt",
});
await response.WriteResponseStreamToFileAsync(
"./downloads/hello.txt", false, CancellationToken.None);(cd examples/csharp && dotnet run -- download tutorial/hello.txt ./downloads/hello.txt)لینک موقت دانلود برای کاربر
این فرمان را با دانلود روی سرور قاطی نکنید. اینجا فایل روی دیسک شما نوشته نمیشود؛ فقط یک آدرس زماندار ساخته میشود. جریان کامل در صفحه شروع است.
<a href> بگذارید، یا با curl --output file.pdf "$URL" بگیرید. Header اضافه لازم نیست. 900 یعنی پانزده دقیقه؛ بعد از آن آدرس کار نمیکند.string downloadUrl = await s3.GetPreSignedURLAsync(new GetPreSignedUrlRequest
{
BucketName = bucket,
Key = objectKey,
Verb = HttpVerb.GET,
Expires = DateTime.UtcNow.AddMinutes(15),
});(cd examples/csharp && dotnet run -- presign-get tutorial/hello.txt 900)curl --output invoice.pdf "$SIGNED_DOWNLOAD_URL"لینک را کوتاه نگه دارید؛ بین ۱ ثانیه تا ۷ روز (۶۰۴۸۰۰ ثانیه). فقط همان Key را میخواند. لینک را فقط بعد از ورود کاربر و چک مجوز بسازید.
لینک موقت آپلود مستقیم
کاربر فایل را از مرورگر به باکت میفرستد. فایل از سرور شما رد نمیشود و کلید API هم به کاربر نمیرسد.
Content-Type را دقیقاً همان مقدار زمان ساخت لینک بگذارید؛ وگرنه معمولاً خطای امضا میگیرید. از مرورگر فقط وقتی کار میکند که CORS باکت سایت شما را مجاز کرده باشد؛ وگرنه از curl یا سرور خودتان استفاده کنید.string contentType = "text/plain";
string uploadUrl = await s3.GetPreSignedURLAsync(new GetPreSignedUrlRequest
{
BucketName = bucket,
Key = objectKey,
Verb = HttpVerb.PUT,
ContentType = contentType,
Expires = DateTime.UtcNow.AddMinutes(15),
});(cd examples/csharp && dotnet run -- presign-put tutorial/upload.txt text/plain 900)curl --request PUT \
--header 'Content-Type: text/plain' \
--upload-file ./hello.txt \
"$SIGNED_UPLOAD_URL"await fetch(signed.url, {
method: "PUT",
headers: { "Content-Type": signed.headers["Content-Type"] },
body: file,
});| Presigned GET | Presigned PUT | |
|---|---|---|
| Method | GET | PUT |
| ورودی امضا | Bucket، Key، انقضا | Bucket، Key، Content-Type، انقضا |
| جایگزین کدام فرمان سرور است | جایگزین download برای کاربر نهایی | جایگزین upload وقتی فایل نباید از سرور شما عبور کند |
اگر موقع ساخت لینک text/plain گذاشتهاید، هنگام ارسال هم باید همان را بفرستید. از مرورگر این کار فقط وقتی درست است که CORS باکت سایت شما را مجاز کرده باشد؛ وگرنه از curl یا سرور خودتان استفاده کنید.
حذف فایل با DeleteObjectAsync
نام را از باکت برمیدارد. لازم نیست اول دانلودش کنید. فایل روی سیستم شما دست نمیخورد.
await s3.DeleteObjectAsync(new DeleteObjectRequest
{
BucketName = bucket,
Key = "tutorial/hello.txt",
});(cd examples/csharp && dotnet run -- delete tutorial/hello.txt)StatusCode و ErrorCode را ثبت کنید
AmazonS3Exception جزئیات پاسخ سرویس را در اختیار شما میگذارد. نمونه آنها را روی stderr چاپ میکند تا خطای مجوز، امضا یا باکت با مشکل ارتباطی اشتباه نشود.
catch (AmazonS3Exception error)
{
Console.Error.WriteLine($"${error.ErrorCode}: ${error.Message}");
return 1;
}
catch (Exception error)
{
Console.Error.WriteLine($"${error.GetType().Name}: ${error.Message}");
return 1;
}| خطا | علت معمول | بررسی |
|---|---|---|
Local file not found | مسیر فایل محلی اشتباه است | مسیر را نسبت به پوشه examples/csharp بررسی کنید |
AccessDenied | کلید یا دسترسی Bucket کافی نیست | مقدارهای پنل و نوع دسترسی کاربر فضای ابری |
SignatureDoesNotMatch | امضای درخواست با تنظیمات یکی نیست | Slash انتهای Endpoint، Region، کلیدها و Content-Type در PUT |
NoSuchBucket | نام Bucket با مقدار پنل یکی نیست | PARSPACK_S3_BUCKET |
Timeout / connection | Endpoint در دسترس نیست یا HTTPS قطع است | آدرس پنل را بدون تغییر و بدون / انتها وارد کنید |
اجرای کامل همین سناریو
فایل همراه مستندات، Loader فایل .env، اعتبارسنجی ورودی، تشخیص Content-Type و خروجی JSON را یکجا دارد و Client را با using میبندد. اگر خروجی هر فرمان شبیه نمونههای بالا بود، میتوانید Key و مسیر را با نام فایلهای برنامه خودتان عوض کنید.
(cd examples/csharp && dotnet restore && dotnet build --no-restore)
cp examples/.env.example examples/csharp/.env
# مقدارهای .env را کامل کنید
printf 'hello ParsPack\n' > hello.txt
(cd examples/csharp && dotnet run -- upload ./hello.txt tutorial/hello.txt)
(cd examples/csharp && dotnet run -- list tutorial/)
(cd examples/csharp && dotnet run -- head tutorial/hello.txt)
(cd examples/csharp && dotnet run -- download tutorial/hello.txt ./downloads/hello.txt)
(cd examples/csharp && dotnet run -- presign-get tutorial/hello.txt 900)
(cd examples/csharp && dotnet run -- presign-put tutorial/upload.txt text/plain 900)
(cd examples/csharp && dotnet run -- delete tutorial/hello.txt)