예제 #1
0
        /// <summary>
        /// Осуществляет загрузку файла на сервер в подкаталог с заданным именем внутри каталога <see cref="UploadsDirectoryPath"/>.
        /// </summary>
        /// <param name="fileUploadKey">
        /// Ключ загрузки файла (используется как имя подкаталога).
        /// </param>
        /// <returns>
        /// Асинхронная операция, которая в случае успешного выполнения вернет метаданные загруженного файла (<see cref="FileDescription"/>).
        /// </returns>
        private Task <FileDescription> UploadFile(string fileUploadKey)
        {
            // Создаём каталог для загружаемого файла, и провайдер для его вычитки и сохранения.
            string fileUploadPath = CreateFileUploadDirectory(fileUploadKey);
            FileUploadStreamProvider fileUploadProvider = new FileUploadStreamProvider(fileUploadPath);

            // Вычитываем загружаемый файл из запроса, и сохраняем в созданном каталоге.
            Task <FileDescription> uploadTask = Request.Content.ReadAsMultipartAsync(fileUploadProvider).ContinueWith((readRequestTask) =>
            {
                // Обрабатываем сбой/отмену при обработке файла.
                if (readRequestTask.IsFaulted || readRequestTask.IsCanceled)
                {
                    Exception exception = readRequestTask.Exception ?? new Exception("Read MIME multipart content task was faulted or cancelled.");

                    throw exception;
                }

                // Возвращаем описание загруженного файла.
                return(new FileDescription(BaseUrl, fileUploadProvider.FileData.First().LocalFileName));
            }).ContinueWith((fileDescriptionTask) =>
            {
                // Если загрузка файла прошла успешно, нужно удалить ранее загруженнй файл,
                // который еще не ассоциированн с объектом данных.
                if (!(fileDescriptionTask.IsFaulted || fileDescriptionTask.IsCanceled))
                {
                    FileDescription previousFileDescription = FileDescription.FromJson(fileUploadProvider.FormData.Get("previousFileDescription"));
                    if (!string.IsNullOrEmpty(previousFileDescription?.FileUploadKey))
                    {
                        RemoveFileUploadDirectory(previousFileDescription.FileUploadKey);
                    }
                }

                return(fileDescriptionTask.Result);
            });

            return(uploadTask);
        }
예제 #2
0
        /// <summary>
        /// Осуществляет проверку того, что файлы корректно загружаются на сервер.
        /// </summary>
        //[Test]
        public void TestUploadSuccess()
        {
            string fileBaseUrl = "http://localhost/api/File";

            // TODO: По какой-то причине этот тест виснет при асинхронном запросе к серверу если создаются временные БД.
            // Скорее всего проблема в контексте синхронизации ASP.NET и асинхронном методе контроллера.
            //using (DataServiceWrapper dataServiceWrapper = new DataServiceWrapper())
            //using (ShimsContext.Create())
            {
                // Подменяем HttpContext.
                //ShimHttpContext.CurrentGet = () =>
                {
                    //return new HttpContext(new HttpRequest(null, "http://localhost", null), new HttpResponse(null));
                };

                //foreach (IDataService dataService in dataServiceWrapper.AllowedDataServices)
                {
                    foreach (string srcFilePath in new List <string> {
                        _srcImageFilePath, _srcTextFilePath
                    })
                    {
                        FileInfo srcFileInfo = new FileInfo(srcFilePath);

                        // Ключ загрузки файла (этим ключем будет именоваться подкаталог в каталоге UploadsDirectoryPath).
                        Guid   fileUploadKeyGuid = Guid.NewGuid();
                        string fileUploadKey     = fileUploadKeyGuid.ToString("D");
                        string fileName          = srcFileInfo.Name;
                        string fileMimeType      = MimeMapping.GetMimeMapping(fileName);
                        long   fileSize          = srcFileInfo.Length;

                        string uploadedFilePath = $"{_uploadsDirectoryPath}\\{fileUploadKey}\\{srcFileInfo.Name}";

                        using (var config = new HttpConfiguration())
                        {
                            config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
                            config.MapODataServiceFileRoute("File", "api/File", _uploadsDirectoryPath, new MSSQLDataService());

                            using (var server = new HttpServer(config))
                            {
                                using (var client = new HttpClient(server, false))
                                {
                                    using (var uploadingImageFileContent = new StreamContent(srcFileInfo.Open(FileMode.Open, FileAccess.Read)))
                                    {
                                        uploadingImageFileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
                                        {
                                            FileName = srcFileInfo.Name
                                        };
                                        uploadingImageFileContent.Headers.ContentType = new MediaTypeHeaderValue(MimeMapping.GetMimeMapping(srcFileInfo.Name));

                                        var formDataContent = new MultipartFormDataContent {
                                            uploadingImageFileContent
                                        };

                                        // Подменяем NewGuid, чтобы имя подкаталога, в который будет загружен файл, было заранее известно.
                                        //ShimGuid.NewGuid = () => fileUploadKeyGuid;
                                        using (HttpResponseMessage response = client.PostAsync(fileBaseUrl, formDataContent).Result)
                                        {
                                            // Проверяем, что запрос завершился успешно.
                                            //Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);

                                            // Проверяем, что загруженный на сервер файл существует, и совпадает с тем файлом, из которого производилась загрузка.
                                            //Assert.AreEqual(true, System.IO.File.Exists(uploadedFilePath));
                                            //Assert.AreEqual(true, FilesComparer.FilesAreEqual(srcFilePath, uploadedFilePath));

                                            // Получаем описание загруженного файла, из ответа, полученного от сервера.
                                            FileDescription receivedFileDescription = FileDescription.FromJson(response.Content.ReadAsStringAsync().Result);

                                            Uri receivedFileUri    = new Uri(receivedFileDescription.FileUrl);
                                            Uri receivedPreviewUri = new Uri(receivedFileDescription.PreviewUrl);

                                            string receivedFileBaseUrl    = receivedFileUri.GetLeftPart(UriPartial.Path);
                                            string receivedPreviewBaseUrl = receivedPreviewUri.GetLeftPart(UriPartial.Path);

                                            NameValueCollection receivedFileQueryParameters    = HttpUtility.ParseQueryString(receivedFileUri.Query);
                                            NameValueCollection receivedPreviewQueryParameters = HttpUtility.ParseQueryString(receivedPreviewUri.Query);

                                            // Проверяем, что полученное описание загруженного файла совпадает с ожидаемым.

                                            /*
                                             * Assert.AreEqual(fileUploadKey, receivedFileDescription.FileUploadKey);
                                             * Assert.AreEqual(fileName, receivedFileDescription.FileName);
                                             * Assert.AreEqual(fileSize, receivedFileDescription.FileSize);
                                             * Assert.AreEqual(fileMimeType, receivedFileDescription.FileMimeType);
                                             * Assert.AreEqual(null, receivedFileDescription.EntityTypeName);
                                             * Assert.AreEqual(null, receivedFileDescription.EntityPropertyName);
                                             * Assert.AreEqual(null, receivedFileDescription.EntityPrimaryKey);
                                             *
                                             * Assert.AreEqual(fileBaseUrl, receivedFileBaseUrl);
                                             * Assert.AreEqual(fileBaseUrl, receivedPreviewBaseUrl);
                                             *
                                             * Assert.AreEqual(2, receivedFileQueryParameters.Count);
                                             * Assert.AreEqual(fileUploadKey, receivedFileQueryParameters[nameof(FileDescription.FileUploadKey)]);
                                             * Assert.AreEqual(fileName, receivedFileQueryParameters[nameof(FileDescription.FileName)]);
                                             *
                                             * Assert.AreEqual(3, receivedPreviewQueryParameters.Count);
                                             * Assert.AreEqual(fileUploadKey, receivedPreviewQueryParameters[nameof(FileDescription.FileUploadKey)]);
                                             * Assert.AreEqual(fileName, receivedPreviewQueryParameters[nameof(FileDescription.FileName)]);
                                             * Assert.AreEqual(true, bool.Parse(receivedPreviewQueryParameters["GetPreview"]));
                                             */
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Осуществляет проверку того, что <see cref="FileDescription"/> с заданными свойствами, описывающими объект данных,
        /// корректно десериализуется из JSON-строки.
        /// </summary>
        //[Test]
        public void TestDeserializationFromJsonByEntityProperties()
        {
            string fileBaseUrl = "http://localhost/api/File";

            // Имя, размер и тип файла.
            string fileName     = "readme.txt";
            long   fileSize     = 1024;
            string fileMimeType = MimeMapping.GetMimeMapping(fileName);

            // Свойства достаточные для описания файла, который привязан к объекту данных
            // (тип и первичный ключ объекта данных, а так же имя файлового свойства в объекте данных).
            КлассСМножествомТипов entity = new КлассСМножествомТипов();
            string entityTypeName        = entity.GetType().AssemblyQualifiedName;
            string entityPropertyName    = nameof(entity.PropertyStormnetFile);
            string entityPrimaryKey      = entity.__PrimaryKey.ToString();

            // Описание файла с избыточным набором свойств.
            FileDescription fileDescription = new FileDescription(fileBaseUrl)
            {
                FileName           = fileName,
                FileSize           = fileSize,
                FileMimeType       = fileMimeType,
                EntityTypeName     = entityTypeName,
                EntityPropertyName = entityPropertyName,
                EntityPrimaryKey   = entityPrimaryKey
            };

            string serializedFileDescription = fileDescription.ToJson();

            // Получаем десериализованные описания файла, полученные различными способами.
            List <FileDescription> deserializedFileDescriptions = new List <FileDescription>
            {
                FileDescription.FromJson(serializedFileDescription)
            };

            using (HttpConfiguration config = new HttpConfiguration())
            {
                config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
                config.Routes.MapHttpRoute("File", "api/File", new { controller = "FileDescriptionTest" });

                using (HttpServer server = new HttpServer(config))
                {
                    using (HttpClient client = new HttpClient(server, false))
                    {
                        // Получаем десериализованное описание файла из тела POST-запроса.
                        using (HttpResponseMessage response = client.PostAsJsonStringAsync("http://localhost/api/File", serializedFileDescription).Result)
                        {
                            // Убедимся, что запрос завершился успешно.
                            //Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);

                            deserializedFileDescriptions.Add(FileDescriptionTestController.FileDescriptionPost);
                        }

                        // Получаем десериализованное описание файла из URL PUT-запроса.
                        string putUrl = string.Format(
                            "http://localhost/api/File?{0}={1}&{2}={3}&{4}={5}&{6}={7}&{8}={9}&{10}={11}",
                            nameof(FileDescription.FileName),
                            fileDescription.FileName,
                            nameof(FileDescription.FileSize),
                            fileDescription.FileSize,
                            nameof(FileDescription.FileMimeType),
                            fileDescription.FileMimeType,
                            nameof(FileDescription.EntityTypeName),
                            fileDescription.EntityTypeName,
                            nameof(FileDescription.EntityPropertyName),
                            fileDescription.EntityPropertyName,
                            nameof(FileDescription.EntityPrimaryKey),
                            fileDescription.EntityPrimaryKey);
                        using (HttpResponseMessage response = client.SendAsync(new HttpRequestMessage(HttpMethod.Put, putUrl)).Result)
                        {
                            // Убедимся, что запрос завершился успешно.
                            //Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);

                            deserializedFileDescriptions.Add(FileDescriptionTestController.FileDescriptionPut);
                        }
                    }
                }
            }

            // Проверяем, что результаты десериализации, полученные разными способами - одинаковы и корректны.
            foreach (FileDescription deserializedFileDescription in deserializedFileDescriptions)
            {
                /*
                 * Assert.AreEqual(fileName, deserializedFileDescription.FileName);
                 * Assert.AreEqual(fileSize, deserializedFileDescription.FileSize);
                 * Assert.AreEqual(fileMimeType, deserializedFileDescription.FileMimeType);
                 * Assert.AreEqual(entityTypeName, deserializedFileDescription.EntityTypeName);
                 * Assert.AreEqual(entityPropertyName, deserializedFileDescription.EntityPropertyName);
                 * Assert.AreEqual(entityPrimaryKey, deserializedFileDescription.EntityPrimaryKey);
                 * Assert.AreEqual(fileDescription.FileUrl, deserializedFileDescription.FileUrl);
                 * Assert.AreEqual(fileDescription.PreviewUrl, deserializedFileDescription.PreviewUrl);
                 * Assert.AreEqual(null, deserializedFileDescription.FileUploadKey);
                 */
            }
        }
예제 #4
0
        /// <summary>
        /// Построение объекта данных по сущности OData.
        /// </summary>
        /// <param name="edmEntity"> Сущность OData. </param>
        /// <param name="key"> Значение ключевого поля сущности. </param>
        /// <param name="dObjs"> Список объектов для обновления. </param>
        /// <param name="endObject"> Признак, что объект добавляется в конец списка обновления. </param>
        /// <returns> Объект данных. </returns>
        private DataObject GetDataObjectByEdmEntity(EdmEntityObject edmEntity, object key, List <DataObject> dObjs, bool endObject = false)
        {
            if (edmEntity == null)
            {
                return(null);
            }

            IEdmEntityType entityType = (IEdmEntityType)edmEntity.ActualEdmType;
            Type           objType    = _model.GetDataObjectType(_model.GetEdmEntitySet(entityType).Name);

            // Значение свойства.
            object value;

            // Получим значение ключа.
            var keyProperty = entityType.Properties().FirstOrDefault(prop => prop.Name == _model.KeyPropertyName);

            if (key != null)
            {
                value = key;
            }
            else
            {
                edmEntity.TryGetPropertyValue(keyProperty.Name, out value);
            }

            // Загрузим объект из хранилища, если он там есть (используем представление по умолчанию), или создадим, если нет, но только для POST.
            // Тем самым гарантируем загруженность свойств при необходимости обновления и установку нужного статуса.
            DataObject obj = ReturnDataObject(objType, value);

            // Добавляем объект в список для обновления, если там ещё нет объекта с таким ключом.
            var objInList = dObjs.FirstOrDefault(o => o.__PrimaryKey.ToString() == obj.__PrimaryKey.ToString());

            if (objInList == null)
            {
                if (!endObject)
                {
                    // Добавляем объект в начало списка.
                    dObjs.Insert(0, obj);
                }
                else
                {
                    // Добавляем в конец списка.
                    dObjs.Add(obj);
                }
            }

            // Все свойства объекта данных означим из пришедшей сущности, если они были там установлены(изменены).
            foreach (var prop in entityType.Properties())
            {
                string dataObjectPropName = _model.GetDataObjectProperty(entityType.FullTypeName(), prop.Name).Name;
                if (edmEntity.GetChangedPropertyNames().Contains(prop.Name))
                {
                    // Обработка мастеров и детейлов.
                    if (prop is EdmNavigationProperty)
                    {
                        EdmNavigationProperty navProp = (EdmNavigationProperty)prop;

                        edmEntity.TryGetPropertyValue(prop.Name, out value);

                        EdmMultiplicity edmMultiplicity = navProp.TargetMultiplicity();

                        // var aggregator = Information.GetAgregatePropertyName(objType);

                        // Обработка мастеров.
                        if (edmMultiplicity == EdmMultiplicity.One || edmMultiplicity == EdmMultiplicity.ZeroOrOne)
                        {
                            if (value != null && value is EdmEntityObject)
                            {
                                EdmEntityObject edmMaster = (EdmEntityObject)value;
                                DataObject      master    = GetDataObjectByEdmEntity(edmMaster, null, dObjs);

                                Information.SetPropValueByName(obj, dataObjectPropName, master);
                            }
                            else
                            {
                                Information.SetPropValueByName(obj, dataObjectPropName, null);
                            }
                        }

                        // Обработка детейлов.
                        if (edmMultiplicity == EdmMultiplicity.Many)
                        {
                            Type        detType = Information.GetPropertyType(objType, dataObjectPropName);
                            DetailArray detarr  = (DetailArray)Information.GetPropValueByName(obj, dataObjectPropName);

                            if (value != null && value is EdmEntityObjectCollection)
                            {
                                EdmEntityObjectCollection coll = (EdmEntityObjectCollection)value;
                                if (coll != null && coll.Count > 0)
                                {
                                    foreach (var edmEnt in coll)
                                    {
                                        DataObject det = GetDataObjectByEdmEntity(
                                            (EdmEntityObject)edmEnt,
                                            null,
                                            dObjs,
                                            true);

                                        if (det.__PrimaryKey == null)
                                        {
                                            detarr.AddObject(det);
                                        }
                                        else
                                        {
                                            detarr.SetByKey(det.__PrimaryKey, det);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                detarr.Clear();
                            }
                        }
                    }
                    else
                    {
                        // Обработка собственных свойств объекта (неключевых, т.к. ключ устанавливаем при начальной инициализации объекта obj).
                        if (prop.Name != keyProperty.Name)
                        {
                            Type dataObjectPropertyType = Information.GetPropertyType(objType, dataObjectPropName);
                            edmEntity.TryGetPropertyValue(prop.Name, out value);

                            // Если тип свойства относится к одному из зарегистрированных провайдеров файловых свойств,
                            // значит свойство файловое, и его нужно обработать особым образом.
                            if (FileController.HasDataObjectFileProvider(dataObjectPropertyType))
                            {
                                IDataObjectFileProvider dataObjectFileProvider = FileController.GetDataObjectFileProvider(dataObjectPropertyType);

                                // Обработка файловых свойств объектов данных.
                                string serializedFileDescription = value as string;
                                if (serializedFileDescription == null)
                                {
                                    // Файловое свойство было сброшено на клиенте.
                                    // Ассоциированный файл должен быть удален, после успешного сохранения изменений.
                                    // Для этого запоминаем метаданные ассоциированного файла, до того как свойство будет сброшено
                                    // (для получения метаданных свойство будет дочитано в объект данных).
                                    // Файловое свойство типа File хранит данные ассоциированного файла прямо в БД,
                                    // соответственно из файловой системы просто нечего удалять,
                                    // поэтому обходим его стороной, чтобы избежать лишных вычиток файлов из БД.
                                    if (dataObjectPropertyType != typeof(File))
                                    {
                                        _removingFileDescriptions.Add(dataObjectFileProvider.GetFileDescription(obj, dataObjectPropName));
                                    }

                                    // Сбрасываем файловое свойство в изменяемом объекте данных.
                                    Information.SetPropValueByName(obj, dataObjectPropName, null);
                                }
                                else
                                {
                                    // Файловое свойство было изменено, но не сброшено.
                                    // Если в метаданных файла присутствует FileUploadKey значит файл был загружен на сервер,
                                    // но еще не был ассоциирован с объектом данных, и это нужно сделать.
                                    FileDescription fileDescription = FileDescription.FromJson(serializedFileDescription);
                                    if (!(string.IsNullOrEmpty(fileDescription.FileUploadKey) || string.IsNullOrEmpty(fileDescription.FileName)))
                                    {
                                        Information.SetPropValueByName(obj, dataObjectPropName, dataObjectFileProvider.GetFileProperty(fileDescription));

                                        // Файловое свойство типа File хранит данные ассоциированного файла прямо в БД,
                                        // поэтому после успешного сохранения объекта данных, оссоциированный с ним файл должен быть удален из файловой системы.
                                        // Для этого запоминаем описание загруженного файла.
                                        if (dataObjectPropertyType == typeof(File))
                                        {
                                            _removingFileDescriptions.Add(fileDescription);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                // Преобразование типов для примитивных свойств.
                                if (value is DateTimeOffset)
                                {
                                    value = ((DateTimeOffset)value).UtcDateTime;
                                }
                                if (value is EdmEnumObject)
                                {
                                    value = ((EdmEnumObject)value).Value;
                                }

                                Information.SetPropValueByName(obj, dataObjectPropName, value);
                            }
                        }
                    }
                }
            }

            return(obj);
        }
예제 #5
0
        /// <summary>
        /// Осуществляет проверку того, что <see cref="FileDescription"/> с заданными ключом загрузки и именем файла
        /// корректно десериализуется из JSON-строки.
        /// </summary>
        //[Test]
        public void TestDeserializationFromJsonByUploadKeyAndFileNameProperties()
        {
            string fileBaseUrl = "http://localhost/api/File";

            // Свойства достаточные для описания файла, который не привязан к объекту данных (ключ загрузки и имя файла).
            string fileUploadKey = Guid.NewGuid().ToString("D");
            string fileName      = "readme.txt";

            // Размер и тип файла.
            long   fileSize     = 1024;
            string fileMimeType = MimeMapping.GetMimeMapping(fileName);

            FileDescription fileDescription = new FileDescription(fileBaseUrl)
            {
                FileUploadKey = fileUploadKey,
                FileName      = fileName,
                FileSize      = fileSize,
                FileMimeType  = fileMimeType
            };

            string serializedFileDescription = fileDescription.ToJson();

            // Получаем десериализованные описания файла, полученные различными способами.
            List <FileDescription> deserializedFileDescriptions = new List <FileDescription>
            {
                FileDescription.FromJson(serializedFileDescription)
            };

            using (HttpConfiguration config = new HttpConfiguration())
            {
                config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
                config.Routes.MapHttpRoute("File", "api/File", new { controller = "FileDescriptionTest" });

                using (HttpServer server = new HttpServer(config))
                {
                    using (HttpClient client = new HttpClient(server, false))
                    {
                        // Получаем десериализованное описание файла из тела POST-запроса.
                        using (HttpResponseMessage response = client.PostAsJsonStringAsync("http://localhost/api/File", serializedFileDescription).Result)
                        {
                            // Убедимся, что запрос завершился успешно.
                            //Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);

                            deserializedFileDescriptions.Add(FileDescriptionTestController.FileDescriptionPost);
                        }

                        // Получаем десериализованное описание файла из URL PUT-запроса.
                        string putUrl = string.Format(
                            "http://localhost/api/File?{0}={1}&{2}={3}&{4}={5}&{6}={7}",
                            nameof(FileDescription.FileUploadKey),
                            fileDescription.FileUploadKey,
                            nameof(FileDescription.FileName),
                            fileDescription.FileName,
                            nameof(FileDescription.FileSize),
                            fileDescription.FileSize,
                            nameof(FileDescription.FileMimeType),
                            fileDescription.FileMimeType);
                        using (HttpResponseMessage response = client.SendAsync(new HttpRequestMessage(HttpMethod.Put, putUrl)).Result)
                        {
                            // Убедимся, что запрос завершился успешно.
                            //Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);

                            deserializedFileDescriptions.Add(FileDescriptionTestController.FileDescriptionPut);
                        }
                    }
                }
            }

            // Проверяем, что результаты десериализации, полученные разными способами - одинаковы и корректны.
            foreach (FileDescription deserializedFileDescription in deserializedFileDescriptions)
            {
                /*
                 * Assert.AreEqual(fileUploadKey, deserializedFileDescription.FileUploadKey);
                 * Assert.AreEqual(fileName, deserializedFileDescription.FileName);
                 * Assert.AreEqual(fileSize, deserializedFileDescription.FileSize);
                 * Assert.AreEqual(fileMimeType, deserializedFileDescription.FileMimeType);
                 * Assert.AreEqual(fileDescription.FileUrl, deserializedFileDescription.FileUrl);
                 * Assert.AreEqual(fileDescription.PreviewUrl, deserializedFileDescription.PreviewUrl);
                 * Assert.AreEqual(null, deserializedFileDescription.EntityTypeName);
                 * Assert.AreEqual(null, deserializedFileDescription.EntityPropertyName);
                 * Assert.AreEqual(null, deserializedFileDescription.EntityPrimaryKey);
                 */
            }
        }