有人问过类似的问题,但是在浏览了所有有关该主题的博客文章之后,我仍然无法弄清这一点,请原谅。
我正在创建一个简单的博客,该博客包含两个部分(针对该问题),一个是Angular 8中的前端SPA,另一个是ASP.NET Core 3中的后端API。在我的前端的一部分中,我试图上传用作新创建的博客的图像的图像。当我尝试上载图像时,后端中生成的IFormFile总是出现在null
中。以下是代码,非常感谢您的帮助!
new-blog.component.html:
<form [formGroup]="newBlogForm" (ngSubmit)="onSubmit(newBlogForm.value)">
<div>
<label for="Name">
Blog Name
</label>
<input type="text" formControlName="Name">
</div>
<div>
<label for="TileImage">
Tile Image
</label>
<input type="file" formControlName="TileImage">
</div>
<button type="submit">Create Blog</button>
</form>
new-blog.component.ts:
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormControl } from '@angular/forms';
import { BlogService } from '../blog-services/blog.service';
@Component({
selector: 'app-new-blog',
templateUrl: './new-blog.component.html',
styleUrls: ['./new-blog.component.css']
})
export class NewBlogComponent implements OnInit {
private newBlogForm: FormGroup;
constructor(private formBuilder: FormBuilder, private blogService: BlogService) { }
ngOnInit() {
this.newBlogForm = this.formBuilder.group({
Name: new FormControl(null),
TileImage: new FormControl(null)
});
}
onSubmit(blogData: FormData) {
console.log('new blog has been submitted.', blogData);
this.blogService.postBlog(blogData);
this.newBlogForm.reset();
}
}
来自blog.service.ts的postBlog
:
postBlog(blogData: FormData): Observable<any> {
const postBlogSubject = new Subject();
this.appOptions.subscribe(
(options) => {
const url = options.blogAPIUrl + '/Blogs';
this.http
.post(url, blogData)
.subscribe(
(blog) => {
postBlogSubject.next(blog);
}
);
}
);
return postBlogSubject.asObservable();
}
我的BlogController的签名如下所示:
[HttpPost]
public async Task<ActionResult<Blog>> PostBlog([FromForm]PostBlogModel blogModel)
使用PostBlogModel如下:
public class PostBlogModel
{
public string Name { get; set; }
public IFormFile TileImage { get; set; }
}
我已经实现了日志记录中间件来尝试调试。输出如下(由于某种原因,我看到前端发送的是application / json而不是multipart / form-data,但是我不确定为什么或如何解决...)
blogapi_1 | info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
blogapi_1 | Request finished in 170.16740000000001ms 500
blogapi_1 | info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
blogapi_1 | Request starting HTTP/1.1 OPTIONS http://localhost:5432/api/v1/Blogs
blogapi_1 | dbug: BlogAPI.Middleware.RequestResponseLoggingMiddleware[0]
blogapi_1 | HTTP Request: Headers:
blogapi_1 | key: Connection, values: keep-alive
blogapi_1 | key: Accept, values: */*
blogapi_1 | key: Accept-Encoding, values: gzip, deflate, br
blogapi_1 | key: Accept-Language, values: en-US,en-IN;q=0.9,en;q=0.8,en-GB;q=0.7
blogapi_1 | key: Host, values: localhost:5432
blogapi_1 | key: Referer, values: http://localhost:5431/blog/new-blog
blogapi_1 | key: User-Agent, values: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
blogapi_1 | key: Origin, values: http://localhost:5431
blogapi_1 | key: Access-Control-Request-Method, values: POST
blogapi_1 | key: Access-Control-Request-Headers, values: content-type
blogapi_1 | key: Sec-Fetch-Site, values: same-site
blogapi_1 | key: Sec-Fetch-Mode, values: cors
blogapi_1 |
blogapi_1 | type:
blogapi_1 | scheme: http
blogapi_1 | host+path: localhost:5432/api/v1/Blogs
blogapi_1 | queryString:
blogapi_1 | body:
blogapi_1 | info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
blogapi_1 | CORS policy execution successful.
blogapi_1 | dbug: BlogAPI.Middleware.RequestResponseLoggingMiddleware[0]
blogapi_1 | HTTP Response: Headers:
blogapi_1 | key: Access-Control-Allow-Headers, values: Content-Type
blogapi_1 | key: Access-Control-Allow-Origin, values: http://localhost:5431
blogapi_1 |
blogapi_1 | statusCode: 204
blogapi_1 | responseBody:
blogapi_1 | info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
blogapi_1 | Request finished in 58.5088ms 204
blogapi_1 | info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
blogapi_1 | Request starting HTTP/1.1 POST http://localhost:5432/api/v1/Blogs application/json 56
blogapi_1 | dbug: BlogAPI.Middleware.RequestResponseLoggingMiddleware[0]
blogapi_1 | HTTP Request: Headers:
blogapi_1 | key: Connection, values: keep-alive
blogapi_1 | key: Content-Type, values: application/json
blogapi_1 | key: Accept, values: application/json, text/plain, */*
blogapi_1 | key: Accept-Encoding, values: gzip, deflate, br
blogapi_1 | key: Accept-Language, values: en-US,en-IN;q=0.9,en;q=0.8,en-GB;q=0.7
blogapi_1 | key: Host, values: localhost:5432
blogapi_1 | key: Referer, values: http://localhost:5431/blog/new-blog
blogapi_1 | key: User-Agent, values: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
blogapi_1 | key: Origin, values: http://localhost:5431
blogapi_1 | key: Content-Length, values: 56
blogapi_1 | key: Sec-Fetch-Site, values: same-site
blogapi_1 | key: Sec-Fetch-Mode, values: cors
blogapi_1 |
blogapi_1 | type: application/json
blogapi_1 | scheme: http
blogapi_1 | host+path: localhost:5432/api/v1/Blogs
blogapi_1 | queryString:
blogapi_1 | body: {"Name":"test","TileImage":"C:\\fakepath\\DSC_0327.jpg"}
参考方案
我的BlogController看起来像这样:
[HttpPost]
public async Task<ActionResult<Blog>> PostBlog([FromForm]PostBlogModel blogModel)
似乎您想使用form-data传递数据,要实现它,可以参考以下代码示例。
.component.html
<form [formGroup]="newBlogForm" (ngSubmit)="onSubmit(newBlogForm.value)">
<div>
<label for="Name">
Blog Name
</label>
<input type="text" formControlName="Name">
</div>
<div>
<label for="TileImage">
Tile Image
</label>
<input type="file" formControlName="TileImage" (change)="onSelectFile($event)" >
</div>
<button type="submit">Create Blog</button>
</form>
.component.ts
selectedFile: File = null;
private newBlogForm: FormGroup;
constructor(private http: HttpClient) { }
ngOnInit() {
this.newBlogForm = new FormGroup({
Name: new FormControl(null),
TileImage: new FormControl(null)
});
}
onSelectFile(fileInput: any) {
this.selectedFile = <File>fileInput.target.files[0];
}
onSubmit(data) {
const formData = new FormData();
formData.append('Name', data.Name);
formData.append('TileImage', this.selectedFile);
this.http.post('your_url_here', formData)
.subscribe(res => {
alert('Uploaded!!');
});
this.newBlogForm.reset();
}
测试结果
我是SignalR的新手。我正在尝试设置一个Asp.Net Core WebAPI,以便其他客户端可以使用SignalR连接到它并获取实时数据。我的Hub类是:public class TimeHub : Hub { public async Task UpdateTime(string message) { await Clients.All.SendAs…
ASP.NET Web API 2中AuthorizeAttribute发生了什么变化? - c#我已经将项目和一组单元测试从ASP.NET Web API升级到ASP.NET Web API 2。我们将自定义DelegatingHandler用于自定义身份验证机制。它将Thread.CurrentPrincipal和HttpContext.Current.User设置为适当的System.Security.Claims.ClaimsPrincipal。…
如何在ASP.NET Core Web应用程序中增加JSON反序列化MaxDepth限制 - c#我们正在将ASP.NET Core 2.1与.NET Framework 4.6.2结合使用。我们有一个客户需要向我们的Web应用程序发送一个很大程度上嵌套的json结构。当他们进行此调用时,我们将输出以下日志并返回错误: 读取器的MaxDepth超过了32。路径“ super.long.path.to property”,第1行,位置42111。”我浏览了…
如何在ASP.NET Core(使用JavascriptService)应用程序中使Node.js代码调用csharp代码? - c#我正在将asp.net内核用于简单的Web api服务器(实际上是使用Deepstream)。虽然C#可以使用NodeServices.InvokeExportAsync完美地调用nodejs代码,但是当我尝试将Action / Func作为NodeServices.InvokeExportAsync的参数传递给nodejs时,却得到了System.Aggr…
从.NET Core 2.1降级到.NET 4.7.1时,如何使用IApplicationBuilder和IServiceCollection? - c#我不得不将我的项目从.NET Core 2.1更改为.NET 4.7.1,并且修复了几乎所有错误,但以下错误仍然困扰着我 “ IApplicationBuilder”不包含“ UseHsts”的定义,也找不到找不到接受类型为“ IApplicationBuilder”的第一个参数的扩展方法“ UseHsts”(是否缺少using指令或程序集引用?) “ IA…