Web API OData v7。我正在为CSV,Excel等编写自定义格式化程序。我不知道如何将自定义格式化程序(ODataMediaTypeFormatter)指向修改输出的自定义类。
CustomFormatter:ODataMediaTypeFormatter-具有一个MessageWriterSettings.MediaTypeResolver,在第7版中不再存在
调试时,我进入GetPerRequestFormatterInstance,然后它死于A。找不到与响应的内容类型匹配的受支持的MIME类型。
我不知道流程-如何将其绑定到我的自定义(ODataWriter)编写器(csv或我想创建的任何内容)上。
例如,来自git上的示例:
public class CustomFormatter : ODataMediaTypeFormatter
{
private readonly string csvMime = ;
public CustomFormatter(params ODataPayloadKind[] kinds)
: base(kinds) {
//----no longer exists in 7
//MessageWriterSettings.MediaTypeResolver = new MixResolver();
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
}
}
public class MixResolver : ODataMediaTypeResolver
{
public override IEnumerable<ODataMediaTypeFormat> GetMediaTypeFormats(ODataPayloadKind payloadKind)
{
if (payloadKind == ODataPayloadKind.Resource || payloadKind == ODataPayloadKind.ResourceSet)
{
return CsvMediaTypeResolver.Instance.GetMediaTypeFormats(payloadKind);
}
return base.GetMediaTypeFormats(payloadKind);
}
}
public class CsvMediaTypeResolver : ODataMediaTypeResolver
{
private static readonly CsvMediaTypeResolver instance = new CsvMediaTypeResolver();
private readonly ODataMediaTypeFormat[] mediaTypeFormats =
{
new ODataMediaTypeFormat(new ODataMediaType("text", "csv"), new CsvFormat())
};
public class CsvMediaTypeResolver : ODataMediaTypeResolver
{
private static readonly CsvMediaTypeResolver instance = new CsvMediaTypeResolver();
private readonly ODataMediaTypeFormat[] mediaTypeFormats = { new ODataMediaTypeFormat(new ODataMediaType("text", "csv"), new CsvFormat())};
private CsvMediaTypeResolver() { }
public static CsvMediaTypeResolver Instance { get { return instance; } }
public override IEnumerable<ODataMediaTypeFormat> GetMediaTypeFormats(ODataPayloadKind payloadKind)
{
if (payloadKind == ODataPayloadKind.Resource || payloadKind == ODataPayloadKind.ResourceSet)
{
return mediaTypeFormats.Concat(base.GetMediaTypeFormats(payloadKind));
}
return base.GetMediaTypeFormats(payloadKind);
}
}
public class CsvWriter : ODataWriter
{
// Etc..
}
与ODataMediaTypeFormatter和CsvMediaTypeResolver断开连接。如何将ODataMediaTypeFormatter链接到我的解析器?
答案 0 :(得分:2)
我已经通过Microsoft.OData.Core的示例中说明的CsvOutputContext
和CsvWriterDemo
解决了这个问题
示例代码已更新
public CsvOutputContext(
ODataFormat format,
ODataMessageWriterSettings settings,
ODataMessageInfo messageInfo,
bool synchronous)
: base(format, settings, messageInfo.IsResponse, synchronous,
messageInfo.Model, messageInfo.UrlResolver)
{
this.stream = messageInfo.GetMessageStream();
this.Writer = new StreamWriter(this.stream);
}
}
private static void CsvWriterDemo()
{
EdmEntityType customer = new EdmEntityType("ns", "customer");
var key = customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32);
customer.AddKeys(key);
customer.AddStructuralProperty("Name", EdmPrimitiveTypeKind.String);
ODataEntry entry1 = new ODataEntry()
{
Properties = new[]
{
new ODataProperty(){Name = "Id", Value = 51},
new ODataProperty(){Name = "Name", Value = "Name_A"},
}
};
ODataEntry entry2 = new ODataEntry()
{
Properties = new[]
{
new ODataProperty(){Name = "Id", Value = 52},
new ODataProperty(){Name = "Name", Value = "Name_B"},
}
};
var stream = new MemoryStream();
var message = new Message { Stream = stream };
// Set Content-Type header value
message.SetHeader("Content-Type", "text/csv");
var settings = new ODataMessageWriterSettings
{
// Set our resolver here.
MediaTypeResolver = CsvMediaTypeResolver.Instance,
DisableMessageStreamDisposal = true,
};
using (var messageWriter = new ODataMessageWriter(message, settings))
{
var writer = messageWriter.CreateODataFeedWriter(null, customer);
writer.WriteStart(new ODataFeed());
writer.WriteStart(entry1);
writer.WriteEnd();
writer.WriteStart(entry2);
writer.WriteEnd();
writer.WriteEnd();
writer.Flush();
}
stream.Seek(0, SeekOrigin.Begin);
string msg;
using (var sr = new StreamReader(stream)) { msg = sr.ReadToEnd(); }
Console.WriteLine(msg);
}
答案 1 :(得分:0)
如this document中所述:
在ODataLib v7.0中,引入了依赖注入(简称“ DI”)支持,以通过消除冗余函数参数和类属性来简化ODataLib的API和实现。
要使DI与ODataLib一起正常工作,基本上,您必须在应用程序中做几件事:
- 基于您的DI框架实现您的容器构建器。
- 从ODataLib和您的应用程序中注册所需的服务。
- 在ODataLib中构建和使用容器(以检索服务)。
Microsoft使用IServiceProvider
接口作为容器的抽象。容器是只读的,您必须实现IContainerBuilder
接口。然后注入您的容器。之后,将所需的服务注册到容器中。您可以使用ContainerBuilderExtensions
类中定义的扩展方法来轻松注册服务。
在使用以下方法之前,您必须谨慎:
对于
AddServicePrototype
,我们目前仅支持以下服务类型:ODataMessageReaderSettings
,ODataMessageWriterSettings
和ODataSimplifiedOptions
。该设计遵循原型模式,您可以在其中为每种服务类型注册一个全局单例实例(作为原型),然后您将为每个作用域/请求获得一个单独的克隆。修改该克隆不会影响单例实例以及后续克隆。就是说,现在您不需要克隆作家设置,就可以使用与请求相关的信息对其进行编辑,而只需针对任何特定请求进行修改即可。
AddDefaultODataServices
方法使用ODataLib的默认实现注册一组服务类型。通常,在注册任何自定义服务之前,必须首先在容器构建器上调用此方法。请注意,注册顺序很重要! ODataLib将始终使用针对特定服务类型注册的最新服务实现。
所提到的文档中有一个服务列表,您可以覆盖; ODataMediaTypeResolver
是其中之一。 在注册任何服务之前,请考虑该列表。
现在,您可以通过在构建器上调用BuildContainer
来构建容器。这样就为您提供了一个实现IServiceProvider
的容器实例。
为了使用ODataLib中的注册服务,必须通过某些入口点将容器传递到ODataLib中。
当前ODataLib中的入口点是
ODataMessageReader
,ODataMessageWriter
和ODataUriParser
。
1。序列化和反序列化:
您可以通过请求和响应消息将容器传递到ODataMessageReader
或ODataMessageWriter
中。为此,您应该创建一个实现IODataRequestMessage
和IODataResponseMessage
以及IContainerProvider
的类,如下所示:
class ODataMessageWrapper : IODataRequestMessage, IODataResponseMessage, IContainerProvider, ...
{
public IServiceProvider Container { get; set; }
// rest of the implementation here
}
然后您可以使用ODataMessageWrapper
类将容器传递到ODataLib中,如下所示:
ODataMessageWrapper responseMessage = new ODataMessageWrapper();
responseMessage.Container = Request.GetRequestContainer();
ODataMessageWriter writer = new ODataMessageWriter(responseMessage);
在上面的示例中,GetRequestContainer
是在Microsoft.AspNet.OData.HttpRequestMessageExtensions.cs中实现的HttpRequestMessage
的扩展。
现在,容器存储在Container
,ODataMessageInfo
和ODataInputContext
的{{1}}属性及其子类中。为了实现自定义媒体类型,您可以通过这些属性访问容器。
如果您未能在
ODataOutputContext
中设置Container
,它将保持为空。在这种情况下,ODataLib不会在内部失败,但是所有服务都将具有其默认实现,并且无法用自定义服务替换它们。也就是说,如果您要扩展性,请使用DI:-)
2。 URI解析:
要将容器传递到URI解析器,应使用IContainerProvider
的构造函数重载。如果使用其他构造函数,则将禁用URI解析器中的DI支持。这样,容器将保存在ODataUriParser
中并在URI解析器中使用。
ODataUriParserConfiguratino
当前
public sealed class ODataUriParser { public ODataUriParser(IEdmModel model, Uri serviceRoot, Uri uri, IServiceProvider container); public ODataUriParser(IEdmModel model, Uri relativeUri, IServiceProvider container); }
,ODataUriResolver
和UriPathParser
可以被覆盖,并且会影响URI解析器的行为。