Попытка / Как опубликовать файл изображения из Angular front end в. NET CORE Backend API - - PullRequest
0 голосов
/ 14 января 2020

Я хочу знать, как лучше всего это сделать.

В своем приложении Angular 8 я выбираю файл img и хочу отправить этот файл изображения в. NET Базовый API-интерфейс. Внутренний сервис должен сохранить это изображение в базе данных.

html для моего селектора изображений -

<div class="image-picker" (click)="fileInput.click()">
  <mat-icon [class.small]="imageUrl">file_upload</mat-icon>
  <canvas width="500" height="380" #canvas hidden="true"></canvas>
  <input #fileInput type="file" hidden="true" (change)="imageDataChanged($event)">
</div>

соответствующий .ts код -

imageDataChanged($event) {
    var file = $event.target.files[0];


    console.log(file);

    var reader = new FileReader();

    // get data from file input and emit as dataUrl
    reader.addEventListener("load", () => {
      var ctx = this.canvas.nativeElement.getContext('2d');
      this.imageUrl = reader.result;
      this.imagePicked.emit(this.imageUrl);
    }, false);

    if (file) {
      reader.readAsDataURL(file);
    }
  }

Так что я получить в моей консоли, детали, связанные с файлом, который я выбрал. Как имя, размер, дата, дата, измененная ..... После нажатия кнопки отправки я хотел бы опубликовать этот файл в бэкэнд-API. У меня вопрос - в каком формате и как. изображение base64? Какой код для этого. Как бы я это сделал? Как я уже сказал, мой бэкэнд находится в. NET Core.

Вот код, который я попытался -

[HttpPost]
        [Route("CaptureSaveImg")]
        public IActionResult CaptureSaveImg(HttpContext context)
        {
            string imageName = null;
            var httpRequest = context.Request;

            var postedFile = httpRequest.Form.Files["Image"];

            try
            {
                if(postedFile!=null)
                {
                    var fileName = postedFile.FileName;

                    var myUniqueFileName = Convert.ToString(Guid.NewGuid());

                    var fileExtension = Path.GetExtension(fileName);

                    var newFileName = string.Concat(myUniqueFileName, fileExtension);

                    var filepath = Path.Combine(_environment.WebRootPath, "CameraPics") + $@"\{newFileName}";

                    if (!string.IsNullOrEmpty(filepath))
                    {
                        // Storing Image in Folder  
                        StoreInFolder(postedFile, filepath);
                    }

                    var imageBytes = System.IO.File.ReadAllBytes(filepath);
                    if (imageBytes != null)
                    {
                        StoreInDatabase(imageBytes);
                    }

                    return Json(new { Success = true, Message = "Image Saved." });
                }
                else
                {
                    return Json(new { Success = false, Message = "An error occurred while saving the image." });
                }
            }
            catch(Exception exp)
            {
                return Json(new { Success =false, Message="An unexpected error occurred!"});
            }
        }


private void StoreInDatabase(byte[] imageBytes)
        {
            try
            {
                if (imageBytes != null)
                {
                    string base64String = Convert.ToBase64String(imageBytes, 0, imageBytes.Length);
                    string imageUrl = string.Concat("data:image/jpg;base64,", base64String);
                    ImageStore imageStore = new ImageStore()
                    {
                        CreateDate = DateTime.Now,
                        ImageBase64String = imageUrl,
                        ImageId = 0
                    };
                    _context.ImageStores.Add(imageStore);
                    _context.SaveChanges();
                }
            }
            catch (Exception exp)
            {
                throw exp.InnerException;
            }
        }

        private void StoreInFolder(IFormFile file, string fileName)
        {
            try
            {
                using (FileStream fs = System.IO.File.Create(fileName))
                {
                    file.CopyTo(fs);
                    fs.Flush();
                }
            }
            catch (Exception exp)
            {
                throw exp.InnerException;
            }

        }

html для нажатия кнопки -

<button class="btn btn-primary btn-lg btn-block" type="button" (click)="OnSubmit(Image)" >UPLOAD</button>

.ts для нажатия кнопки -

OnSubmit(file: File)
  {
    this.userRestService.uploadImage(this.fileToUpload)
      .subscribe((data: any) => {
        console.log('Done successfully! '+data.Message);
        this.imageUrl = null;
      });
  }

В службе use-rest -

fileToUpload: File = null;  

uploadImage(file: File) {
    var reqHeader = new HttpHeaders({ 'No-Auth': 'True' });

    const formData: FormData = new FormData();
    formData.append('Image', file, file.name);

    return this.http.post(this.baseUrl +'CaptureSaveImg', formData, { headers: reqHeader });
  }

Я хочу сначала сохранить ее в пути к локальной папке, а затем оттуда прочитать файл и сохранить в БД. Я понимаю, что, когда я пытаюсь опубликовать его как fileToUpload, он, вероятно, отправляет значение null.

Проблема, с которой я сталкиваюсь - что мне отправлять / отправлять из внешнего интерфейса в API. Как. Можете ли вы показать мне некоторый код, который достиг бы этого. Можете ли вы дать мне пошаговое руководство для достижения этой цели.

Не стесняйтесь спрашивать более подробную информацию о том, что я пытался, чтобы лучше понять. Спасибо

ОБНОВЛЕНИЕ:

Я забыл упомянуть ранее, что мой компонент выбора изображений в основном является отдельным angular компонентом, который я использую, как на главной странице. Таким образом, код imageDataChanged ($ event) также находится в этом компоненте. Позвольте мне опубликовать.

<input #fileInput type="file" hidden="true" (change)="imageDataChanged($event)">

.ts код -

imageDataChanged($event) {
    var file = $event.target.files[0];
    this.ds.selectedFile = file;

    if (file.length===0) {
      return;
    }

    var reader = new FileReader();

    // get data from file input and emit as dataUrl
    reader.addEventListener("load", () => {
      var ctx = this.canvas.nativeElement.getContext('2d');
      this.imageUrl = reader.result;
      this.imagePicked.emit(this.imageUrl);
    }, false);

    if (file) {
      reader.readAsDataURL(file);
    }

    const formData = new FormData();

    formData.append(file.name, file);

    this.ds.formDataPost = formData;

  }

Здесь ds - не что иное, как промежуточный класс для инъекции данных.

@Injectable()
export class DataSharingService {

  public selectedFile: any;

  public formDataPost: any;

}

Теперь, мой код OnSubmit -

OnSubmit()
  {
    console.log(this.ds.formDataPost);

    const uplRequest = new HttpRequest('POST', this.baseUrl + '/CaptureSaveImg', this.ds.formDataPost, { reportProgress: true });

    this.http.request(uplRequest)
      .subscribe((data: any) =>
      {
        if (data.Success == "true")
        {
          console.log("Upload successful.");
        }
        else
        {
          console.log("Problem while uploading file.");
        }
      })
  }

Я просто получаю сообщение об ошибке - core. js: 6014 ОШИБКА TypeError: Вы указали 'undefined', где ожидался поток. Вы можете предоставить Observable, Promise, Array или Iterable.

Я думаю, что я близок. Любое преобразование необходимо? Или формат данных?

1 Ответ

0 голосов
/ 14 января 2020

Я сделал это, сохранив в базе данных как Base 64. Это удобно, потому что после немедленного преобразования изображения на клиенте в строку отправка на сервер и сохранение в базе данных становится тривиальным.

myForm = new FormGroup({
  foo: new FormControl(''), // etc...
  imageBase64: new FormControl('')
});

constructor(private cd: ChangeDetectorRef) { }

onImageAttached(event): void {
  const reader = new FileReader();

  if (event.target.files && event.target.files.length) {
    const [file] = event.target.files;
    reader.readAsDataURL(file);

    reader.onload = () => {
      this.myForm.patchValue({
        imageBase64: reader.result
      });

      // need to run CD since file load runs outside of zone
      this.cd.markForCheck();
    };
  }
}

Позже, если вы отображаете эти изображения в приложении, вы можете отправить эту строку base64 полностью в DOM.

С другой стороны, если у вас есть веб-сервер, отображающий ваши Angular клиент, вы также можете конвертировать в файл на сервере по соображениям производительности. Это дает вам маршрут приложения для ваших изображений.

public class AppImageController : Controller
{
    [HttpGet]
    public async Task<IActionResult> Index(int id)
    {
        var imageBase64 = await _imageRepository.GetByIdAsync(id);

        var mimeStartIndex = imageBase64.IndexOf("image/");

        var mime = imageBase64
            .Substring(
                mimeStartIndex,
                result.Data.Attachment.IndexOf(';') - mimeStartIndex
             );

        var content = imageBase64
            .Remove(0, result.Data.Attachment.LastIndexOf(',') + 1);

        var bytes = Convert.FromBase64String(content);

        return File(bytes, mime.Length > 0 ? mime : "image/png");
    }
}
<img src="AppImage/Index/{{appImage.id}}"
     alt="{{appImage.name}}">

Нельзя сказать, что сохранение изображений в базу данных всегда лучший вызов. Сохранение в файловой системе сервера, AWS S3 file store и др. c. все очень жизнеспособные варианты. Между этими подходами есть компромиссы, которые вы можете исследовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...