Browse Source

Remove the custom method in HttpApi.

pull/10197/head
maliming 4 years ago
parent
commit
13787cdafb
  1. 5
      modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Files/FileUploadInputDto.cs
  2. 3
      modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Files/IFileAppService.cs
  3. 51
      modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Files/FileAppService.cs
  4. 11
      modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Files/ImageFormatHelper.cs
  5. 9
      modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/BlogFilesClientProxy.Generated.cs
  6. 69
      modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/blogging-generate-proxy.json
  7. 48
      modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/BlogFilesController.cs
  8. 6
      modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/BloggingHttpApiModule.cs
  9. 12
      modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/FileUploadResult.cs
  10. 14
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/edit.js
  11. 14
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/new.js
  12. 12
      modules/blogging/src/Volo.Blogging.Web/wwwroot/client-proxies/blogging-proxy.js

5
modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Files/FileUploadInputDto.cs

@ -1,13 +1,14 @@
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Content;
namespace Volo.Blogging.Files
{
public class FileUploadInputDto
{
[Required]
public byte[] Bytes { get; set; }
public IRemoteStreamContent File { get; set; }
[Required]
public string Name { get; set; }
}
}
}

3
modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Files/IFileAppService.cs

@ -1,5 +1,6 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Content;
namespace Volo.Blogging.Files
{
@ -7,6 +8,8 @@ namespace Volo.Blogging.Files
{
Task<RawFileDto> GetAsync(string name);
Task<IRemoteStreamContent> GetFileAsync(string name);
Task<FileUploadOutputDto> CreateAsync(FileUploadInputDto input);
}
}

51
modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Files/FileAppService.cs

@ -1,10 +1,12 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Net.Mime;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.BlobStoring;
using Volo.Abp.Content;
using Volo.Abp.Validation;
using Volo.Blogging.Areas.Blog.Helpers;
@ -30,26 +32,61 @@ namespace Volo.Blogging.Files
};
}
public virtual async Task<IRemoteStreamContent> GetFileAsync(string name)
{
var fileStream = await BlobContainer.GetAsync(name);
return new RemoteStreamContent(fileStream, name, GetByExtension(Path.GetExtension(name)), disposeStream: true);
}
private static string GetByExtension(string extension)
{
extension = extension.RemovePreFix(".").ToLowerInvariant();
switch (extension)
{
case "png":
return "image/png";
case "gif":
return "image/gif";
case "jpg":
case "jpeg":
return "image/jpeg";
//TODO: Add other extensions too..
default:
return "application/octet-stream";
}
}
public virtual async Task<FileUploadOutputDto> CreateAsync(FileUploadInputDto input)
{
if (input.Bytes.IsNullOrEmpty())
if (input.File == null)
{
ThrowValidationException("Bytes of file can not be null or empty!", "Bytes");
ThrowValidationException("Bytes of file can not be null or empty!", nameof(input.File));
}
if (input.Bytes.Length > BloggingWebConsts.FileUploading.MaxFileSize)
if (input.File.ContentLength > BloggingWebConsts.FileUploading.MaxFileSize)
{
throw new UserFriendlyException($"File exceeds the maximum upload size ({BloggingWebConsts.FileUploading.MaxFileSizeAsMegabytes} MB)!");
}
if (!ImageFormatHelper.IsValidImage(input.Bytes, FileUploadConsts.AllowedImageUploadFormats))
var position = input.File.GetStream().Position;
if (!ImageFormatHelper.IsValidImage(input.File.GetStream(), FileUploadConsts.AllowedImageUploadFormats))
{
throw new UserFriendlyException("Invalid image format!");
}
// IsValidImage may change the position of the stream
if (input.File.GetStream().CanSeek)
{
input.File.GetStream().Position = position;
}
var uniqueFileName = GenerateUniqueFileName(Path.GetExtension(input.Name));
await BlobContainer.SaveAsync(uniqueFileName, input.Bytes);
await BlobContainer.SaveAsync(uniqueFileName, input.File.GetStream());
return new FileUploadOutputDto
{

11
modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Files/ImageFormatHelper.cs

@ -7,20 +7,17 @@ namespace Volo.Blogging.Areas.Blog.Helpers
{
public class ImageFormatHelper
{
public static ImageFormat GetImageRawFormat(byte[] fileBytes)
public static ImageFormat GetImageRawFormat(Stream stream)
{
using (var memoryStream = new MemoryStream(fileBytes))
{
return System.Drawing.Image.FromStream(memoryStream).RawFormat;
}
return System.Drawing.Image.FromStream(stream).RawFormat;
}
public static bool IsValidImage(byte[] fileBytes, ICollection<ImageFormat> validFormats)
public static bool IsValidImage(Stream stream, ICollection<ImageFormat> validFormats)
{
// System.Drawing only works on windows => https://docs.microsoft.com/en-us/dotnet/api/system.drawing.image?view=net-5.0#remarks
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var imageFormat = GetImageRawFormat(fileBytes);
var imageFormat = GetImageRawFormat(stream);
return validFormats.Contains(imageFormat);
}

9
modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/BlogFilesClientProxy.Generated.cs

@ -7,6 +7,7 @@ using Volo.Abp.Http.Modeling;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.Blogging.Files;
using Volo.Abp.Content;
// ReSharper disable once CheckNamespace
namespace Volo.Blogging.ClientProxies
@ -23,6 +24,14 @@ namespace Volo.Blogging.ClientProxies
});
}
public virtual async Task<IRemoteStreamContent> GetFileAsync(string name)
{
return await RequestAsync<IRemoteStreamContent>(nameof(GetFileAsync), new ClientProxyRequestTypeValue
{
{ typeof(string), name }
});
}
public virtual async Task<FileUploadOutputDto> CreateAsync(FileUploadInputDto input)
{
return await RequestAsync<FileUploadOutputDto>(nameof(CreateAsync), new ClientProxyRequestTypeValue

69
modules/blogging/src/Volo.Blogging.HttpApi.Client/ClientProxies/blogging-generate-proxy.json

@ -51,9 +51,9 @@
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Files.IFileAppService"
},
"GetForWebAsyncByName": {
"uniqueName": "GetForWebAsyncByName",
"name": "GetForWebAsync",
"GetFileAsyncByName": {
"uniqueName": "GetFileAsyncByName",
"name": "GetFileAsync",
"httpMethod": "GET",
"url": "api/blogging/files/www/{name}",
"supportedVersions": [],
@ -82,17 +82,17 @@
}
],
"returnValue": {
"type": "Microsoft.AspNetCore.Mvc.FileResult",
"typeSimple": "Microsoft.AspNetCore.Mvc.FileResult"
"type": "Volo.Abp.Content.IRemoteStreamContent",
"typeSimple": "Volo.Abp.Content.IRemoteStreamContent"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.BlogFilesController"
"implementFrom": "Volo.Blogging.Files.IFileAppService"
},
"CreateAsyncByInput": {
"uniqueName": "CreateAsyncByInput",
"name": "CreateAsync",
"httpMethod": "POST",
"url": "api/blogging/files",
"url": "api/blogging/files/images/upload",
"supportedVersions": [],
"parametersOnMethod": [
{
@ -107,60 +107,35 @@
"parameters": [
{
"nameOnMethod": "input",
"name": "input",
"name": "File",
"jsonName": null,
"type": "Volo.Blogging.Files.FileUploadInputDto",
"typeSimple": "Volo.Blogging.Files.FileUploadInputDto",
"type": "Volo.Abp.Content.IRemoteStreamContent",
"typeSimple": "Volo.Abp.Content.IRemoteStreamContent",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "Body",
"descriptorName": ""
}
],
"returnValue": {
"type": "Volo.Blogging.Files.FileUploadOutputDto",
"typeSimple": "Volo.Blogging.Files.FileUploadOutputDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.Files.IFileAppService"
},
"UploadImageByFile": {
"uniqueName": "UploadImageByFile",
"name": "UploadImage",
"httpMethod": "POST",
"url": "api/blogging/files/images/upload",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "file",
"typeAsString": "Microsoft.AspNetCore.Http.IFormFile, Microsoft.AspNetCore.Http.Features",
"type": "Microsoft.AspNetCore.Http.IFormFile",
"typeSimple": "Microsoft.AspNetCore.Http.IFormFile",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
"bindingSourceId": "FormFile",
"descriptorName": "input"
},
{
"nameOnMethod": "file",
"name": "file",
"nameOnMethod": "input",
"name": "Name",
"jsonName": null,
"type": "Microsoft.AspNetCore.Http.IFormFile",
"typeSimple": "Microsoft.AspNetCore.Http.IFormFile",
"type": "System.String",
"typeSimple": "string",
"isOptional": false,
"defaultValue": null,
"constraintTypes": null,
"bindingSourceId": "FormFile",
"descriptorName": ""
"bindingSourceId": "ModelBinding",
"descriptorName": "input"
}
],
"returnValue": {
"type": "Microsoft.AspNetCore.Mvc.JsonResult",
"typeSimple": "Microsoft.AspNetCore.Mvc.JsonResult"
"type": "Volo.Blogging.Files.FileUploadOutputDto",
"typeSimple": "Volo.Blogging.Files.FileUploadOutputDto"
},
"allowAnonymous": null,
"implementFrom": "Volo.Blogging.BlogFilesController"
"implementFrom": "Volo.Blogging.Files.IFileAppService"
}
}
},

48
modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/BlogFilesController.cs

@ -1,11 +1,8 @@
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Http;
using Volo.Blogging.Areas.Blog.Models;
using Volo.Abp.Content;
using Volo.Blogging.Files;
namespace Volo.Blogging
@ -31,51 +28,16 @@ namespace Volo.Blogging
[HttpGet]
[Route("www/{name}")]
public async Task<FileResult> GetForWebAsync(string name) //TODO: output cache would be good
public async Task<IRemoteStreamContent> GetFileAsync(string name)
{
var file = await _fileAppService.GetAsync(name);
return File(
file.Bytes,
MimeTypes.GetByExtension(Path.GetExtension(name))
);
return await _fileAppService.GetFileAsync(name);
}
[HttpPost]
[Route("images/upload")]
public Task<FileUploadOutputDto> CreateAsync(FileUploadInputDto input)
{
return _fileAppService.CreateAsync(input);
}
[HttpPost]
[Route("images/upload")]
public async Task<JsonResult> UploadImage(IFormFile file)
{
//TODO: localize exception messages
if (file == null)
{
throw new UserFriendlyException("No file found!");
}
if (file.Length <= 0)
{
throw new UserFriendlyException("File is empty!");
}
if (!file.ContentType.Contains("image"))
{
throw new UserFriendlyException("Not a valid image!");
}
var output = await _fileAppService.CreateAsync(
new FileUploadInputDto
{
Bytes = file.GetAllBytes(),
Name = file.FileName
}
);
return Json(new FileUploadResult(output.WebUrl));
}
}
}

6
modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/BloggingHttpApiModule.cs

@ -4,6 +4,7 @@ using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Blogging.Localization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Blogging.Files;
namespace Volo.Blogging
{
@ -28,6 +29,11 @@ namespace Volo.Blogging
.Get<BloggingResource>()
.AddBaseTypes(typeof(AbpUiResource));
});
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(FileUploadInputDto));
});
}
}
}

12
modules/blogging/src/Volo.Blogging.HttpApi/Volo/Blogging/FileUploadResult.cs

@ -1,12 +0,0 @@
namespace Volo.Blogging.Areas.Blog.Models
{
public class FileUploadResult
{
public string FileUrl { get; set; }
public FileUploadResult(string fileUrl)
{
FileUrl = fileUrl;
}
}
}

14
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/edit.js

@ -13,15 +13,15 @@ $(function () {
var $postFormSubmitButton = $('#PostFormSubmitButton');
var setCoverImage = function (file) {
$postCoverImage.val(file.fileUrl);
$coverImage.attr('src', file.fileUrl);
$postCoverImage.val(file.webUrl);
$coverImage.attr('src', file.webUrl);
$postFormSubmitButton.removeAttr('disabled');
};
var uploadCoverImage = function (file) {
var formData = new FormData();
formData.append('file', file);
formData.append('name', file.name);
$.ajax({
type: 'POST',
url: '/api/blogging/files/images/upload',
@ -63,7 +63,7 @@ $(function () {
var uploadImage = function (file, callbackFn) {
var formData = new FormData();
formData.append('file', file);
formData.append('name', file.name);
$.ajax({
type: 'POST',
url: '/api/blogging/files/images/upload',
@ -71,7 +71,7 @@ $(function () {
contentType: false,
processData: false,
success: function (response) {
callbackFn(response.fileUrl);
callbackFn(response.webUrl);
},
});
};
@ -87,8 +87,8 @@ $(function () {
addImageBlobHook: function (blob, callback, source) {
var imageAltText = blob.name;
uploadImage(blob, function (fileUrl) {
callback(fileUrl, imageAltText);
uploadImage(blob, function (webUrl) {
callback(webUrl, imageAltText);
});
},
},

14
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/new.js

@ -13,8 +13,8 @@ $(function () {
var $postFormSubmitButton = $('#PostFormSubmitButton');
var setCoverImage = function (file) {
$postCoverImage.val(file.fileUrl);
$coverImage.attr('src', file.fileUrl);
$postCoverImage.val(file.webUrl);
$coverImage.attr('src', file.webUrl);
$coverImage.show();
$postFormSubmitButton.removeAttr('disabled');
};
@ -22,7 +22,7 @@ $(function () {
var uploadCoverImage = function (file) {
var formData = new FormData();
formData.append('file', file);
formData.append('name', file.name);
$.ajax({
type: 'POST',
url: '/api/blogging/files/images/upload',
@ -47,7 +47,7 @@ $(function () {
var uploadImage = function (file, callbackFn) {
var formData = new FormData();
formData.append('file', file);
formData.append('name', file.name);
$.ajax({
type: 'POST',
url: '/api/blogging/files/images/upload',
@ -55,7 +55,7 @@ $(function () {
contentType: false,
processData: false,
success: function (response) {
callbackFn(response.fileUrl);
callbackFn(response.webUrl);
},
});
};
@ -70,8 +70,8 @@ $(function () {
addImageBlobHook: function (blob, callback, source) {
var imageAltText = blob.name;
uploadImage(blob, function (fileUrl) {
callback(fileUrl, imageAltText);
uploadImage(blob, function (webUrl) {
callback(webUrl, imageAltText);
});
},
},

12
modules/blogging/src/Volo.Blogging.Web/wwwroot/client-proxies/blogging-proxy.js

@ -18,7 +18,7 @@
}, ajaxParams));
};
volo.blogging.blogFiles.getForWeb = function(name, ajaxParams) {
volo.blogging.blogFiles.getFile = function(name, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/files/www/' + name + '',
type: 'GET'
@ -27,15 +27,7 @@
volo.blogging.blogFiles.create = function(input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/files',
type: 'POST',
data: JSON.stringify(input)
}, ajaxParams));
};
volo.blogging.blogFiles.uploadImage = function(file, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/blogging/files/images/upload',
url: abp.appPath + 'api/blogging/files/images/upload' + abp.utils.buildQueryString([{ name: 'name', value: input.name }]) + '',
type: 'POST'
}, ajaxParams));
};

Loading…
Cancel
Save