Autorest/Swagger为返回文件的Web Api控制器生成的代码 [英] Autorest/Swagger generated code for Web Api controller that returns File

查看:102
本文介绍了Autorest/Swagger为返回文件的Web Api控制器生成的代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的ASP.NET Web API应用程序中,我有一个像这样的控制器:

In my ASP.NET Web API application I have a controller like this:

    [RoutePrefix("api/ratings")]
    public class RateCostumerController : ApiController
    { 

        [AllowAnonymous]  
        [Route("Report/GetReport")]  
        [HttpGet]
        public HttpResponseMessage ExportReport([FromUri] string costumer)  

        {  
            var rd = new ReportDocument();  

           /*No relevant code here*/

            var result = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new ByteArrayContent(ms.ToArray())
            };
            result.Content.Headers.ContentDisposition =
                new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
                {
                    FileName = "Reporte.pdf"
                };
            result.Content.Headers.ContentType =
                new MediaTypeHeaderValue("application/octet-stream");

            return result;
        }
}

因此,当我使用客户参数进行简单的GET请求时,会在浏览器中得到一个pdf文件作为响应.一些响应头:

So, when I make a simple GET request with a costumer parameter I get a pdf file in browser as response. Some of the response headers:

Content-Disposition:附件;filename = Reporte.pdf内容长度:22331内容类型:应用程序/八位字节流

Content-Disposition : attachment; filename=Reporte.pdf Content-Length : 22331 Content-Type : application/octet-stream

设置好摇摇欲坠之后,在我的Xamarin PCL项目中生成了json metadafile并由此生成了C#代码,我尝试使用该服务.但这失败了,因为在生成的代码中试图对JSON进行反序列化,但不是JSON结果!

After setting up swagger, generated json metadafile and generated C# code with it in my Xamarin PCL project I tried to consume the service. But it failed because in the generated code is trying to Deserialize json, but is not a json result!

这里是失败的生成代码的一部分:

Here it is part of the generated code where it fails:

[...]
var _result = new Microsoft.Rest.HttpOperationResponse<object>();
            _result.Request = _httpRequest;
            _result.Response = _httpResponse;
            // Deserialize Response
            if ((int)_statusCode == 200)
            {
                _responseContent = await _httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
                try
                {
                    _result.Body = Microsoft.Rest.Serialization.SafeJsonConvert.DeserializeObject<object>(_responseContent, this.Client.DeserializationSettings);
                }
                catch (Newtonsoft.Json.JsonException ex)
                {
                    _httpRequest.Dispose();
                    if (_httpResponse != null)
                    {
                        _httpResponse.Dispose();
                    }
                    throw new Microsoft.Rest.SerializationException("Unable to deserialize the response.", _responseContent, ex);
                }
            }
            if (_shouldTrace)
            {
                Microsoft.Rest.ServiceClientTracing.Exit(_invocationId, _result);
            }
            return _result;
[...]

当我调试时,我发现文件的内容在主体中,因此反序列化将其弄乱了.由于不建议您编辑此生成的类文件,因此我需要在API中进行哪些更改才能正确生成用于应用程序/八位字节流内容响应的代码?

When I debugged I figure out that the content of the file is in the body, so deserialization is messing it up. Since is not recommended to edit this generated class file, What I need to change in my API to properly generate the code for application/octet-stream content-response?

推荐答案

创建返回文件的自定义过滤器:

Creating a custom filter that returns a file:

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
    public sealed class SwaggerFileResponseAttribute : SwaggerResponseAttribute
    {
        public SwaggerFileResponseAttribute(HttpStatusCode statusCode) : base(statusCode)
        {
        }

        public SwaggerFileResponseAttribute(HttpStatusCode statusCode, string description = null, Type type = null)  : base(statusCode, description, type)
        {
        }
        public SwaggerFileResponseAttribute(int statusCode) : base(statusCode)
        {
        }

        public SwaggerFileResponseAttribute(int statusCode, string description = null, Type type = null) : base(statusCode, description, type)
        {
        }
    }

还有这个自定义的ResponseTypeFilter类:

And also this custom ResponseTypeFilter class:

public sealed class UpdateFileResponseTypeFilter : IOperationFilter
    {
        public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
        {
            if (apiDescription.GetControllerAndActionAttributes<SwaggerResponseRemoveDefaultsAttribute>().Any())
            {
                operation.responses.Clear();
            }
            var responseAttributes = apiDescription.GetControllerAndActionAttributes<SwaggerFileResponseAttribute>()
                .OrderBy(attr => attr.StatusCode);

            foreach (var attr in responseAttributes)
            {
                var statusCode = attr.StatusCode.ToString();

                Schema responseSchema = new Schema { format = "byte", type = "file" };

                operation.produces.Clear();
                operation.produces.Add("application/octet-stream");

                operation.responses[statusCode] = new Response
                {
                    description = attr.Description ?? InferDescriptionFrom(statusCode),
                    schema = responseSchema
                };
            }
        }

        private string InferDescriptionFrom(string statusCode)
        {
            HttpStatusCode enumValue;
            if (Enum.TryParse(statusCode, true, out enumValue))
            {
                return enumValue.ToString();
            }
            return null;
        }
    }

然后将其注册到SwaggerConfig文件中:

Then register it in SwaggerConfig file:

c.OperationFilter<UpdateFileResponseTypeFilter>();

要使用此过滤器,只需将其添加到每个动作控制器中,如下所示:

To use this filter just add it in every action controller like this:

 [Route("Report/GetReport/{folio}")]
        [SwaggerFileResponse(HttpStatusCode.OK, "File Response")]
        [HttpGet]
        public HttpResponseMessage ExportReport(string folio)
        {
...

因此,当swagger生成json元数据时,autorest将正确创建一个返回Task<的方法.Microsoft.Rest.HttpOperationResponse<System.IO.Stream>>

So, when swagger generates json metadata, autorest will properly create a method that returns a Task < Microsoft.Rest.HttpOperationResponse< System.IO.Stream > >

这篇关于Autorest/Swagger为返回文件的Web Api控制器生成的代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆