CKEditor 和 C# Web API,使用简单的上传插件上传图片

Posted

技术标签:

【中文标题】CKEditor 和 C# Web API,使用简单的上传插件上传图片【英文标题】:CKEditor and C# Web API, upload image with simple upload plugin 【发布时间】:2021-12-01 12:44:27 【问题描述】:

在我的项目中,我使用 CKEditor WYSWYG 包为我的网站制作 html 内容。 可以插入图片并直接从包发送到服务器。

两天以来,我试图弄清楚如何将发送的图像从 Angular 前端捕获到 Web API,但仍然没有成功。

我将 .Net6 和 Angular 12 与 CKEditor 5 一起使用。

public async Task<ActionResult<string>> AddPostPhoto(IFormFile photo)

    try
    
        System.Console.WriteLine(Request.ContentType);

        var folderDirectory = $"\\Photos\\PostPhotos";
        var path = Path.Combine("Photos/PostPhotos", "fileName.jpg");

        var memoryStream = new MemoryStream();
        await Request.Body.CopyToAsync(memoryStream);
        
        System.Console.WriteLine(Request.HttpContext.Request.ContentLength);
        System.Console.WriteLine(Request.Form.Keys);

        if (!Directory.Exists(folderDirectory))
        
            Directory.CreateDirectory(folderDirectory);
        

        await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
        
            memoryStream.WriteTo(fs);
        

        return Ok(new  Url = path );
     
    catch(Exception exception)
    
        return BadRequest(exception.Message);
    

【问题讨论】:

【参考方案1】:

我终于找到了一个可行的解决方案。

my-upload-adapter.ts

//ckeditorExComponent class Ends here and MyUploadAdapter class begins here in the same ckeditorEx.ts
export class MyUploadAdapter 
    xhr: any;
    loader: any;
    serverUrl: string;
    baseApiUrl: string;
   
    constructor(loader: any, serverUrl: string, baseApiUrl: string) 
      // The file loader instance to use during the upload.
      this.loader = loader;
      this.serverUrl = serverUrl;
      this.baseApiUrl = baseApiUrl;
    
   
    // Starts the upload process.
    upload() 
      return this.loader.file
        .then((file: any) => new Promise((resolve, reject) => 
          this._initRequest();
          this._initListeners(resolve, reject, file);
          this._sendRequest(file);
        ));
    
   
    // Aborts the upload process.
    abort() 
      if (this.xhr) 
        this.xhr.abort();
      
    
   
    // Initializes the XMLHttpRequest object using the URL passed to the constructor.
    _initRequest() 
      const xhr = this.xhr = new XMLHttpRequest();
  
      // Note that your request may look different. It is up to you and your editor
      // integration to choose the right communication channel. This example uses
      // a POST request with JSON as a data structure but your configuration
      // could be different.
      //Replace below url with your API url
      xhr.open('POST', this.baseApiUrl + 'Tutorial/add-post-photo', true);
      xhr.responseType = 'json';
    
   
    // Initializes XMLHttpRequest listeners.
    _initListeners(resolve: any, reject: any, file: any) 
      const xhr = this.xhr;
      const loader = this.loader;
      const genericErrorText = `Couldn't upload file: $file.name.`;
   
      xhr.addEventListener('error', () => reject(genericErrorText));
      xhr.addEventListener('abort', () => reject());
      xhr.addEventListener('load', () => 
   
        const response = xhr.response;
   
        // This example assumes the XHR server's "response" object will come with
        // an "error" which has its own "message" that can be passed to reject()
        // in the upload promise.
        //
        // Your integration may handle upload errors in a different way so make sure
        // it is done properly. The reject() function must be called when the upload fails.
        if (!response || response.error) 
          return reject(response && response.error ? response.error.message : genericErrorText);
        
   
        // If the upload is successful, resolve the upload promise with an object containing
        // at least the "default" URL, pointing to the image on the server.
        // This URL will be used to display the image in the content. Learn more in the
        // UploadAdapter#upload documentation.
        resolve(
          default: this.serverUrl + response.url
        );
      );
   
      // Upload progress when it is supported. The file loader has the #uploadTotal and #uploaded
      // properties which are used e.g. to display the upload progress bar in the editor
      // user interface.
   
      if (xhr.upload) 
        xhr.upload.addEventListener('progress', (evt: any) => 
          if (evt.lengthComputable) 
            loader.uploadTotal = evt.total;
            loader.uploaded = evt.loaded;
          
        );
      
    
   
    // Prepares the data and sends the request.
   
    _sendRequest(file: any)  
      // Prepare the form data. 
      const data = new FormData();
      data.append('upload', file);
  
      // Important note: This is the right place to implement security mechanisms
      // like authentication and CSRF protection. For instance, you can use
      // XMLHttpRequest.setRequestHeader() to set the request headers containing
      // the CSRF token generated earlier by your application.
      // Send the request.
   
      this.xhr.send(data);
   
    
   
  

在 Angular 组件中

onReady($event: any) 
    $event.plugins.get('FileRepository').createUploadAdapter = (loader: any) => 
        return new MyUploadAdapter(loader, this.serverUrl, this.apiUrl);
    ;

C# Web API 控制器

[HttpPost("add-post-photo")]
public async Task<ActionResult<string>> AddPostPhoto(IFormFile upload)

    try
    
        FileInfo fileInfo = new FileInfo(upload.FileName);
        System.Console.WriteLine(upload.FileName);
        var folderDirectory = $"\\Photos\\PostPhotos";
        var path = Path.Combine("Photos\\PostPhotos", upload.FileName);

        var memoryStream = new MemoryStream();
        await upload.OpenReadStream().CopyToAsync(memoryStream);

        if (!Directory.Exists(folderDirectory))
        
            Directory.CreateDirectory(folderDirectory);
        

        await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
        
            memoryStream.WriteTo(fs);
        

        return Ok(new  Url = path );
     
    catch(Exception exception)
    
        return BadRequest(exception.Message);
    

参数上传很重要,否则找不到后端端点

【讨论】:

角度组件中的 onReady 是什么?我正在使用角度 4。

以上是关于CKEditor 和 C# Web API,使用简单的上传插件上传图片的主要内容,如果未能解决你的问题,请参考以下文章

在两个应用程序中使用时,ckeditor 未在 IE 中加载

使用 angular js 和 c# 使用 web api

使用 C# Web Api 和 axios 进行令牌认证

C# Web Api 2 PUT 和 POST 请求“不支持”

七牛云:ckeditor JS SDK 结合 C#实现多图片上传。

使用xpath web api c#从xml获取数据