【问题标题】:How to deal with input=file / IFormFile two-way binding in Razor Pages如何处理 Razor Pages 中的 input=file / IFormFile 双向绑定
【发布时间】:2020-07-15 07:54:29
【问题描述】:

我有一个实体,它具有 byte[] 以将徽标作为 varbinary 存储在数据库中。但是为了在 Razor 页面上使用这个模型,我扩展了它并添加了一个 IFormFile 属性来接收上传的文件。

public class Company
{ 
    public string Name { get; set; }
    public byte[] Logo { get; set; }
}
public class CompanyModel : Company 
{ 
    [DataType(DataType.Upload)]
    [FromForm(Name = "UploadedLogo")]
    public IFormFile UploadedLogo { get; set; }
}

在一个方法中,我从数据库中获取这家公司并相应地设置 IFormFile:

var response = await _companyService.GetByIdAsync(id);
if (response != null)
{
    if (response.Logo != null)
    {
        using (var stream = new MemoryStream(response.Logo))
        {
            var formFile = new FormFile(stream, 0, stream.Length, response.Name, response.Name);
            formFile.Headers = new HeaderDictionary()
            {
                new KeyValuePair<string, StringValues>("Content-Disposition", $"form-data; name=\"Company.UploadedLogo\"; filename=\"{response.Name}.png\""),
                new KeyValuePair<string, StringValues>("Content-Type", "image/png"),
            };
            response.UploadedLogo = formFile;
        }
    }

    return response;
}

UploadedLogo 已填充,我将其绑定在 Razor 页面上

<form method="post"
      enctype="multipart/form-data"
      data-ajax="true"
      data-ajax-method="post"
      data-ajax-begin="begin"
      data-ajax-complete="completed"
      data-ajax-failure="failed">
    ...
    <div class="form-group row"> 
        <div class="col-sm-2 text-right">
            <label asp-for="@Model.Company.Logo" class="col-form-label"></label>
        </div>
        <div class="col-sm-9">
            <input type="file" class="dropify" data-height="200"
                   asp-for="@Model.Company.UploadedLogo"
                   data-max-file-size="100K" data-allowed-file-extensions="png jpg jpeg" />
        </div>
    </div>
    ...
    <div class="form-group modal-actions">
        <input type="submit" class="btn btn-primary btn-icon-text btn-md btn-save-editing" value="Save" />
    </div>
</form>

顺便说一句,我使用Dropify 作为文件上传插件和jquery-ajax-unobtrusive 库来处理发布请求。这是post方法:

public async Task<CompanyModel> OnPostAsync(CompanyModel company)
{
    CompanyModel result = new CompanyModel();

    try
    {
        if (company.UploadedLogo != null)
            company.Logo = await company.UploadedLogo.GetBytes();

        var response = await _companyService.SaveAsync(company);
        if (response != null)
            result = response;
    }
    catch (Exception ex)
    {
        _Logger.LogException(ex);
    }

    return result;
}

现在是场景:

  • 当我添加一个新公司时,我输入公司名称并从我的计算机上浏览一个文件,然后保存数据。我可以看到在 post 请求中收到的公司模型中的 Uploaded logo,然后将其转换为 byte[] 并保存在数据库中。一切顺利。下面是提琴手捕获: Fiddler capture for INSERT
  • 当我尝试编辑公司时,问题开始。我打开公司,服务获取数据,将 byte[] 转换为 IFormFile,数据(名称 + 徽标)显示在表单上。我只是编辑名称,不要触摸徽标,让它保持原样,然后点击保存。此时,在 post request 中收到的 company model 中 Uploaded logo 为空。下面是提琴手捕获: Fiddler capture for UPDATE

我可以清楚地看到发布的请求捕获的差异。在编辑的情况下该文件不存在。但我不知道如何解决这个问题。我已经为此伤脑筋了一天,有人可以帮助我吗?

更新:还添加了 fiddler 捕获。

【问题讨论】:

  • 如果 UploadedLogo 从 UI 中为 null,则不应在数据库中更新它。
  • 我有这个解决方案,但这将是我的最后一个优先事项。因为我使用的是通用存储库模式,所以我不想做这样的事情。此外,我在很多其他页面上都有这种情况,因此不使用通用模式并专门为此目的在代码中添加 if else 不是我想要的。

标签: c# arrays asp.net-core razor-pages iformfile


【解决方案1】:

我知道这不是最好的解决方案,但我设法做到了。

我所做的是,我将图像字节转换为图像的 base64 数据 uri,并将 uri 保存在 input[hidden] 中。我还添加了另一个 input[hidden] 来保存用户是否更改了徽标的标志。当用户更改徽标时,我会使用上传图像的新 base64 数据 uri 和 flag=true 更新这些隐藏字段。并且如果用户不改变图像,则uri是相同的并且flag=false。现在保存时,我得到了 uri 字符串和标志。如果标志为真,我将 uri 转换为图像并将其保存在数据库中。

【讨论】:

    猜你喜欢
    • 2015-02-20
    • 2017-06-19
    • 2020-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-27
    • 1970-01-01
    相关资源
    最近更新 更多