首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >是否有一种简单的方法将表单从ASP.NET MVC转发到ASP.NET API?

是否有一种简单的方法将表单从ASP.NET MVC转发到ASP.NET API?
EN

Stack Overflow用户
提问于 2021-12-10 15:02:52
回答 2查看 132关注 0票数 0

假设我有这样一个ViewModel,它来自于ASP.NET MVC中的表单提交:

代码语言:javascript
运行
复制
public class EditProfileViewModel
{
    public string DisplayName { get; set; }
    public IFormFile Photo { get; set; }
}

我可以很容易地在控制器内接收到这个信息:

代码语言:javascript
运行
复制
public async Task<IActionResult> OnPost([FromForm] EditProfileViewModel edits)
{
    // edits contains form data, great
}

但是现在我想把它转发到后端API,也使用ASP.NET,包括文件上传。最简单的方法似乎是使用HttpClient创建一个新的表单POST,使用MultipartFormDataContent。但据我所知,虽然从表单内容到模型类的转换是在接收请求时透明地进行的,但是创建MultipartFormDataContent需要对键值对进行硬编码。

我知道这样做是有可能的:

代码语言:javascript
运行
复制
var form = new MultipartFormDataContent()
form.Add(new StringContent(edits.DisplayName), "displayName")
var content = new StreamContent(edits.Photo.OpenReadStream());
content.Headers.ContentType = MediaTypeHeaderValue.Parse(file.ContentType)
form.Add(content, "photo") // Is this the right capitalization ?? See how error prone this is?

var result = await client.PostAsync("some-api", form);

但这是冗长的,容易出现重复声明的错误。此外,要在接收端使用相同的模型类反序列化,需要了解转换魔术。

是否有更好的方法将模型类转换回MultipartFormDataContent?或者,如果这是XY问题,那么将此表单模型完全转发到后端ASP.NET API的更好方法是什么?

EN

回答 2

Stack Overflow用户

发布于 2021-12-10 15:09:59

需要了解转换魔术。

这就是要点-- MultipartFormDataContent可以用来向任何web应用程序发布表单,而且代码不知道底层解析的魔力,因为需要告诉接收端如何期望它的格式。

一个web框架可以区分大小写,而另一个则需要小写或完全匹配的大小写.或者对于数组,可以支持字段名的重复(name="foo"name="foo",.)另一个可能需要[]后缀(name="foo[]"name="foo[]",.)还有一个可能需要指数(name="foo[0]"name="foo[1]",.)。

更不用说多个层次的属性:name="foo.bar"name="foo_bar",.

因此,您必须编写自己的属性到字段名称映射代码,知道您发布到哪个框架。

票数 0
EN

Stack Overflow用户

发布于 2021-12-10 15:42:26

我用一些扩展方法和反射解决了“键值对的硬编码”问题:

代码语言:javascript
运行
复制
    public static class MultiContentExtensionMethods
    {
        public static void AddDto<TDto>(this MultipartFormDataContent multiContent, TDto dto)
        {
            List<PropertyInfo> propertyInfos = dto.GetType().GetProperties().ToList();

            foreach(var propertyInfo in propertyInfos)
            {
                if (propertyInfo.PropertyType != typeof(IFormFile) &&
                   !propertyInfo.PropertyType.Name.Contains("List")) 
                {
                    if(propertyInfo.GetValue(dto) is not null)
                        multiContent.Add(new StringContent(propertyInfo.GetValue(dto).ToString()), propertyInfo.Name);
                }
                else if(propertyInfo.PropertyType != typeof(IFormFile) &&
                    propertyInfo.PropertyType.Name.Contains("List"))
                {
                    var list = (IList)propertyInfo.GetValue(dto, null);

                    if(list is not null)
                    foreach (var item in list) 
                    {
                        multiContent.Add(new StringContent(item.ToString()), propertyInfo.Name);
                    }
                }
            }
        }


       public static void AddFile(this MultipartFormDataContent multiContent, IFormFile file, string name)
       {
            byte[] data;
            using (var br = new BinaryReader(file.OpenReadStream()))
            {
                data = br.ReadBytes((int)file.OpenReadStream().Length);
            }

            ByteArrayContent bytes = new(data);

            multiContent.Add(bytes, name, file.FileName);
        }
    }

用法:

在本例中,ViewModel和Dto之间没有区别,因此可以使用ViewModel

代码语言:javascript
运行
复制
public class EditProfileDto
{
    public string DisplayName { get; set; }
    public IFormFile Photo { get; set; }
}
代码语言:javascript
运行
复制
EditProfileDto dto = new()
{
    DisplayName = edits.DisplayName
};

MultipartFormDataContent form = new();
form.AddDto(dto);
form.AddFile(edits.Photo, nameof(dto.Photo));

var result = await client.PostAsync("some-api", form);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70306462

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档