diff --git a/docs/en/Tutorials/Part-3.md b/docs/en/Tutorials/Part-3.md
index 41c4781421..03daab1843 100644
--- a/docs/en/Tutorials/Part-3.md
+++ b/docs/en/Tutorials/Part-3.md
@@ -709,7 +709,7 @@ Open `/src/app/book/book.component.html` and make the following changes:
-
@@ -844,7 +844,7 @@ Also replace `` with the following code p
````html
-
+
{%{{{ '::Close' | abpLocalization }}}%}
diff --git a/docs/en/Tutorials/Part-9.md b/docs/en/Tutorials/Part-9.md
index 55c077bd9c..1fb4d0e703 100644
--- a/docs/en/Tutorials/Part-9.md
+++ b/docs/en/Tutorials/Part-9.md
@@ -792,7 +792,7 @@ Open the `/src/app/author/author.component.html` and replace the content as belo
-
+
{%{{{ '::Close' | abpLocalization }}}%}
diff --git a/docs/en/UI/Angular/Entity-Action-Extensions.md b/docs/en/UI/Angular/Entity-Action-Extensions.md
index fd22e293fd..1ee0a3b70a 100644
--- a/docs/en/UI/Angular/Entity-Action-Extensions.md
+++ b/docs/en/UI/Angular/Entity-Action-Extensions.md
@@ -180,7 +180,7 @@ Let's employ dependency injection to extend the functionality of `IdentityModule
-
+
{%{{{ 'AbpUi::Close' | abpLocalization }}}%}
diff --git a/docs/en/UI/Angular/How-Replaceable-Components-Work-with-Extensions.md b/docs/en/UI/Angular/How-Replaceable-Components-Work-with-Extensions.md
index d942975646..147f8010a6 100644
--- a/docs/en/UI/Angular/How-Replaceable-Components-Work-with-Extensions.md
+++ b/docs/en/UI/Angular/How-Replaceable-Components-Work-with-Extensions.md
@@ -215,7 +215,7 @@ Open the generated `src/app/my-role/my-role.component.html` file and replace its
-
+
{%{{{ 'AbpIdentity::Cancel' | abpLocalization }}}%}
{%{{{
diff --git a/docs/en/UI/Angular/Modal.md b/docs/en/UI/Angular/Modal.md
index f1583d4813..144f38e842 100644
--- a/docs/en/UI/Angular/Modal.md
+++ b/docs/en/UI/Angular/Modal.md
@@ -6,7 +6,7 @@ The `abp-modal` provides some additional benefits:
- It is **flexible**. You can pass header, body, footer templates easily by adding the templates to the `abp-modal` content. It can also be implemented quickly.
- Provides several inputs be able to customize the modal and several outputs be able to listen to some events.
- - Automatically detects the close button which has a `#abpClose` template variable and closes the modal when pressed this button.
+ - Automatically detects the close button which has a `abpClose` directive attached to and closes the modal when pressed this button.
- Automatically detects the `abp-button` and triggers its loading spinner when the `busy` input value of the modal component is true.
- Automatically checks if the form inside the modal **has changed, but not saved**. It warns the user by displaying a [confirmation popup](Confirmation-Service) in this case when a user tries to close the modal or refresh/close the tab of the browser.
@@ -47,7 +47,7 @@ You can add the `abp-modal` to your component very quickly. See an example:
- Close
+ Close
```
@@ -116,7 +116,7 @@ See an example form inside a modal:
-
+
Cancel
diff --git a/docs/en/UI/Angular/Page-Component.md b/docs/en/UI/Angular/Page-Component.md
new file mode 100644
index 0000000000..a9e9857142
--- /dev/null
+++ b/docs/en/UI/Angular/Page-Component.md
@@ -0,0 +1,218 @@
+# Page Component
+
+ABP provides a component that wraps your content with some built-in components to reduce the amount of code you need to write.
+
+If the template of a component looks as follows, you can utilize the `abp-page` component.
+
+Let's look at the following example without `abp-page` component.
+
+`dashboard.component.ts`
+
+```html
+
+
+
{{ '::Dashboard' | abpLocalization }}
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Page Parts
+
+PageComponent divides the template shown above into three parts, `title`, `breadcrumb`, `toolbar`. Each can be configured separately. There, also, is an enum exported from the package that describes each part.
+
+```javascript
+export enum PageParts {
+ title = 'PageTitleContainerComponent',
+ breadcrumb = 'PageBreadcrumbContainerComponent',
+ toolbar = 'PageToolbarContainerComponent',
+}
+
+// You can import this enum from -> import { PageParts } from '@abp/ng.components/page';
+```
+
+## Usage
+
+Firstly, you need to import `PageModule` from `@abp/ng.components/page` as follows:
+
+`dashboard.module.ts`
+
+```javascript
+import { PageModule } from '@abp/ng.components/page';
+import { DashboardComponent } from './dashboard.component';
+
+@NgModule({
+ declarations: [DashboardComponent],
+ imports: [PageModule]
+})
+export class DashboardModule {}
+```
+
+And change the template of `dashboard.component.ts` to the following:
+
+```html
+
+
+
+
+
+```
+
+## Inputs
+
+* title: `string`: Will be be rendered within `h1.content-header-title`. If not provided, the parent `div` will not be rendered
+* breadcrumb: `boolean`: Determines whether to render `abp-breadcrumb`. Default is `true`.
+* toolbar: `any`: Will be passed into `abp-page-toolbar` component through `record` input. If your page does not contain `abp-page-toolbar`, you can simply omit this field.
+
+## Overriding template
+
+If you need to replace the template of any part, you can use the following sub-components.
+
+```html
+
+
+
+
Custom Title
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+You do not have to provide them all. You can just use which one you need to replace. These components have priority over the inputs declared above. If you use these components, you can omit the inputs.
+
+## PagePartDirective
+
+`PageModule` provides a structural directive that is used internally within `PageComponent` and can also be used externally.
+
+`PageComponent` employs this directive internally as follows:
+
+```html
+
+
+
+```
+
+It also can take a context input as follows:
+
+```html
+
+
+
+```
+
+Its render strategy can be provided through Angular's Dependency Injection system.
+
+It expects a service through the `PAGE_RENDER_STRATEGY` injection token that implements the following interface.
+
+```javascript
+interface PageRenderStrategy {
+ shouldRender(type?: string): boolean | Observable;
+ onInit?(type?: string, injector?: Injector, context?: any): void;
+ onDestroy?(type?: string, injector?: Injector, context?: any): void;
+ onContextUpdate?(change?: SimpleChange): void;
+}
+```
+
+* `shouldRender` (required): It takes a string input named `type` and expects a `boolean` or `Observable` in return.
+* `onInit` (optional): Will be called when the directive is initiated. Three inputs will be passed into this method.
+ * `type`: type of the page part
+ * `injector`: injector of the directive which could be used to retrieve anything from directive's DI tree.
+ * `context`: whatever context is available at the initialization phase.
+* `onDestroy` (optional): Will be called when the directive is destroyed. The parameters are the same with `onInit`
+* `onContextUpdate` (optional): Will be called when the context is updated.
+ * `change`: changes of the `context` will be passed through this method.
+
+Let's see everything in action.
+
+```javascript
+import {
+ PageModule,
+ PageRenderStrategy,
+ PageParts,
+ PAGE_RENDER_STRATEGY
+} from '@abp/ng.components/page';
+
+@Injectable()
+export class MyPageRenderStrategy implements PageRenderStrategy {
+ shouldRender(type: string) {
+ // meaning everything but breadcrumb and custom-part will be rendered
+ return type !== PageParts.breadcrumb && type !== 'custom-part';
+ }
+
+ /**
+ * shouldRender can also return an Observable which means
+ * an async service can be used within.
+
+ constructor(private service: SomeAsyncService) {}
+
+ shouldRender(type: string) {
+ return this.service.checkTypeAsync(type).pipe(map(val => val.isTrue()));
+ }
+ */
+
+ onInit(type: string, injector: Injector, context: any) {
+ // this method will be called in ngOnInit of the directive
+ }
+
+ onDestroy(type: string, injector: Injector, context: any) {
+ // this method will be called in ngOnDestroy of the directive
+ }
+
+ onContextUpdate?(change?: SimpleChange) {
+ // this method will be called everytime context is updated within the directive
+ }
+}
+
+@Component({
+ selector: 'app-dashboard',
+ template: `
+
+
+ New Dashboard
+
+
+
+
Inner Title
+
+
+ `
+})
+export class DashboardComponent {}
+
+@NgModule({
+ imports: [PageModule],
+ declarations: [DashboardComponent],
+ providers: [
+ {
+ provide: PAGE_RENDER_STRATEGY,
+ useClass: MyPageRenderStrategy,
+ }
+ ]
+})
+export class DashboardModule {}
+```
+
+## See Also
+
+- [Page Toolbar Extensions for Angular UI](./Page-Page-Toolbar-Extensions.md)
diff --git a/docs/en/UI/Angular/Permission-Management-Component-Replacement.md b/docs/en/UI/Angular/Permission-Management-Component-Replacement.md
index 9ae712cedd..b6fcef3bb9 100644
--- a/docs/en/UI/Angular/Permission-Management-Component-Replacement.md
+++ b/docs/en/UI/Angular/Permission-Management-Component-Replacement.md
@@ -459,7 +459,7 @@ Open the generated `permission-management.component.html` in `src/app/permission
-
+
{%{{{ 'AbpIdentity::Cancel' | abpLocalization }}}%}
{%{{{
diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json
index 23d9cc761d..f4e07c9521 100644
--- a/docs/en/docs-nav.json
+++ b/docs/en/docs-nav.json
@@ -882,6 +882,15 @@
]
}
]
+ },
+ {
+ "text": "Components",
+ "items": [
+ {
+ "text": "Page",
+ "path": "UI/Angular/Page-Component.md"
+ }
+ ]
}
]
},
diff --git a/docs/pt-BR/Tutorials/Angular/Part-II.md b/docs/pt-BR/Tutorials/Angular/Part-II.md
index b75fa9e21c..b4b86350b0 100644
--- a/docs/pt-BR/Tutorials/Angular/Part-II.md
+++ b/docs/pt-BR/Tutorials/Angular/Part-II.md
@@ -90,7 +90,7 @@ Abra o `book-list.component.html`e adicione o `abp-modal`para mostrar / ocultar
-
+
Cancel
@@ -276,7 +276,7 @@ Abra o `book-list.component.html`e adicione um `abp-button`para salvar o formul
```html
-
+
Cancel
diff --git a/docs/zh-Hans/Tutorials/Part-3.md b/docs/zh-Hans/Tutorials/Part-3.md
index 7ad96a0465..fec101c2a2 100644
--- a/docs/zh-Hans/Tutorials/Part-3.md
+++ b/docs/zh-Hans/Tutorials/Part-3.md
@@ -718,7 +718,7 @@ export class BookComponent implements OnInit {
-
+
{%{{{ '::Close' | abpLocalization }}}%}
@@ -859,7 +859,7 @@ export class BookComponent implements OnInit {
````html
-
+
{%{{{ '::Close' | abpLocalization }}}%}
diff --git a/docs/zh-Hans/UI/Angular/Permission-Management-Component-Replacement.md b/docs/zh-Hans/UI/Angular/Permission-Management-Component-Replacement.md
index 0b1f71035e..3ea2db6f51 100644
--- a/docs/zh-Hans/UI/Angular/Permission-Management-Component-Replacement.md
+++ b/docs/zh-Hans/UI/Angular/Permission-Management-Component-Replacement.md
@@ -459,7 +459,7 @@ function getPermissions(groups: PermissionManagement.Group[]): PermissionManagem
-
+
{%{{{ 'AbpIdentity::Cancel' | abpLocalization }}}%}
{%{{{
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/AbpRemoteStreamContentModelBinder.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/AbpRemoteStreamContentModelBinder.cs
index 8b7264fef0..da58641d7e 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/AbpRemoteStreamContentModelBinder.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ContentFormatters/AbpRemoteStreamContentModelBinder.cs
@@ -115,13 +115,6 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
}
}
}
- else
- {
- postedFiles.Add(new RemoteStreamContent(request.Body)
- {
- ContentType = request.ContentType
- });
- }
}
}
}
diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/RequestPayloadBuilder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/RequestPayloadBuilder.cs
index 8532f02c7c..1096fa971e 100644
--- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/RequestPayloadBuilder.cs
+++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/RequestPayloadBuilder.cs
@@ -53,17 +53,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
return null;
}
- if (value is IRemoteStreamContent remoteStreamContent)
- {
- var content = new StreamContent(remoteStreamContent.GetStream());
- content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(remoteStreamContent.ContentType);
- content.Headers.ContentLength = remoteStreamContent.ContentLength;
- return content;
- }
- else
- {
- return new StringContent(jsonSerializer.Serialize(value), Encoding.UTF8, MimeTypes.Application.Json);
- }
+ return new StringContent(jsonSerializer.Serialize(value), Encoding.UTF8, MimeTypes.Application.Json);
}
private static HttpContent GenerateFormPostData(ActionApiDescriptionModel action, IReadOnlyDictionary methodArguments)
@@ -80,7 +70,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
if (parameters.Any(x => x.BindingSourceId == ParameterBindingSources.FormFile))
{
- var postDataBuilder = new MultipartFormDataContent();
+ var formData = new MultipartFormDataContent();
foreach (var parameter in parameters)
{
var value = HttpActionParameterHelper.FindParameterValue(methodArguments, parameter);
@@ -91,32 +81,42 @@ namespace Volo.Abp.Http.Client.DynamicProxying
if (value is IRemoteStreamContent remoteStreamContent)
{
- var streamContent = new StreamContent(remoteStreamContent.GetStream());
+ var stream = remoteStreamContent.GetStream();
+ if (stream.CanSeek)
+ {
+ stream.Position = 0;
+ }
+ var streamContent = new StreamContent(stream);
if (!remoteStreamContent.ContentType.IsNullOrWhiteSpace())
{
streamContent.Headers.ContentType = new MediaTypeHeaderValue(remoteStreamContent.ContentType);
}
- postDataBuilder.Add(streamContent, parameter.Name, parameter.Name);
+ formData.Add(streamContent, parameter.Name, parameter.Name);
}
else if (value is IEnumerable remoteStreamContents)
{
foreach (var content in remoteStreamContents)
{
- var streamContent = new StreamContent(content.GetStream());
+ var stream = content.GetStream();
+ if (stream.CanSeek)
+ {
+ stream.Position = 0;
+ }
+ var streamContent = new StreamContent(stream);
if (!content.ContentType.IsNullOrWhiteSpace())
{
streamContent.Headers.ContentType = new MediaTypeHeaderValue(content.ContentType);
}
- postDataBuilder.Add(streamContent, parameter.Name, parameter.Name);
+ formData.Add(streamContent, parameter.Name, parameter.Name);
}
}
else
{
- postDataBuilder.Add(new StringContent(value.ToString(), Encoding.UTF8), parameter.Name);
+ formData.Add(new StringContent(value.ToString(), Encoding.UTF8), parameter.Name);
}
}
- return postDataBuilder;
+ return formData;
}
else
{
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs
index 15491f9b21..e74c9d52e8 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController.cs
@@ -25,11 +25,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
[HttpPost]
[Route("Upload")]
- public async Task UploadAsync([FromBody]IRemoteStreamContent streamContent)
+ public async Task UploadAsync(IRemoteStreamContent file)
{
- using (var reader = new StreamReader(streamContent.GetStream()))
+ using (var reader = new StreamReader(file.GetStream()))
{
- return await reader.ReadToEndAsync() + ":" + streamContent.ContentType;
+ return await reader.ReadToEndAsync() + ":" + file.ContentType;
}
}
}
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs
index 3d49a5b3ff..12745da732 100644
--- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ContentFormatters/RemoteStreamContentTestController_Tests.cs
@@ -1,5 +1,6 @@
using System.IO;
using System.Net.Http;
+using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Shouldly;
@@ -25,8 +26,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ContentFormatters
var memoryStream = new MemoryStream();
await memoryStream.WriteAsync(Encoding.UTF8.GetBytes("UploadAsync"));
memoryStream.Position = 0;
- requestMessage.Content = new StreamContent(memoryStream);
- requestMessage.Content.Headers.Add("Content-Type", "application/rtf");
+
+ var streamContent = new StreamContent(memoryStream);
+ streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/rtf");
+
+ requestMessage.Content = new MultipartFormDataContent {{streamContent, "file", "file"}};
var response = await Client.SendAsync(requestMessage);
diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/MediaDescriptors/CreateMediaInputWithStream.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/MediaDescriptors/CreateMediaInputWithStream.cs
new file mode 100644
index 0000000000..a8a13b2ed2
--- /dev/null
+++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/MediaDescriptors/CreateMediaInputWithStream.cs
@@ -0,0 +1,16 @@
+using System.ComponentModel.DataAnnotations;
+using Volo.Abp.Content;
+using Volo.Abp.Validation;
+using Volo.CmsKit.MediaDescriptors;
+
+namespace Volo.CmsKit.Admin.MediaDescriptors
+{
+ public class CreateMediaInputWithStream
+ {
+ [Required]
+ [DynamicStringLength(typeof(MediaDescriptorConsts), nameof(MediaDescriptorConsts.MaxNameLength))]
+ public string Name { get; set; }
+
+ public IRemoteStreamContent File { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/MediaDescriptors/IMediaDescriptorAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/MediaDescriptors/IMediaDescriptorAdminAppService.cs
index eb4819dd06..83cd14e90c 100644
--- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/MediaDescriptors/IMediaDescriptorAdminAppService.cs
+++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/MediaDescriptors/IMediaDescriptorAdminAppService.cs
@@ -6,7 +6,7 @@ namespace Volo.CmsKit.Admin.MediaDescriptors
{
public interface IMediaDescriptorAdminAppService : IApplicationService
{
- Task CreateAsync(CreateMediaInputStream inputStream);
+ Task CreateAsync(string entityType, CreateMediaInputWithStream inputStream);
Task DeleteAsync(Guid id);
}
diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminAppService.cs
index b359d55244..fa799cb65b 100644
--- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminAppService.cs
+++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminAppService.cs
@@ -1,11 +1,9 @@
using System;
using System.Threading.Tasks;
-using Microsoft.AspNetCore.Authorization;
using Volo.Abp.BlobStoring;
using Volo.Abp.GlobalFeatures;
using Volo.CmsKit.GlobalFeatures;
using Volo.CmsKit.MediaDescriptors;
-using Volo.CmsKit.Permissions;
namespace Volo.CmsKit.Admin.MediaDescriptors
{
@@ -29,16 +27,16 @@ namespace Volo.CmsKit.Admin.MediaDescriptors
MediaDescriptorDefinitionStore = mediaDescriptorDefinitionStore;
}
- public virtual async Task CreateAsync(CreateMediaInputStream inputStream)
+ public virtual async Task CreateAsync(string entityType, CreateMediaInputWithStream inputStream)
{
- var definition = await MediaDescriptorDefinitionStore.GetAsync(inputStream.EntityType);
+ var definition = await MediaDescriptorDefinitionStore.GetAsync(entityType);
/* TODO: Shouldn't CreatePolicies be a dictionary and we check for inputStream.EntityType? */
await CheckAnyOfPoliciesAsync(definition.CreatePolicies);
- using (var stream = inputStream.GetStream())
+ using (var stream = inputStream.File.GetStream())
{
- var newEntity = await MediaDescriptorManager.CreateAsync(inputStream.EntityType, inputStream.Name, inputStream.ContentType, inputStream.ContentLength ?? 0);
+ var newEntity = await MediaDescriptorManager.CreateAsync(entityType, inputStream.Name, inputStream.File.ContentType, inputStream.File.ContentLength ?? 0);
await MediaContainer.SaveAsync(newEntity.Id.ToString(), stream);
await MediaDescriptorRepository.InsertAsync(newEntity);
diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/CmsKitAdminHttpApiModule.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/CmsKitAdminHttpApiModule.cs
index 5d84242bcd..bb573d55e6 100644
--- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/CmsKitAdminHttpApiModule.cs
+++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/CmsKitAdminHttpApiModule.cs
@@ -1,5 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;
+using Volo.CmsKit.Admin.MediaDescriptors;
namespace Volo.CmsKit.Admin
{
@@ -16,5 +18,13 @@ namespace Volo.CmsKit.Admin
mvcBuilder.AddApplicationPartIfNotExists(typeof(CmsKitAdminHttpApiModule).Assembly);
});
}
+
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.ConventionalControllers.FormBodyBindingIgnoredTypes.Add(typeof(CreateMediaInputWithStream));
+ });
+ }
}
}
diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs
index da84dc8a3d..07c1315eed 100644
--- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs
+++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs
@@ -25,10 +25,10 @@ namespace Volo.CmsKit.Admin.MediaDescriptors
}
[HttpPost]
- [NonAction]
- public virtual Task CreateAsync(CreateMediaInputStream inputStream)
+ [Route("{entityType}")]
+ public virtual Task CreateAsync(string entityType, CreateMediaInputWithStream inputStream)
{
- return MediaDescriptorAdminAppService.CreateAsync(inputStream);
+ return MediaDescriptorAdminAppService.CreateAsync(entityType, inputStream);
}
[HttpDelete]
@@ -37,26 +37,5 @@ namespace Volo.CmsKit.Admin.MediaDescriptors
{
return MediaDescriptorAdminAppService.DeleteAsync(id);
}
-
- [HttpPost]
- [Route("{entityType}")]
- public virtual async Task UploadAsync(string entityType, IFormFile file)
- {
- if (file == null)
- {
- return BadRequest();
- }
-
- var inputStream = new CreateMediaInputStream(file.OpenReadStream())
- {
- EntityType = entityType,
- ContentType = file.ContentType,
- Name = file.FileName
- };
-
- var mediaDescriptorDto = await MediaDescriptorAdminAppService.CreateAsync(inputStream);
-
- return StatusCode((int)HttpStatusCode.Created, mediaDescriptorDto);
- }
}
}
\ No newline at end of file
diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/MediaDescriptors/MediaDescriptorAdminAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/MediaDescriptors/MediaDescriptorAdminAppService_Tests.cs
index 52169eddbe..38a8b472bd 100644
--- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/MediaDescriptors/MediaDescriptorAdminAppService_Tests.cs
+++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/MediaDescriptors/MediaDescriptorAdminAppService_Tests.cs
@@ -3,6 +3,7 @@ using System.IO;
using System.Text;
using System.Threading.Tasks;
using Shouldly;
+using Volo.Abp.Content;
using Volo.CmsKit.Admin.MediaDescriptors;
using Xunit;
@@ -31,14 +32,14 @@ namespace Volo.CmsKit.MediaDescriptors
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(mediaContent));
- var inputStream = new CreateMediaInputStream(stream)
+ var media = await _mediaDescriptorAdminAppService.CreateAsync(_cmsKitTestData.Media_1_EntityType, new CreateMediaInputWithStream
{
- ContentType = mediaType,
Name = mediaName,
- EntityType = _cmsKitTestData.Media_1_EntityType
- };
-
- var media = await _mediaDescriptorAdminAppService.CreateAsync(inputStream);
+ File = new RemoteStreamContent(stream)
+ {
+ ContentType = mediaType
+ }
+ });
media.ShouldNotBeNull();
}
diff --git a/npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.html b/npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.html
index e8b2df61e1..91e68d9a0a 100644
--- a/npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.html
+++ b/npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.html
@@ -3,7 +3,7 @@