Вопрос

В продолжение дискуссии "Отправка файлов на Ftp"

Доброго времени суток.

Желательно присутствие бывалых Одинов, которые повидали многое в данном продукте.

В продолжение предыдущего поста было принято решения не отходить от стандартной реализации отправления файла, используя FileAPI.



На данный момент были созданы на основе базовых схем, следующие схемы:

аналог FileUploadInfo,

аналог IFileUploadInfo,

KmFileUploadService - аналог сервиса FileApiService,

аналог FileUploader аналог.



Так же была заимствована логика подготовки и отправки файла до FileAPI из FileDetailV2 и ConfigurationFileApi.




При выборе некого файла (если помните ранее писал про кнопку Selec file, клик которой создает скрытый input с type = file и реализует клик по нему) после логики схем FileDetailV2 и ConfigurationFileApi файл попадает в FileAPI, где на мой взгляд происходит его подготовка и разбиение на Chunk (далее Чанки).

После всех манипуляций дынный Api посылает его в KmFileUploadService
 , который вызывает унаследованный FileUploader, конкретно метод Upload, где происходит проверка размера файла, а далее ведется проверка связанная с Чанками (!fileUploadInfo.IsChunkedUpload || fileUploadInfo.IsFirstChunk) и в зависимости от проверки запускается метод Save или AppendData.



Как только текущий Чанк попадает в Save, исходя из нашей логики я организовываю запросы на Ftp по созданию файла (ничего такого, чего нет на MSDN).

Далее как я понимаю идёт обратный запрос к FileAPI который в свою очередь отдает нам следующий Чанк, который попадает в AppendData.



Базовая реализация этого метода подразумевает вызов метода DBLobUtilities.AppendBlob.

В нашем случае мы не используем этот метод, так как сохранение файла в базу у нас не велось. Мы используем аналогичный подход как в нашем Save только указываем WebRequestMethods.Ftp.AppendFile ,который должен нам исходя из следующего Чанка дописать ранее созданный экземпляр файла. По завершению этого действия по идее должен быть обратный ответ от FileAPI, который вышлет нам следующий Чанк и так далее пока все Чанки не кончатся, но этого не происходит. См. приложенный скриншот.

Изображение удалено.



Итак самое главное вопросы:

1. Не удалось найти реализацию базового метода DBLobUtilities.AppendBlob, т.е. что он выполняет и каким образом запросы к FileAPI не прерываются. Потому что в нашем случае весь процесс состоит из двух Чанков, + второй Чанк сильно переписывает и ломает тело файла.

2. Хотелось бы узнать существует ли возможность в наш сервис передать кастомное значение типа пункта назначения фолдера, куда сохранять файл. Есть подозрения что нужно будет расширить FileUploadInfo и интерфейс который он использует, и обязательно расширить UI методы который формируют объект для FileAPI.

 

P.s. если не использовать данный подход, а работать с обыкновенным FileReader и читать тело файла readAsDataURL то всё бы ничего, но вот если файл весит свыше 10мб у сервиса начинается батхерт со временем обработки запроса.

Нравится

2 комментария

Не понимаю зачем зарывать в такие дебри. У меня сработало так:

1) Создал миксин, обрабатывающий  клик и загрузку.

define("TmUploadMixin", ["MaskHelper", "ConfigurationFileApi"],
	function(MaskHelper) {
 
		Ext.define("Terrasoft.configuration.mixins.TmUploadMixin", {
		alternateClassName: "Terrasoft.TmUploadMixin",
 
		/**FILE_IMPORTER**/
		onFilesSelected: function(file, tag) {
			if (file.length <= 0) {
				return;
			}
			var config = this.getUploadConfig(file, tag);
			this.upload(config);
		},
		getUploadConfig: function(file, tag) {
			return {
				uploadWebServicePath: "TmFilesUploader/Upload", // "FileApiService/Upload"
				scope: this,
				columnName: "columnName",
				parentColumnName: "parentColumnName",
				parentColumnValue: "parentColumnValue",
				onFileComplete: this.onFileComplete,
				entitySchemaName: tag,
				files: file,
				isChunkedUpload: false
			};
		},
		upload: function(config) {
			MaskHelper.ShowBodyMask();
			Terrasoft.ConfigurationFileApi.upload(config);
		},
		onFileComplete: function(error, xhr, file, options) {
			MaskHelper.HideBodyMask();
			//debugger;
			var data = JSON.parse(Terrasoft.decode(xhr.responseText));
			if (data.error !== "False") {
				this.showInformationDialog("Ошибка импорта. Подробнее — в консоли");
				console.log(data.data);
			} else {
				this.showInformationDialog("Записей импортировано: "+data.data);
				//this.reloadGridData();
			}
		}
 
	});
	return Terrasoft.TmUploadMixin;
});

 

2) Создал сервис

namespace Terrasoft.Configuration.TmFilesUploader
{
	using System;
	using System.IO;
	using System.Net;
	using System.Data;
	using System.Runtime;
	using System.Collections.Generic;
	using System.Runtime.Serialization;
	using System.ServiceModel;
	using System.ServiceModel.Web;
	using System.ServiceModel.Activation;
	using System.Web;
	using System.Web.SessionState;
	using Terrasoft.Common;
	using Terrasoft.Core;
	using Terrasoft.Core.Factories;
	using Terrasoft.Core.Entities;
	using Terrasoft.Configuration.FileUpload;
	using Terrasoft.Web.Common;
 
 
	[ServiceContract]
	[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
	public class TmFilesUploader : BaseService, IReadOnlySessionState
	{
		[Obsolete]
		public const string HeaderContentRange = "Content-Range";
		[Obsolete]
		public const string HeaderRange = "Range";
		[Obsolete]
		public const string HeaderContentDisposition = "Content-Disposition";
 
		[OperationContract]
		[WebInvoke(Method = "POST", UriTemplate = "Upload", ResponseFormat = WebMessageFormat.Json)]
		public string Upload(Stream fileContent) {
			string value;
			bool error=false;
			try {
				IFileUploadInfo fileUploadInfo = new FileUploadInfo(fileContent, new HttpRequestWrapper(HttpContext.Current.Request);
				/**стрим будет валяться в fileUploadInfo.Content**/
			} catch (Exception ex) {
				value = ex.Message+"|"+ex.Source+"|"+ex.StackTrace+"|"+ex.InnerException;
				error = true;
			}
 
			return "{\"error\":\"" + error + "\",\"data\":\"" + value + "\"}";
		}
	}
}

И как бы всё... Ну единственно отрубил chunkedUpload и оставил дефолтный террасофтовский метод по проверке веса файла (думаю можно отредактировать если надо)

Варфоломеев Данила пишет:

Варфоломеев Данила

Добрый день/ночь, вот что получаем в итоге при ~20+ мб весом файла, ограничение Террасофта в настройке повысил. Понимаю что файл надо разбить каким-то образом на осмысленные части и грубо говоря из сервиса append'ить эти части между собой. Но мысли пока зашли в тупик.

Есть предположения у Вас коллега? 

Показать все комментарии