简体   繁体   English

CKEditor 和 C# Web API 上传图片

[英]CKEditor and C# Web API, upload image with simple upload plugin

In my project I use CKEditor WYSWYG package to make HTML content for my website.在我的项目中,我使用 CKEditor WYSWYG package 为我的网站制作 HTML 内容。 There is possible to insert image and send it directly from the package to the server.可以插入图像并将其直接从 package 发送到服务器。

Since 2 days I try to figure out how is it possible to catch the sent image from the Angular front-end to the Web API, but still no success.两天以来,我试图弄清楚如何从 Angular 前端到 Web API 捕获发送的图像,但仍然没有成功。

I use.Net6 and Angular 12 with CKEditor 5.我使用.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);
    }
}

Finally I could find a working solution.最后我可以找到一个可行的解决方案。

my-upload-adapter.ts我的上传适配器.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);
   
    }
   
  }

In the Angular component在 Angular 组件中

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

The C# Web API controller C# Web API controller

[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);
    }
}

It is important to have the parameter upload, otherwise the find the back-end endpoint重要的是要上传参数,否则会找到后端端点

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM