0

私はこの行を持っています:

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"))

正常に動作し、Web API から Excelfile を作成します。

この分類クラスを継承するいくつかのサブクラスがあり、各サブクラスのメディアフォーマッターを作成して、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);
            }
        }
    }
4

1 に答える 1

0

CanWriteType戻りますfalse、ということTCustomClassificationございtypeますClassification。false を返す場合、フォーマッタは使用されません。

aClassificationは必ずしも a ではないため、CustomClassificationこれは機能しません。

目的を達成するには、実装を少し変更する必要があります。

あなたExcelMediaTypeFormatterはもはや一般的ではありません。渡されるのは 1 つではなく、インスタンス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すべてのビルダーに1 つだけ登録します。

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);
于 2013-01-29T09:51:11.417 に答える