Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将文件从Angular上载到ASP.NET核心Web API_C#_Angular_Typescript_Asp.net Core_Angular8 - Fatal编程技术网

C# 如何将文件从Angular上载到ASP.NET核心Web API

C# 如何将文件从Angular上载到ASP.NET核心Web API,c#,angular,typescript,asp.net-core,angular8,C#,Angular,Typescript,Asp.net Core,Angular8,有人问过类似的问题,但在浏览了所有这些和许多关于这个主题的博客文章后,我还没有弄明白这一点,所以请原谅我 为了回答这个问题,我正在创建一个简单的博客,其中包含两个部分,Angular 8中的前端SPA和ASP.NET Core 3中的后端API。在我的前端的一部分,我试图上传一个图像作为新创建的博客的图像。当我尝试上载图像时,后端生成的文件总是显示为null。下面是代码,非常感谢您的帮助 new-blog.component.html: 博客名 瓷砖图像 创建博客 new-blog.comp

有人问过类似的问题,但在浏览了所有这些和许多关于这个主题的博客文章后,我还没有弄明白这一点,所以请原谅我

为了回答这个问题,我正在创建一个简单的博客,其中包含两个部分,Angular 8中的前端SPA和ASP.NET Core 3中的后端API。在我的前端的一部分,我试图上传一个图像作为新创建的博客的图像。当我尝试上载图像时,后端生成的文件总是显示为
null
。下面是代码,非常感谢您的帮助

new-blog.component.html:


博客名
瓷砖图像
创建博客
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();
  }

}
postBlog
来自blog.service.ts:

  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();
  }
我已经实现了日志中间件来尝试调试。输出如下(我看到前端出于某种原因发送application/json而不是multipart/form数据,但我不确定为什么或如何修复…)

我的博客控制器如下所示:

[HttpPost]

public async Task<ActionResult<Blog>> PostBlog([FromForm]PostBlogModel blogModel)
[HttpPost]
公共异步任务

首先

使用
ngModel
formControlName
绑定angular只会捕获
值属性
但实际上,当我们提交表单时,我们需要
文件属性
,以便创建 适用于所有项目
元素的自定义指令,因此 我们提交了我们获得文件属性的表单

以前

之后

要使用Http上传文件,您的数据应使用允许通过Http post发送文件的
multipart/form data
进行编码,以便使用
FormData

FormData对象将使用MIME自动生成请求数据 键入现有服务器可以处理的多部分/表单数据。添加 “文件”字段,以显示您使用的扩展名可以访问的文件对象的数据 从文件路径构造。然后可以简单地创建FormData对象 传递到XMLHttpRequest:

所以你的提交方法应该是

onSubmit() {
      let formData: FormData = new FormData();
        Object.keys(this.newBlogForm.value).forEach(key => {
            formData.append(key, this.newBlogForm.value[key])
        });
    //pass formData to your service
  }
第三次

在您创建的
postBlog
方法中,您创建的
Subject
没有任何好处,您只需返回http.post,然后在调用方方法中使用指定的
subscribe
async/wait
来启动http调用

onSubmit() {
   .....
    this.postBlog(formData).subscribe(
        result => { }
    );
}

async onSubmit() {
   .....
    let res = await this.postBlog(formData).toPromise();
}

您是否尝试将包含内容类型标头的httpOptions添加到http.post?似乎您正在使用跨域服务。您的浏览器将首先发送一个HTTP选项请求,并测试返回的头是否允许它进行真正的提交。在HTTP选项测试过程中,服务器无法获取该文件。请参阅:@Yeheshuah-当我尝试添加内容类型标题时,ASP.NET core似乎无法处理输入,它仍然从角度显示正文,带有
{“Name”:“test”,“TileImage”:“C:\\fakepath\\DSC\u 0327.jpg”}
,我得到错误
System.IO.InvalidDataException:缺少内容类型边界。
@Anduin-是,这是在Docker容器中运行的,但是,正如日志显示的那样,选项请求似乎正在成功执行,并且在响应中返回了访问控制允许源代码,因为我已经为此设置了CORS策略。您是如何在post请求中设置HttpOptions的?@AngelaAmarapala我在上面的postBlog函数中添加了以下内容:
let HttpOptions:any={headers:newhttpheaders({“内容类型”:“multipart/formdata”});this.http.post(url、blogData、httpOptions)
。可能还需要补充一点,当我指定此选项时,似乎没有提出选项请求,它只是直接发送到帖子。我是angular方面的新手,你能解释一下为什么没有PostBlog和.subscribe中的异步任务,它就不能工作吗(res=>{alert('upload!!');});它不会引发异常,但不会进入方法。是否必须将FormData对象单独发送到后端?我似乎无法将FormData对象包装到另一个对象中,然后将该对象一起发送
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();
}
import { Directive, forwardRef, HostListener, ElementRef, Renderer2 } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';


@Directive({
    selector : `input[type=file][formControlName], 
    input[type=file][formControl],
    input[type=file][ngModel]`,
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: FileValueAccessorDirective,
            multi: true
        }
    ]
})
export class FileValueAccessorDirective implements ControlValueAccessor {

    constructor(private elementRef: ElementRef, private render: Renderer2) {

    }

    // Function to call when the file changes.
    onChange = (file: any) => {}


    //fire when the form value changed programmaticly
    writeValue(value: any): void {

    }

    //fire only one time to register on change event
    registerOnChange = (fn: any) => { this.onChange = fn; }


    //fire only one time to register on touched event
    registerOnTouched = (fn: any) => { }


    //Disable the input
    setDisabledState?(isDisabled: boolean): void {

    }

    //listen to change event
    @HostListener('change', ['$event.target.files'])
    handleChange(file) {
        this.onChange(file[0]);
    }

}
onSubmit() {
      let formData: FormData = new FormData();
        Object.keys(this.newBlogForm.value).forEach(key => {
            formData.append(key, this.newBlogForm.value[key])
        });
    //pass formData to your service
  }
onSubmit() {
   .....
    this.postBlog(formData).subscribe(
        result => { }
    );
}

async onSubmit() {
   .....
    let res = await this.postBlog(formData).toPromise();
}