上传图片到 .NET Core 2.1 API






4.98/5 (18投票s)
本文介绍如何从您的 .NET core 2.1 API 上传和检索图像。
引言
本文介绍如何从您的 .NET Core 2.1 API 上传和检索图像。可以使用在浏览器上显示的图像名称来访问图像。
我还在 Github 上传了代码。希望您觉得本指南有用。
背景
- 我使用 Postman 发送
POST
请求,任何替代方案都应该可以。 - .NET Core 2.1 兼容的 Visual Studio
- 了解依赖注入
- 对
Task<>
和async
方法有良好的了解 - 对 API 控制器有一些了解(我从很高的层面解释了,这足以理解发生了什么)
代码
首先,让我们创建一个新的 ASP .NET Core Web 应用程序并选择 API 项目,并将其命名为 ImageUploader
。
项目结构
以下是我用来创建项目的项目结构。我将解释每个文件的作用
Handler 文件夹有一个 ImageHandler.cs,ImageController
使用它,通过将处理程序注入到控制器中来调用程序的图像写入组件。
ImageWriter
是一个 .NET Core 2.1 类库项目,负责将图像写入磁盘。我们将图像写入我创建的 wwwroot/images 文件夹中。
WriterHelper.cs 是 ImageWriter
使用的辅助类,用于验证给定文件是否为图像文件。
代码
我想从下面的 WriterHelper.cs 开始,这是验证上传文件的代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ImageWriter.Helper
{
public class WriterHelper
{
public enum ImageFormat
{
bmp,
jpeg,
gif,
tiff,
png,
unknown
}
public static ImageFormat GetImageFormat(byte[] bytes)
{
var bmp = Encoding.ASCII.GetBytes("BM"); // BMP
var gif = Encoding.ASCII.GetBytes("GIF"); // GIF
var png = new byte[] { 137, 80, 78, 71 }; // PNG
var tiff = new byte[] { 73, 73, 42 }; // TIFF
var tiff2 = new byte[] { 77, 77, 42 }; // TIFF
var jpeg = new byte[] { 255, 216, 255, 224 }; // jpeg
var jpeg2 = new byte[] { 255, 216, 255, 225 }; // jpeg canon
if (bmp.SequenceEqual(bytes.Take(bmp.Length)))
return ImageFormat.bmp;
if (gif.SequenceEqual(bytes.Take(gif.Length)))
return ImageFormat.gif;
if (png.SequenceEqual(bytes.Take(png.Length)))
return ImageFormat.png;
if (tiff.SequenceEqual(bytes.Take(tiff.Length)))
return ImageFormat.tiff;
if (tiff2.SequenceEqual(bytes.Take(tiff2.Length)))
return ImageFormat.tiff;
if (jpeg.SequenceEqual(bytes.Take(jpeg.Length)))
return ImageFormat.jpeg;
if (jpeg2.SequenceEqual(bytes.Take(jpeg2.Length)))
return ImageFormat.jpeg;
return ImageFormat.unknown;
}
}
}
现在,是时候设置实际的 ImageWriter.cs 了,但在那之前,让我们填充 IImageWriter.cs 接口,以便我们可以在处理程序中注入它。
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
namespace ImageWriter.Interface
{
public interface IImageWriter
{
Task<string> UploadImage(IFormFile file);
}
}
现在是 ImageWriter.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using ImageWriter.Helper;
using ImageWriter.Interface;
using Microsoft.AspNetCore.Http;
namespace ImageWriter.Classes
{
public class ImageWriter : IImageWriter
{
public async Task<string> UploadImage(IFormFile file)
{
if (CheckIfImageFile(file))
{
return await WriteFile(file);
}
return "Invalid image file";
}
/// <summary>
/// Method to check if file is image file
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
private bool CheckIfImageFile(IFormFile file)
{
byte[] fileBytes;
using (var ms = new MemoryStream())
{
file.CopyTo(ms);
fileBytes = ms.ToArray();
}
return WriterHelper.GetImageFormat(fileBytes) != WriterHelper.ImageFormat.unknown;
}
/// <summary>
/// Method to write file onto the disk
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public async Task<string> WriteFile(IFormFile file)
{
string fileName;
try
{
var extension = "." + file.FileName.Split('.')[file.FileName.Split('.').Length - 1];
fileName = Guid.NewGuid().ToString() + extension; //Create a new Name
//for the file due to security reasons.
var path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot\\images", fileName);
using (var bits = new FileStream(path, FileMode.Create))
{
await file.CopyToAsync(bits);
}
}
catch (Exception e)
{
return e.Message;
}
return fileName;
}
}
}
这里的主要逻辑是首先检查文件。如果它是图像文件,我们出于安全原因使用新名称写入它,并将名称返回给用户(我们也可以使用持久性存储将文件名映射到新名称,以便稍后检索)。如果文件无效,我们会返回一条错误消息。
完成主要功能后,让我们转到处理程序,在那里我们将传入的请求定向到适当的方法。
using System.Threading.Tasks;
using ImageWriter.Interface;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace ImageUploader.Handler
{
public interface IImageHandler
{
Task<IActionResult> UploadImage(IFormFile file);
}
public class ImageHandler : IImageHandler
{
private readonly IImageWriter _imageWriter;
public ImageHandler(IImageWriter imageWriter)
{
_imageWriter = imageWriter;
}
public async Task<IActionResult> UploadImage(IFormFile file)
{
var result = await _imageWriter.UploadImage(file);
return new ObjectResult(result);
}
}
}
在这里,ImageWriter
被注入到处理程序中。
是时候配置控制器了
using System.Threading.Tasks;
using ImageUploader.Handler;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace ImageUploader.Controllers
{
[Route("api/image")]
public class ImagesController : Controller
{
private readonly IImageHandler _imageHandler;
public ImagesController(IImageHandler imageHandler)
{
_imageHandler = imageHandler;
}
/// <summary>
/// Uplaods an image to the server.
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public async Task<IActionResult> UploadImage(IFormFile file)
{
return await _imageHandler.UploadImage(file);
}
}
}
最后,我们必须配置 Startup.cs 以通知应用程序使用 wwwroot/images 文件夹。我们可以通过在我们的 Configure
方法中添加一行简单的代码来实现这一点。
我们还可以通过指定上面屏幕截图注释区域内的路径来引用 wwwroot 文件夹之外的文件。在上面的屏幕截图中,注释的配置将使用主项目中的名为 StaticFiles 的文件夹。
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
//Use this to set path of files outside the wwwroot folder
//app.UseStaticFiles(new StaticFileOptions
//{
// FileProvider = new PhysicalFileProvider(
// Path.Combine(Directory.GetCurrentDirectory(), "StaticFiles")),
// RequestPath = "/StaticFiles"
//});
app.UseStaticFiles(); //letting the application know that we need access to wwwroot folder.
app.UseHttpsRedirection();
app.UseMvc();
}
最后,我们在 ConfigureServices
方法中为 ImageHandler
和 ImageWriter
添加依赖注入。
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddTransient<IImageHandler, ImageHandler>();
services.AddTransient<ImageWriter.Interface.IImageWriter,
ImageWriter.Classes.ImageWriter>();
}
结果
让我们启动它并使用 postman 发送一个图像文件
确保将 key 设置为 file,将 value 设置为有效的图像文件。还要确保请求是 POST
请求。正如我们从上面的屏幕截图中所看到的,我们得到了上传文件的名称。让我们检查它是否确实在 images 文件夹中
现在我们如何检索它?这非常简单,我们所要做的就是调用 http://ipaddress:port/images/filename。
就是这样!一个用于上传和检索图像的 API。您可以使用上面的链接将图像直接嵌入到 HTML <img src =””>
标签中。