【问题标题】:Asp.net core file upload with Graphql-dotnet使用 Graphql-dotnet 上传 Asp.net 核心文件
【发布时间】:2018-06-06 00:17:53
【问题描述】:

我正在尝试使用graphql-dotnet 上传图像文件,但它从未成功。

我在我的 GraphQLController 中获取文件对象:

var files = this.Request.Form.Files;

var executionOptions = new ExecutionOptions 
{
    Schema = _schema,
    Query = queryToExecute,
    Inputs = inputs,
    UserContext = files,
    OperationName = query.OperationName
};

这里是我的突变:

Field<UserGraphType>(
    "uploadUserAvatar",
    Description="Kullanıcı resmi yükleme.",
    arguments: new QueryArguments(
        new QueryArgument<NonNullGraphType<IntGraphType>> { Name = "Id", Description = "Identity Alanı" }
    ),
    resolve: context => {
        var file = context.UserContext.As<IFormCollection>();
        var model = userService.UploadAvatar(context.GetArgument<int>("Id"),file);
        return true;
    }
);

我认为它接受了唯一的 JSON。它不接受作为文件类型的请求。

我还在客户端使用 React 和 apollo-client。控制台报错:

无法加载http://localhost:5000/graphql:请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,Origin 'http://localhost:8080' 不允许访问。响应的 HTTP 状态代码为 500。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

我正在尝试这样发送查询:

const { selectedFile,id } = this.state

this.props.uploadAvatar({
    variables: {id},
    file:selectedFile
}).then(result => {
    console.log(result);
});

我能做些什么来实现这一目标?

【问题讨论】:

    标签: reactjs asp.net-core graphql apollo-client graphql-dotnet


    【解决方案1】:

    无法加载http://localhost:5000/graphql:否 请求中存在“Access-Control-Allow-Origin”标头 资源。因此不允许使用原点“http://localhost:8080” 访问。

    此错误表示您需要启用 CORS。

    查看这些文档:https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1

    基本上你需要这两件事:

    services.AddCors();
    
    app.UseCors(builder =>
       builder.WithOrigins("http://example.com"));
    

    我还建议查看 GraphQL.Relay 项目中的这个 Deserializer 辅助函数。它可以帮助您的服务器处理multipart/form-data 请求。然后您可以使用解析的查询信息和文件并将其传递给DocumentExecutor

    https://github.com/graphql-dotnet/relay/blob/master/src/GraphQL.Relay/Http/Deserializer.cs

    public static class Deserializer
    {
        public static async Task<RelayRequest> Deserialize(Stream body, string contentType)
        {
            RelayRequest queries;
    
            switch (contentType)
            {
                case "multipart/form-data":
                    queries = DeserializeFormData(body);
                    break;
                case "application/json":
                    var stream = new StreamReader(body);
                    queries = DeserializeJson(await stream.ReadToEndAsync());
                    break;
                default:
                    throw new ArgumentOutOfRangeException($"Unknown media type: {contentType}. Cannot deserialize the Http request");
            }
    
            return queries;
        }
    
    
        private static RelayRequest DeserializeJson(string stringContent)
        {
            if (stringContent[0] == '[')
                return new RelayRequest(
                    JsonConvert.DeserializeObject<RelayQuery[]>(stringContent),
                    isBatched: true
                );
    
            if (stringContent[0] == '{')
                return new RelayRequest() {
                    JsonConvert.DeserializeObject<RelayQuery>(stringContent)
                };
    
            throw new Exception("Unrecognized request json. GraphQL queries requests should be a single object, or an array of objects");
        }
    
        private static RelayRequest DeserializeFormData(Stream body)
        {
            var form = new MultipartFormDataParser(body);
    
            var req = new RelayRequest()
            {
                Files = form.Files.Select(f => new HttpFile {
                    ContentDisposition = f.ContentDisposition,
                    ContentType = f.ContentType,
                    Data = f.Data,
                    FileName = f.FileName,
                    Name = f.Name
                })
            };
    
            req.Add(new RelayQuery {
                Query = form.Parameters.Find(p => p.Name == "query").Data,
                Variables = form.Parameters.Find(p => p.Name == "variables").Data.ToInputs(),
            });
    
            return req;
        }
    }
    

    【讨论】:

    • 感谢您的建议。但我也有关于 ContentType 的错误。所以它没有得到 GraphQLControlller 中内容类型的文件原因。我正在使用 apollo-client 作为客户端 btw。
    • 从客户端发送文件是否正确?
    • 您可能应该将其作为 multipart/form-data 请求发送。据我了解,Apollo 不支持开箱即用。见这篇文章。 medium.freecodecamp.org/…
    • 是的,我读过这个。但是 dotnet-graphql 中没有 Upload! 的图形类型。所以我不能申请 Apollo。它在 github.com/graphql-dotnet/graphql-dotnet/issues/419 上提到过这个问题
    • 是的,Apollo 或 GraphQL 不直接支持文件上传。 GraphQL 与传输无关,因此您可能不会通过 http 运行 GraphQL。您必须在 Apollo 和您的服务器中实现自定义。
    猜你喜欢
    • 2017-03-25
    • 1970-01-01
    • 2017-04-20
    • 2020-01-20
    • 1970-01-01
    • 2017-05-08
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    相关资源
    最近更新 更多