2017-02-14 10 views
0

В моем ASP.NET приложения Web API У меня есть контроллер, как это:Autorest/Кураж сгенерированный код для контроллера Web Api, который возвращает файл

[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-файл в браузере в качестве ответа. Некоторые из заголовков ответов:

Содержание-Планировка: приложение; имя файла = Reporte.pdf Content-Length: 22331 Content-Type: применение/октет-поток

После настройки чванство, генерируется JSon metadafile и сгенерированный код C# с ним в моем проекте Xamarin PCL я пытался потреблять услугу , Но это не получилось, потому что в сгенерированном коде пытается Deserialize json, но это не результат json!

Здесь часть сгенерированного кода, где она терпит неудачу:

[...] 
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, чтобы правильно генерировать код для контента-ответа для приложения/октета-потока?

+0

Вы пробовали использовать Swagger Codegen для генерации клиент C# API вместо этого? Клиент C# API, созданный Swagger Codegen, должен иметь возможность обрабатывать загрузку файла. –

+0

Я нашел код фильтра, который заставил его работать. Но у него все еще есть проблема с сгенерированным кодом. После этого я отправлю его здесь –

ответ

1

Создание пользовательского фильтра, который возвращает файл:

[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 класс:

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 файле:

c.OperationFilter<UpdateFileResponseTypeFilter>(); 

Чтобы использовать этот фильтр просто добавьте его в каждый контроллер действия следующим образом:

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

Таким образом, когда развязность генерирует метаданные JSon, autorest будет правильно создать метод, который возвращает Task < < Microsoft.Rest.HttpOperationResponse System.IO.Stream>>