WebApi自定义BufferedMediaTypeFormatter WriteToStream永远不会被调用

时间:2018-05-17 08:28:35

标签: c# asp.net-web-api2 mediatypeformatter

我在客户端使用带有角度的WebApi2。 我正在尝试在我的网站中实现导出到excel文件。 我实现了自定义BufferedMediaTypeFormatter。但不幸的是它不起作用。 WriteToStream函数永远不会被调用,尽管CanWriteType函数被调用两次并且两次都返回true。 这是我的代码:

 public class FileMediaFormatter : BufferedMediaTypeFormatter
{
    public const string SupportedMediaType = "text/html";
    public FileMediaFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue(SupportedMediaType));
    }

    public override bool CanReadType(Type type)
    {
        return false;
    }

    public override bool CanWriteType(Type type)
    {

        if (ExportableResolver.Instance.Value.CanConvert(type))
            return true;

        if (!type.IsGenericType)
            return false;
        var arguments = type.GetGenericArguments();
        if (arguments.Length != 1)
            return false;
        var ienumType = typeof(IEnumerable<>).MakeGenericType(arguments[0]);

        if (!ienumType.IsAssignableFrom(type))
            return false;

        return arguments[0].IsClass;
    }

    public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
    {
        IEnumerable<object> enumValue;
        Type genericType = type;
        if (ExportableResolver.Instance.Value.CanConvert(value.GetType()))
        {
            enumValue = ExportableResolver.Instance.Value.Convert(value);
            genericType = enumValue.GetType();
        }
        else
        {
            enumValue = (value as IEnumerable<object>);
            if (enumValue.Count() > 0)
            {
                genericType = typeof(List<>).MakeGenericType(enumValue.First().GetType());
            }
            else
            {
                // source of baseentity is no important because its just makes an empty file
                genericType = typeof(List<>).MakeGenericType(new FileArchive.Domain.Entities.FileProperties().GetType());
            }
            var a = genericType.Name;
        }

        if (enumValue == null)
        {
            base.WriteToStream(type, value, writeStream, content);
            return;
        }
        var list = enumValue as object[] ?? enumValue.ToArray();

        var fTypeObj = HttpUtility.ParseQueryString(HttpContext.Current.Request.RawUrl).Get("fType");
        if (fTypeObj != null)
        {
            string fType = fTypeObj.ToString();
            var dataTable = DependencyResolver.Current.GetService<IExportXslService>().ConvertToDataTable(list.ToList(), genericType.GetGenericArguments()[0]);
            DependencyResolver.Current.GetService<IExportXslService>().WriteDataTableToStream(dataTable, string.Format("{0}", genericType.GetGenericArguments()[0].Name), writeStream, string.Empty);
        }
    }


    public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
    {
        if (CanWriteType(type))
        {
            string typeName = ExportableResolver.Instance.Value.CanConvert(type)
            ? type.Name
            : type.GetGenericArguments()[0].Name;

            //if object (its for the complex type tbls) then give the assembly name
            typeName = typeName == "Object" ? System.Reflection.Assembly.GetExecutingAssembly().GetName().Name : typeName;
            //string tempFileName = GetHebrewFileName(typeName);
            //if (!string.IsNullOrEmpty(tempFileName))
            //    typeName = tempFileName;
            headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = string.Format("{0}_{1:yyyyMMddHHmmss}.xlsx", typeName, DateTime.Now) };

            var fTypeObj = HttpUtility.ParseQueryString(HttpContext.Current.Request.RawUrl).Get("fType");
            if (fTypeObj != null)
            {
                string fType = fTypeObj.ToString();

                if (fType == "excel")
                {
                    headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

                    headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = string.Format("{0}_{1:yyyyMMddHHmmss}.xlsx", typeName, DateTime.Now) };
                }
                else if (fType == "text")
                {
                    headers.ContentType = new MediaTypeHeaderValue("text/plain");
                    headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = string.Format("{0}_{1:yyyyMMddHHmmss}.txt", typeName, DateTime.Now) };
                }
                return;
            }
        }
        base.SetDefaultContentHeaders(type, headers, mediaType);
    }

}

在WebApiConifg注册函数中我添加了:

 config.Formatters.Insert(0,new FileMediaFormatter());

我错过了什么?

1 个答案:

答案 0 :(得分:0)

万一有人遇到这个问题,我会遇到这个问题,而我的问题是,尽管我的格式化程序能够对CanWriteType(myCustomType)做出“真”响应,但在最后一场比赛结束时却无法应对。
最后的“让它完成”调用基于“ ObjectContent”,这是一个错误响应,导致回退到标准Json格式化程序:因此从未调用过我的WriteStream(...)。 解决方案是确保格式化程序可以处理ObjectContent。