首页 > 解决方案 > Angular 8 上传图像文件(jpg 等) - 第二种方法

问题描述

我想将 Angular 8 与 Asp.Net Web Api 一起使用来上传图像文件并将其存储到 SQL Server 数据库表中,其中图像列定义为 varbinary(max)。

注意:我可以使用 ASP.Net Web 表单来做到这一点 - 它添加了图像,我可以相应地显示它。(我在下面添加了图像代码)。所以我试图模仿网络表单上传,但使用 Angular 作为前端。

为了在 Angular 8 中上传文件,我使用了以下建议:https ://www.academind.com/learn/angular/snippets/angular-image-upload-made-easy/

我将选定的图像文件作为二进制文件发送到 Web Api。

单击按钮后,我在服务器端收到错误消息。http://localhost:50454/Api/Image/AddImage/的 Http 失败响应:500 内部服务器错误。身体是:[对象对象]

我能够使选定的图像文件出现在页面上。


这是所有的代码。注意:为简单起见,并未包含所有代码。

我的 SQL 服务器表定义 - 其中图像被定义为 varbinary:

 CREATE TABLE [dbo].[tblImages]
 (  
    [ImageId]                [int] IDENTITY(1,1) NOT NULL,
    [ImageData]              [varbinary](max) NOT NULL
  CONSTRAINT [PK_Image] PRIMARY KEY CLUSTERED   
 (  
  [ImageId] ASC  
 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
 ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]  
 ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]  

我的 SQL 服务器插入存储过程:

CREATE procedure [dbo].[InsertImages]

@ImageData      varbinary(max)

AS
BEGIN 
    SET NOCOUNT ON; 
    INSERT INTO dbo.tblImages (
      ImageData  )
    VALUES (
      @ImageData ) 
   RETURN 0
END

角 html:

<input type="file" (change)="onFileChanged($event)">
<img [src]="imgURL" height="200" *ngIf="imgURL">

Angular 组件方法代码:

onFileChanged(event) {
   // Get the file selected.
   const selectedFile = event.target.files[0];

   // To display the selected image before deciding to upload it.
   let reader = new FileReader();

   // Gets a 'base64' representation of an image.
   reader.readAsDataURL(event.target.files[0]);

   reader.onload = (event2) => {
     // Sets the html <img> tag to the image.
     this.imgURL = reader.result;
   };

  // Call the service to use the web api to add the image to the database.
  this.imageService.addImage(selectedFile).subscribe(
    event => {
      console.log(event);
    });
}

我的 Angular Image 服务方法:

private data: any;
// The Asp.Net Web Api endpoint.
url = "http://localhost:50454/Api/Image";

addImage(image: Image): Observable<Image> {
  const httpOptions = {
    headers: new HttpHeaders({ "Content-Type": "application/json" })
  };

  // Call the ASP.NET 2.1 MVC Web API.
  return this.http
    .post<Image>(this.url + "/AddImage/", image, httpOptions)
    .pipe(
      tap(data => data),
      catchError(this.handleError)
    );
}

我的角度模型类:

export class Image {
    ImageData: Binary[];   <--- Is this correct?
}

我的 Asp.Net Web Api 数据模型:

namespace PrototypeWebApi2.Models
{
    public class Image
    {
        public byte[] ImageData { get; set; }   <--- Is this correct?
    }
}

我的 Asp.Net Web Api 方法:

    [HttpPost]
    [Route("AddImage")]
    public IHttpActionResult PostImage(Image data)
    {
        try
        {
            return Ok(dataaccesslayer.AddImage(data));
        }
        catch (Exception)
        {
            throw;
        }
    }

我的 Asp.Net Web Api 数据访问层方法:

  public int AddImage(Image image)
    {
        try
        {
            using (SqlConnection con = new SqlConnection(connectionString))
            {
                SqlCommand cmd = new SqlCommand("InsertImages", con);
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.Clear();

                cmd.Parameters.AddWithValue("@ImageData", image.ImageData);

                con.Open();
                cmd.ExecuteNonQuery();
                con.Close();
            }

            return 1;
        }
        catch
        {
            throw;
        }
    }

我的 Asp.Net Web 表单代码可以上传图像文件并且工作正常:

HTML:

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="AdminPage.aspx.cs" Inherits="Media.Admin.AdminPage" %>

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <h1>Administration</h1>
    <hr />
    <h3>Add Image:</h3>

    <table>
        <tr>
            <td><asp:Label ID="LabelAddImageFile" runat="server">Image File:</asp:Label></td>
            <td>
                <asp:FileUpload ID="MediaUploadFile" runat="server" />
                <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" Text="* Image file path required." ControlToValidate="MediaUploadFile" SetFocusOnError="true" Display="Dynamic"></asp:RequiredFieldValidator>
            </td>
        </tr>
    </table>
    <p></p>

    <asp:Button ID="AddMediaButton" runat="server" Text="Add Media" OnClick="AddMediaButton_Click" CausesValidation="true" CssClass="btn btn-primary"/>
    <asp:Label ID="LabelAddStatus" runat="server" Text=""></asp:Label>
    <p></p>
</asp:Content>

后面的代码:

    protected void AddMediaButton_Click(object sender, EventArgs e)
    {
        string strErrorMessage = "";
        string fileExtension = "";
        int fileSize = 0;
        Boolean fileOK = false;

        // Get the image file that was selected. References the ASP.Net control.
        HttpPostedFile postedFile = MediaUploadFile.PostedFile;

        fileExtension = Path.GetExtension(fileName).ToLower();

        ....

        if (fileOK)
        {
            Stream stream = postedFile.InputStream;

            BinaryReader binaryReader = new BinaryReader(stream);

            // Read the file into a array of bytes.
            Byte[] bytes = binaryReader.ReadBytes((int)stream.Length);

            try
            {
                ....

                cmd.Parameters.Add("@ImageData", SqlDbType.VarBinary).Value = bytes;
                cmd.ExecuteNonQuery();

                .....
            }
            catch (Exception ex)
            {

            }
            finally
            {
                dbFunc.CloseDB();
            }
        }
        else
        {
            ....
        }
    }

标签: sqlsql-serverangular

解决方案


您从中提取的对象类型event.target.files[0]是,File但是您将其传递给addImage需要类型的函数Image。我猜它假设是any这样 Typescript 不会捕捉到不匹配的情况。

接下来,在将文件发布到服务器时,我总是使用FormData对象获得更好的成功。

uploadFiles(files: File[]) {
    const formData = new FormData();

    files.forEach(file => {
        formData.append(file.name, file, file.name);
    });

    return this.http.post(`/api/files`, formData);
}

Angular 的 HttpClient 服务会自动为此设置Content-Type: multipart/form-data标头。

然后在 WebApi 端,我System.Web.HttpContext.Current.Request.Files用来访问实际的文件二进制文件。从那里你应该能够使用某种形式IO.Stream来保存文件。

希望这可以帮助!


推荐阅读