我有这一行:
GlobalConfiguration.Configuration.Formatters.Add(New ExcelMediaTypeFormatter(Of Classification)(Function(t) New ExcelRow(ExcelCell.Map(t.ChemicalAbstractService), ExcelCell.Map(t.Substance), ExcelCell.Map(t.Columns("Classifidcation")), ExcelCell.Map(t.Columns("Classification"))), Function(format) "excel"))
它工作正常,并从我的网络api创建一个excelfile。
我有几个继承此Classification类的子类,我想为每个子类创建一个mediaformatter,以获取excelformatter中的特定列。 问题是,如果我这样做:
GlobalConfiguration.Configuration.Formatters.Add(New ExcelMediaTypeFormatter(Of CustomClassification)(Function(t) New ExcelRow(ExcelCell.Map(t.ChemicalAbstractService), ExcelCell.Map(t.Substance), ExcelCell.Map(t.Columns("Classifidcation")), ExcelCell.Map(t.Columns("Classification"))), Function(format) "excel"))
然后它根本不起作用。它只是从标准格式化程序生成xml。当web api返回
时,如何让它对子类做出反应IQueryable(Of Classification)
格式化程序:
public class ExcelMediaTypeFormatter<T> : BufferedMediaTypeFormatter
{
private const string ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
private readonly Func<T, ExcelRow> builder;
public ExcelMediaTypeFormatter(Func<T, ExcelRow> value)
{
builder = value;
SupportedMediaTypes.Add(new MediaTypeHeaderValue(ContentType));
}
public ExcelMediaTypeFormatter(Func<T, ExcelRow> value, params Func<object, string>[] type)
: this(value)
{
foreach (var mediaTypeMapping in type) {
this.MediaTypeMappings.Add(Map(mediaTypeMapping));
}
}
public override bool CanWriteType(Type type)
{
return type == typeof(IQueryable<T>) || type == typeof(T);
}
public override bool CanReadType(Type type)
{
return false;
}
public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
{
using (Stream ms = new MemoryStream()) {
using (var book = new ClosedXML.Excel.XLWorkbook()) {
var sheet = book.Worksheets.Add("sample");
ICollection<T> rows = type == typeof(IQueryable<T>) ? ((IQueryable<T>)value).ToList() : new List<T>() { (T)value };
for (var r = 0; r < rows.Count; r++) {
var result = builder((T)rows.ElementAt(r));
for (var c = 0; c < result.Count(); c++) {
if (result.ElementAt(c) != null)
sheet.Cell(r + 2, c + 1).Value = result.ElementAt(c).Value.ToString();
}
}
sheet.Columns().AdjustToContents();
book.SaveAs(ms);
byte[] buffer = new byte[ms.Length];
ms.Position = 0;
ms.Read(buffer, 0, buffer.Length);
writeStream.Write(buffer, 0, buffer.Length);
}
}
}
答案 0 :(得分:0)
CanWriteType
将返回false
,因为T
为CustomClassification
而type
为Classification
。如果格式化程序返回false,则不会使用它。
由于Classification
不一定是CustomClassification
,因此无效。
为了达到你想要的效果,你需要稍微改变你的实现。
您的ExcelMediaTypeFormatter
将不再是通用的。并且它不会传递一个Func
,而是传递IRowsBuilder
个实例的列表。这些将在WriteToStream
方法中用于选择正确的构建器:
public interface IRowsBuilder
{
bool CanBuildFor(Type type);
IEnumerable<Type> SupportedTypes { get; }
ExcelRow BuildRow(object value);
}
public class RowsBuilder<T> : IRowsBuilder where T : Classification
{
Func<T, ExcelRow> _builder;
public RowsBuilder(Func<T, ExcelRow> builder)
{
if(builder == null) throw new ArgumentNullException("builder");
_builder = builder;
}
public bool CanBuildFor(Type type)
{
return type.IsSubclassOf(typeof(T));
}
public IEnumerable<Type> SupportedTypes
{
get { yield return typeof(T); }
}
public ExcelRow BuildRow(object value)
{
if(!CanBuildFor(value.GetType()))
throw new ArgumentException();
return _builder((T)value);
}
}
public class ExcelMediaTypeFormatter : BufferedMediaTypeFormatter
{
private readonly ILookup<Type, IRowsBuilder> _builder;
public ExcelMediaTypeFormatter(IEnumerable<IRowsBuilder> builder)
{
_builder = builder.SelectMany(x => builder.SupportedTypes
.Select(y => new
{
Type = y,
Builder = x
}))
.ToLookup(x => x.Type, x => x.Builder);
}
public override bool CanWriteType(Type type)
{
return type == typeof(IQueryable<Classification>) ||
type == typeof(Classification);
}
// ...
public override void WriteToStream(Type type, object value,
Stream writeStream, HttpContent content)
{
// ...
List<Classification> rows;
if(type == typeof(IQueryable<Classification>))
rows = ((IQueryable<Classification>)value).ToList();
else
rows = new List<Classification> { (Classification)value };
for (var r = 0; r < rows.Count; r++)
{
var value = rows.ElementAt(r);
var builder = _builder[value.GetType()];
var result = builder(value);
// ...
}
}
}
现在,您只需向所有构建者注册一个ExcelMediaTypeFormatter
:
var customBuilder = new RowsBuilder<CustomClassification>(
t => new ExcelRow(ExcelCell.Map(t.ChemicalAbstractService),
ExcelCell.Map(t.Substance),
ExcelCell.Map(t.Columns("Classifidcation")),
ExcelCell.Map(t.Columns("Classification"))));
var builders = new List<IRowsBuilder>();
builder.Add(customBuilder);
builder.Add(someOtherBuilder);
var excelFormatter = new ExcelMediaTypeFormatter(builders, format => "excel");
GlobalConfiguration.Configuration
.Formatters
.Add(excelFormatter);