You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Azure部署的ASP.NET CRUD项目中集成Azure Blob图片上传?

解决方案:ASP.NET MVC/API 集成 Azure Blob 存储实现图片上传与回显

一、前期准备

  • 登录Azure门户创建Blob存储账户,在「访问密钥」页面复制存储连接字符串
  • 给项目安装Azure.Storage.Blobs NuGet包

二、修改实体类与数据库

在现有实体(比如User)中添加存储Blob图片URL的字段:

public class User
{
    // 原有字段
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }

    // 新增图片URL字段
    public string ProfileImageUrl { get; set; }
}

然后通过EF迁移更新Azure SQL数据库:

Add-Migration AddProfileImageUrl
Update-Database

三、封装Blob操作工具类

写一个工具类处理Blob上传、删除逻辑,避免重复代码:

public class BlobHelper
{
    private readonly BlobServiceClient _blobServiceClient;
    private readonly string _containerName;

    public BlobHelper(string connectionString, string containerName)
    {
        _blobServiceClient = new BlobServiceClient(connectionString);
        _containerName = containerName;
        // 自动创建容器,设置公共读取权限(方便图片回显)
        _blobServiceClient.CreateBlobContainerIfNotExists(_containerName, PublicAccessType.Blob);
    }

    // 上传文件到Blob,返回可访问的URL
    public async Task<string> UploadBlobAsync(IFormFile file)
    {
        // 生成唯一文件名避免覆盖
        var blobName = $"{Guid.NewGuid()}_{file.FileName}";
        var blobContainerClient = _blobServiceClient.GetBlobContainerClient(_containerName);
        var blobClient = blobContainerClient.GetBlobClient(blobName);

        using var stream = file.OpenReadStream();
        await blobClient.UploadAsync(stream, new BlobHttpHeaders { ContentType = file.ContentType });

        return blobClient.Uri.ToString();
    }

    // 删除指定URL的Blob(配合删除用户操作)
    public async Task DeleteBlobAsync(string blobUrl)
    {
        var blobClient = new BlobClient(new Uri(blobUrl));
        await blobClient.DeleteIfExistsAsync();
    }
}

在Program.cs中注册这个工具类(用配置文件里的连接字符串):

builder.Services.AddSingleton<BlobHelper>(sp => 
    new BlobHelper(
        builder.Configuration["AzureBlob:ConnectionString"], 
        builder.Configuration["AzureBlob:ContainerName"]
    )
);

在appsettings.json中添加Blob配置:

"AzureBlob": {
  "ConnectionString": "你的Blob存储连接字符串",
  "ContainerName": "user-profile-images"
}

四、整合到现有CRUD流程

1. MVC场景(Create/Edit页面)

修改Create/Edit视图,添加文件上传控件:

<div class="form-group">
    <label asp-for="ProfileImage" class="control-label"></label>
    <input type="file" asp-for="ProfileImage" class="form-control" accept="image/*" />
    <span asp-validation-for="ProfileImage" class="text-danger"></span>
</div>

对应的ViewModel需要新增IFormFile字段:

public class UserCreateViewModel
{
    public string Name { get; set; }
    public string Email { get; set; }
    public IFormFile ProfileImage { get; set; }
}

在控制器的Post方法中,把上传逻辑和原有CRUD结合:

private readonly BlobHelper _blobHelper;
private readonly ApplicationDbContext _context;

public UsersController(ApplicationDbContext context, BlobHelper blobHelper)
{
    _context = context;
    _blobHelper = blobHelper;
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(UserCreateViewModel model)
{
    if (ModelState.IsValid)
    {
        string imageUrl = null;
        // 如果用户上传了图片,调用工具类上传到Blob
        if (model.ProfileImage != null && model.ProfileImage.Length > 0)
        {
            imageUrl = await _blobHelper.UploadBlobAsync(model.ProfileImage);
        }

        // 构造实体,把图片URL存入数据库
        var user = new User
        {
            Name = model.Name,
            Email = model.Email,
            ProfileImageUrl = imageUrl
        };

        _context.Add(user);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(model);
}

编辑用户时,如果上传了新图片,记得删除旧Blob:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, UserEditViewModel model)
{
    if (id != model.Id) return NotFound();

    if (ModelState.IsValid)
    {
        try
        {
            var user = await _context.Users.FindAsync(id);
            if (model.ProfileImage != null && model.ProfileImage.Length > 0)
            {
                // 删除旧图片(如果存在)
                if (!string.IsNullOrEmpty(user.ProfileImageUrl))
                {
                    await _blobHelper.DeleteBlobAsync(user.ProfileImageUrl);
                }
                // 上传新图片并更新URL
                user.ProfileImageUrl = await _blobHelper.UploadBlobAsync(model.ProfileImage);
            }

            // 更新其他字段
            user.Name = model.Name;
            user.Email = model.Email;

            _context.Update(user);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!UserExists(model.Id)) return NotFound();
            throw;
        }
        return RedirectToAction(nameof(Index));
    }
    return View(model);
}

2. API场景

在API接口中接收IFormFile参数,逻辑和MVC一致:

[HttpPost]
public async Task<IActionResult> CreateUser([FromForm] UserCreateDto dto)
{
    if (!ModelState.IsValid) return BadRequest(ModelState);

    string imageUrl = null;
    if (dto.ProfileImage != null)
    {
        imageUrl = await _blobHelper.UploadBlobAsync(dto.ProfileImage);
    }

    var user = new User
    {
        Name = dto.Name,
        Email = dto.Email,
        ProfileImageUrl = imageUrl
    };

    _context.Users.Add(user);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user);
}

五、图片回显实现

1. MVC页面

在列表页或详情页直接用img标签绑定数据库中的ProfileImageUrl:

<!-- 用户列表页示例 -->
@foreach (var user in Model)
{
    <tr>
        <td>
            @if (!string.IsNullOrEmpty(user.ProfileImageUrl))
            {
                <img src="@user.ProfileImageUrl" alt="用户头像" width="60" height="60" style="border-radius:50%" />
            }
            else
            {
                <span class="text-muted">无头像</span>
            }
        </td>
        <td>@user.Name</td>
        <td>@user.Email</td>
        <td>
            <a asp-action="Edit" asp-route-id="@user.Id">编辑</a> |
            <a asp-action="Delete" asp-route-id="@user.Id">删除</a>
        </td>
    </tr>
}

2. API前端调用

API返回的用户数据中包含ProfileImageUrl字段,前端直接用这个URL作为图片的src属性即可渲染。

六、部署注意事项

  • 在Azure Web App的「配置」-「应用设置」中添加Blob连接字符串(不要硬编码到代码里)
  • 确保Blob容器的访问级别设置为「Blob(仅限Blob匿名读取)」,否则图片无法直接访问
  • 如果需要限制图片访问,可以生成SAS令牌代替直接的Blob URL,简单场景用公共Blob即可

内容的提问来源于stack exchange,提问作者Kkye

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 15:00:54